From ffee0868ef1341cfb7622821431cb73c52590962 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 3 Oct 2010 16:14:44 +0200 Subject: Assorted Multicast Fixes: - Upgrade bundled OpenPGM to SVN r1135 - Timing fixes: Make all rate-limited and timer-pending operation wait for at least 1ms to avoid busy-waiting - No distinction between sending and receiving sockets when setting up socket options (Receivers need to be able to send anyway when using PGMCC). - Switch from fixed-rate transmission to using PGMCC for congestion control. - Remove some obnoxious debugging outputs - Some white space fixes - Introduce a short waiting time before actually starting file transmission in order to allow enough SPM messages to be sent so that receivers can initialize properly. - Fix MCASTFTANNOUNCE message to include full file name instead of basename. - Fix generateMcastTransferID in order to gather more random IDs. PVSGUI may become confused if transfer IDs are reused. - Properly dispose of clientFileReceiveDialog when multicast transfer is finished. - Properly display transfer size in clientFileReceiveDialog --- 3rdparty/01-libpgm-fix-switch-fallthrough.patch | 11 - .../doc/draft-ietf-rmt-bb-pgmcc-03.txt | 1226 ---- 3rdparty/openpgm-svn-r1085/doc/rfc3208.txt | 6219 -------------------- 3rdparty/openpgm-svn-r1085/pgm/COPYING | 504 -- 3rdparty/openpgm-svn-r1085/pgm/INSTALL | 4 - 3rdparty/openpgm-svn-r1085/pgm/LICENSE | 19 - 3rdparty/openpgm-svn-r1085/pgm/README | 7 - 3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgm | 170 - 3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgm89 | 80 - 3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmex | 18 - .../openpgm-svn-r1085/pgm/SConscript.libpgmhttp | 53 - .../openpgm-svn-r1085/pgm/SConscript.libpgmsnmp | 35 - 3rdparty/openpgm-svn-r1085/pgm/SConstruct | 326 - 3rdparty/openpgm-svn-r1085/pgm/SConstruct.097 | 321 - .../openpgm-svn-r1085/pgm/SConstruct.097.intelc | 331 -- .../openpgm-svn-r1085/pgm/SConstruct.097.mingw64 | 325 - .../openpgm-svn-r1085/pgm/SConstruct.097.sunstudio | 312 - 3rdparty/openpgm-svn-r1085/pgm/SConstruct.Debian4 | 281 - .../openpgm-svn-r1085/pgm/SConstruct.FreeBSD80 | 337 -- .../openpgm-svn-r1085/pgm/SConstruct.OpenSolaris | 310 - 3rdparty/openpgm-svn-r1085/pgm/SConstruct.RHEL4 | 279 - .../openpgm-svn-r1085/pgm/SConstruct.Solaris.gcc64 | 324 - .../pgm/SConstruct.Solaris.sungcc | 321 - .../pgm/SConstruct.Solaris.sunstudio | 306 - 3rdparty/openpgm-svn-r1085/pgm/SConstruct.clang | 336 -- 3rdparty/openpgm-svn-r1085/pgm/SConstruct.mingw | 330 -- .../openpgm-svn-r1085/pgm/SConstruct.mingw-wine | 339 -- 3rdparty/openpgm-svn-r1085/pgm/atomic_unittest.c | 166 - 3rdparty/openpgm-svn-r1085/pgm/backtrace.c | 69 - 3rdparty/openpgm-svn-r1085/pgm/checksum.c | 941 --- 3rdparty/openpgm-svn-r1085/pgm/checksum_perftest.c | 807 --- 3rdparty/openpgm-svn-r1085/pgm/checksum_unittest.c | 278 - 3rdparty/openpgm-svn-r1085/pgm/crossmingw.py | 144 - 3rdparty/openpgm-svn-r1085/pgm/crossmingw64.py | 140 - 3rdparty/openpgm-svn-r1085/pgm/engine.c | 277 - 3rdparty/openpgm-svn-r1085/pgm/engine_unittest.c | 232 - 3rdparty/openpgm-svn-r1085/pgm/error.c | 518 -- 3rdparty/openpgm-svn-r1085/pgm/error_unittest.c | 292 - 3rdparty/openpgm-svn-r1085/pgm/examples/SConscript | 88 - .../openpgm-svn-r1085/pgm/examples/SConscript89 | 41 - 3rdparty/openpgm-svn-r1085/pgm/examples/async.c | 441 -- 3rdparty/openpgm-svn-r1085/pgm/examples/async.h | 82 - .../openpgm-svn-r1085/pgm/examples/blocksyncrecv.c | 350 -- 3rdparty/openpgm-svn-r1085/pgm/examples/daytime.c | 546 -- .../pgm/examples/enonblocksyncrecv.c | 382 -- .../pgm/examples/enonblocksyncrecvmsg.c | 382 -- .../pgm/examples/enonblocksyncrecvmsgv.c | 397 -- 3rdparty/openpgm-svn-r1085/pgm/examples/getopt.c | 110 - 3rdparty/openpgm-svn-r1085/pgm/examples/getopt.h | 62 - 3rdparty/openpgm-svn-r1085/pgm/examples/pgmdump.c | 279 - 3rdparty/openpgm-svn-r1085/pgm/examples/pgmping.cc | 1059 ---- 3rdparty/openpgm-svn-r1085/pgm/examples/pgmrecv.c | 649 -- 3rdparty/openpgm-svn-r1085/pgm/examples/pgmsend.c | 305 - 3rdparty/openpgm-svn-r1085/pgm/examples/pgmtop.c | 1031 ---- 3rdparty/openpgm-svn-r1085/pgm/examples/ping.proto | 47 - .../pgm/examples/pnonblocksyncrecv.c | 385 -- .../openpgm-svn-r1085/pgm/examples/purinrecv.c | 474 -- .../openpgm-svn-r1085/pgm/examples/purinrecvcc.cc | 434 -- .../openpgm-svn-r1085/pgm/examples/purinsend.c | 280 - .../openpgm-svn-r1085/pgm/examples/purinsendcc.cc | 269 - .../openpgm-svn-r1085/pgm/examples/shortcakerecv.c | 430 -- .../pgm/examples/snonblocksyncrecv.c | 435 -- 3rdparty/openpgm-svn-r1085/pgm/fec-block.txt | 66 - 3rdparty/openpgm-svn-r1085/pgm/fec.txt | 77 - 3rdparty/openpgm-svn-r1085/pgm/galois_generator.pl | 139 - 3rdparty/openpgm-svn-r1085/pgm/gcov-parse.pl | 41 - 3rdparty/openpgm-svn-r1085/pgm/gcov-seed.sh | 33 - 3rdparty/openpgm-svn-r1085/pgm/gcov.sh | 29 - 3rdparty/openpgm-svn-r1085/pgm/getifaddrs.c | 840 --- .../openpgm-svn-r1085/pgm/getifaddrs_unittest.c | 262 - 3rdparty/openpgm-svn-r1085/pgm/getnodeaddr.c | 196 - .../openpgm-svn-r1085/pgm/getnodeaddr_unittest.c | 573 -- 3rdparty/openpgm-svn-r1085/pgm/gsi.c | 227 - 3rdparty/openpgm-svn-r1085/pgm/gsi_unittest.c | 350 -- 3rdparty/openpgm-svn-r1085/pgm/hashtable.c | 327 - 3rdparty/openpgm-svn-r1085/pgm/histogram.c | 414 -- 3rdparty/openpgm-svn-r1085/pgm/htdocs/404.html | 11 - 3rdparty/openpgm-svn-r1085/pgm/htdocs/base.css | 136 - .../pgm/htdocs/convert_to_macro.pl | 20 - 3rdparty/openpgm-svn-r1085/pgm/htdocs/robots.txt | 2 - .../pgm/htdocs/xhtml10_strict.doctype | 3 - 3rdparty/openpgm-svn-r1085/pgm/http.c | 1718 ------ 3rdparty/openpgm-svn-r1085/pgm/http_unittest.c | 186 - 3rdparty/openpgm-svn-r1085/pgm/if.c | 1595 ----- 3rdparty/openpgm-svn-r1085/pgm/if_unittest.c | 1495 ----- .../openpgm-svn-r1085/pgm/include/impl/checksum.h | 75 - .../openpgm-svn-r1085/pgm/include/impl/engine.h | 43 - .../openpgm-svn-r1085/pgm/include/impl/features.h | 42 - .../openpgm-svn-r1085/pgm/include/impl/fixed.h | 140 - .../openpgm-svn-r1085/pgm/include/impl/framework.h | 76 - .../openpgm-svn-r1085/pgm/include/impl/galois.h | 138 - .../pgm/include/impl/getifaddrs.h | 73 - .../pgm/include/impl/getnodeaddr.h | 41 - .../openpgm-svn-r1085/pgm/include/impl/hashtable.h | 58 - .../openpgm-svn-r1085/pgm/include/impl/histogram.h | 129 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/i18n.h | 32 - .../pgm/include/impl/indextoaddr.h | 41 - .../pgm/include/impl/indextoname.h | 37 - .../pgm/include/impl/inet_network.h | 41 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/ip.h | 150 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/list.h | 43 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/math.h | 75 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/md5.h | 61 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/mem.h | 34 - .../openpgm-svn-r1085/pgm/include/impl/messages.h | 352 -- .../pgm/include/impl/nametoindex.h | 40 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/net.h | 38 - .../openpgm-svn-r1085/pgm/include/impl/notify.h | 298 - .../pgm/include/impl/packet_parse.h | 45 - .../pgm/include/impl/packet_test.h | 40 - .../openpgm-svn-r1085/pgm/include/impl/pgmMIB.h | 28 - .../pgm/include/impl/pgmMIB_columns.h | 372 -- .../pgm/include/impl/pgmMIB_enums.h | 64 - .../openpgm-svn-r1085/pgm/include/impl/processor.h | 61 - .../openpgm-svn-r1085/pgm/include/impl/queue.h | 51 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/rand.h | 50 - .../pgm/include/impl/rate_control.h | 54 - .../openpgm-svn-r1085/pgm/include/impl/receiver.h | 142 - .../pgm/include/impl/reed_solomon.h | 51 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/rxw.h | 220 - .../openpgm-svn-r1085/pgm/include/impl/slist.h | 52 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/sn.h | 186 - .../openpgm-svn-r1085/pgm/include/impl/sockaddr.h | 105 - .../openpgm-svn-r1085/pgm/include/impl/socket.h | 182 - .../openpgm-svn-r1085/pgm/include/impl/source.h | 75 - .../openpgm-svn-r1085/pgm/include/impl/sqn_list.h | 38 - .../openpgm-svn-r1085/pgm/include/impl/string.h | 59 - .../openpgm-svn-r1085/pgm/include/impl/thread.h | 210 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/time.h | 51 - .../openpgm-svn-r1085/pgm/include/impl/timer.h | 58 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/tsi.h | 39 - 3rdparty/openpgm-svn-r1085/pgm/include/impl/txw.h | 204 - .../pgm/include/impl/wsastrerror.h | 37 - .../openpgm-svn-r1085/pgm/include/pgm/atomic.h | 140 - .../openpgm-svn-r1085/pgm/include/pgm/backtrace.h | 33 - .../openpgm-svn-r1085/pgm/include/pgm/engine.h | 37 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/error.h | 109 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/gsi.h | 49 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/http.h | 37 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/if.h | 33 - .../openpgm-svn-r1085/pgm/include/pgm/ip/pgm.hh | 100 - .../pgm/include/pgm/ip/pgm_endpoint.hh | 171 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/list.h | 40 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/log.h | 33 - .../openpgm-svn-r1085/pgm/include/pgm/macros.h | 171 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/mem.h | 60 - .../openpgm-svn-r1085/pgm/include/pgm/messages.h | 66 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/msgv.h | 54 - .../openpgm-svn-r1085/pgm/include/pgm/packet.h | 472 -- 3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm.h | 42 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm.hh | 33 - .../pgm/include/pgm/pgm_socket.hh | 157 - .../openpgm-svn-r1085/pgm/include/pgm/signal.h | 36 - .../openpgm-svn-r1085/pgm/include/pgm/skbuff.h | 243 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/snmp.h | 35 - .../openpgm-svn-r1085/pgm/include/pgm/socket.h | 170 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/time.h | 54 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/tsi.h | 47 - 3rdparty/openpgm-svn-r1085/pgm/include/pgm/types.h | 56 - .../openpgm-svn-r1085/pgm/include/pgm/version.h | 41 - .../openpgm-svn-r1085/pgm/include/pgm/winint.h | 198 - .../pgm/include/pgm/wininttypes.h | 254 - 3rdparty/openpgm-svn-r1085/pgm/indextoaddr.c | 98 - .../openpgm-svn-r1085/pgm/indextoaddr_unittest.c | 302 - 3rdparty/openpgm-svn-r1085/pgm/indextoname.c | 52 - 3rdparty/openpgm-svn-r1085/pgm/inet_network.c | 237 - .../openpgm-svn-r1085/pgm/inet_network_unittest.c | 203 - 3rdparty/openpgm-svn-r1085/pgm/ip_unittest.c | 362 -- 3rdparty/openpgm-svn-r1085/pgm/list.c | 146 - 3rdparty/openpgm-svn-r1085/pgm/log.c | 151 - 3rdparty/openpgm-svn-r1085/pgm/math.c | 75 - 3rdparty/openpgm-svn-r1085/pgm/md5.c | 368 -- 3rdparty/openpgm-svn-r1085/pgm/md5_unittest.c | 189 - 3rdparty/openpgm-svn-r1085/pgm/mem.c | 249 - 3rdparty/openpgm-svn-r1085/pgm/memcheck | 13 - 3rdparty/openpgm-svn-r1085/pgm/messages.c | 173 - .../pgm/mibs/PGM-MIB-petrova-01.txt | 5459 ----------------- 3rdparty/openpgm-svn-r1085/pgm/mld-semantics.txt | 52 - 3rdparty/openpgm-svn-r1085/pgm/msfec.txt | 33 - 3rdparty/openpgm-svn-r1085/pgm/nametoindex.c | 249 - 3rdparty/openpgm-svn-r1085/pgm/net-snmp.txt | 34 - 3rdparty/openpgm-svn-r1085/pgm/net.c | 175 - 3rdparty/openpgm-svn-r1085/pgm/net_unittest.c | 375 -- 3rdparty/openpgm-svn-r1085/pgm/options.txt | 158 - 3rdparty/openpgm-svn-r1085/pgm/packet_parse.c | 615 -- .../openpgm-svn-r1085/pgm/packet_parse_unittest.c | 382 -- 3rdparty/openpgm-svn-r1085/pgm/packet_test.c | 1158 ---- .../openpgm-svn-r1085/pgm/packet_test_unittest.c | 169 - 3rdparty/openpgm-svn-r1085/pgm/pgmMIB.c | 3212 ---------- 3rdparty/openpgm-svn-r1085/pgm/pgmMIB_unittest.c | 257 - 3rdparty/openpgm-svn-r1085/pgm/plan.txt | 238 - 3rdparty/openpgm-svn-r1085/pgm/queue.c | 110 - 3rdparty/openpgm-svn-r1085/pgm/rand.c | 137 - 3rdparty/openpgm-svn-r1085/pgm/rate_control.c | 158 - .../openpgm-svn-r1085/pgm/rate_control_unittest.c | 241 - 3rdparty/openpgm-svn-r1085/pgm/receiver.c | 2268 ------- 3rdparty/openpgm-svn-r1085/pgm/receiver_unittest.c | 857 --- 3rdparty/openpgm-svn-r1085/pgm/recv.c | 1059 ---- 3rdparty/openpgm-svn-r1085/pgm/recv_unittest.c | 1600 ----- 3rdparty/openpgm-svn-r1085/pgm/reed_solomon.c | 576 -- .../openpgm-svn-r1085/pgm/reed_solomon_unittest.c | 305 - 3rdparty/openpgm-svn-r1085/pgm/rxw.c | 2229 ------- 3rdparty/openpgm-svn-r1085/pgm/rxw_unittest.c | 1844 ------ 3rdparty/openpgm-svn-r1085/pgm/signal.c | 176 - 3rdparty/openpgm-svn-r1085/pgm/signal_unittest.c | 115 - 3rdparty/openpgm-svn-r1085/pgm/skbuff.c | 115 - 3rdparty/openpgm-svn-r1085/pgm/slist.c | 166 - 3rdparty/openpgm-svn-r1085/pgm/snmp.c | 222 - 3rdparty/openpgm-svn-r1085/pgm/snmp_unittest.c | 184 - 3rdparty/openpgm-svn-r1085/pgm/sockaddr.c | 1193 ---- 3rdparty/openpgm-svn-r1085/pgm/socket.c | 2046 ------- 3rdparty/openpgm-svn-r1085/pgm/socket_unittest.c | 1186 ---- 3rdparty/openpgm-svn-r1085/pgm/source.c | 2339 -------- 3rdparty/openpgm-svn-r1085/pgm/source_unittest.c | 1216 ---- 3rdparty/openpgm-svn-r1085/pgm/string.c | 486 -- 3rdparty/openpgm-svn-r1085/pgm/test/PGM/Test.pm | 394 -- 3rdparty/openpgm-svn-r1085/pgm/test/SConscript | 15 - 3rdparty/openpgm-svn-r1085/pgm/test/ambient_spm.pl | 86 - 3rdparty/openpgm-svn-r1085/pgm/test/apdu.pl | 56 - 3rdparty/openpgm-svn-r1085/pgm/test/apdu_parity.pl | 59 - 3rdparty/openpgm-svn-r1085/pgm/test/app.c | 904 --- 3rdparty/openpgm-svn-r1085/pgm/test/async.c | 572 -- 3rdparty/openpgm-svn-r1085/pgm/test/async.h | 76 - 3rdparty/openpgm-svn-r1085/pgm/test/dump-json.c | 1292 ---- 3rdparty/openpgm-svn-r1085/pgm/test/dump-json.h | 33 - .../openpgm-svn-r1085/pgm/test/heartbeat_spm.pl | 57 - 3rdparty/openpgm-svn-r1085/pgm/test/monitor.c | 349 -- 3rdparty/openpgm-svn-r1085/pgm/test/nak.pl | 66 - .../openpgm-svn-r1085/pgm/test/nak_cancellation.pl | 161 - 3rdparty/openpgm-svn-r1085/pgm/test/nak_list.pl | 70 - 3rdparty/openpgm-svn-r1085/pgm/test/nak_parity.pl | 75 - 3rdparty/openpgm-svn-r1085/pgm/test/nak_repeat.pl | 69 - 3rdparty/openpgm-svn-r1085/pgm/test/ncf.pl | 66 - .../openpgm-svn-r1085/pgm/test/ncf_cancellation.pl | 147 - 3rdparty/openpgm-svn-r1085/pgm/test/ncf_list.pl | 72 - .../openpgm-svn-r1085/pgm/test/ncf_suppression.pl | 101 - 3rdparty/openpgm-svn-r1085/pgm/test/odata.pl | 44 - .../openpgm-svn-r1085/pgm/test/odata_completion.pl | 87 - 3rdparty/openpgm-svn-r1085/pgm/test/odata_jump.pl | 71 - .../pgm/test/odata_jump_parity.pl | 83 - .../openpgm-svn-r1085/pgm/test/odata_number.pl | 59 - 3rdparty/openpgm-svn-r1085/pgm/test/odata_rate.pl | 68 - .../openpgm-svn-r1085/pgm/test/odata_reception.pl | 59 - .../openpgm-svn-r1085/pgm/test/on-demand_spm.pl | 49 - .../openpgm-svn-r1085/pgm/test/outofwindow_ncf.pl | 103 - .../openpgm-svn-r1085/pgm/test/rdata_completion.pl | 87 - .../pgm/test/rdata_completion_parity.pl | 97 - .../pgm/test/rdata_completion_parity_var_pktlen.pl | 97 - 3rdparty/openpgm-svn-r1085/pgm/test/rdata_jump.pl | 71 - .../openpgm-svn-r1085/pgm/test/rdata_reception.pl | 59 - 3rdparty/openpgm-svn-r1085/pgm/test/sim.c | 1924 ------ 3rdparty/openpgm-svn-r1085/pgm/test/spm.pl | 42 - 3rdparty/openpgm-svn-r1085/pgm/test/spm_jump.pl | 60 - 3rdparty/openpgm-svn-r1085/pgm/test/spm_jump2.pl | 59 - .../openpgm-svn-r1085/pgm/test/spm_reception.pl | 58 - 3rdparty/openpgm-svn-r1085/pgm/test/spmr.pl | 73 - .../openpgm-svn-r1085/pgm/test/spmr_after_spm.pl | 78 - .../openpgm-svn-r1085/pgm/test/spmr_from_odata.pl | 53 - .../openpgm-svn-r1085/pgm/test/spmr_suppression.pl | 58 - .../openpgm-svn-r1085/pgm/test/sudoers.example | 26 - 3rdparty/openpgm-svn-r1085/pgm/test/test.conf.pl | 27 - 3rdparty/openpgm-svn-r1085/pgm/thread.c | 457 -- 3rdparty/openpgm-svn-r1085/pgm/time.c | 770 --- 3rdparty/openpgm-svn-r1085/pgm/time_unittest.c | 188 - 3rdparty/openpgm-svn-r1085/pgm/timer.c | 223 - 3rdparty/openpgm-svn-r1085/pgm/timer_unittest.c | 355 -- .../pgm/token and leaky bucket.txt | 12 - 3rdparty/openpgm-svn-r1085/pgm/tsi.c | 119 - 3rdparty/openpgm-svn-r1085/pgm/tsi_unittest.c | 185 - 3rdparty/openpgm-svn-r1085/pgm/txw.c | 763 --- 3rdparty/openpgm-svn-r1085/pgm/txw_unittest.c | 743 --- 3rdparty/openpgm-svn-r1085/pgm/valgrind.supp | 147 - .../openpgm-svn-r1085/pgm/version_generator.py | 52 - .../pgm/win/mingw32-runtime_3.13-1openpgm3.diff | 136 - .../pgm/win/mingw32-runtime_3.15.2-0openpgm1.diff | 135 - ...mingw-w64-bin_x86-64-linux_4.4.1-1openpgm1.diff | 53 - 3rdparty/openpgm-svn-r1085/pgm/wsastrerror.c | 372 -- .../openpgm-svn-r1135-0001-sigsegv-in-txw.patch | 28 + ...n-r1135-0002-correct-checksum-calculation.patch | 17 + ...n-r1135-0003-fix-rdata-congestion-control.patch | 42 + .../doc/draft-ietf-rmt-bb-pgmcc-03.txt | 1226 ++++ 3rdparty/openpgm-svn-r1135/doc/rfc3208.txt | 6219 ++++++++++++++++++++ 3rdparty/openpgm-svn-r1135/pgm/COPYING | 504 ++ 3rdparty/openpgm-svn-r1135/pgm/INSTALL | 4 + 3rdparty/openpgm-svn-r1135/pgm/LICENSE | 19 + 3rdparty/openpgm-svn-r1135/pgm/README | 7 + 3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgm | 171 + 3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgm89 | 83 + 3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmex | 18 + .../openpgm-svn-r1135/pgm/SConscript.libpgmhttp | 53 + .../openpgm-svn-r1135/pgm/SConscript.libpgmsnmp | 35 + 3rdparty/openpgm-svn-r1135/pgm/SConstruct | 345 ++ 3rdparty/openpgm-svn-r1135/pgm/SConstruct.097 | 332 ++ .../openpgm-svn-r1135/pgm/SConstruct.097.intelc | 387 ++ .../openpgm-svn-r1135/pgm/SConstruct.097.mingw64 | 338 ++ .../openpgm-svn-r1135/pgm/SConstruct.097.sunstudio | 332 ++ 3rdparty/openpgm-svn-r1135/pgm/SConstruct.Debian4 | 281 + .../openpgm-svn-r1135/pgm/SConstruct.FreeBSD80 | 351 ++ .../openpgm-svn-r1135/pgm/SConstruct.OpenSolaris | 310 + 3rdparty/openpgm-svn-r1135/pgm/SConstruct.RHEL4 | 279 + .../openpgm-svn-r1135/pgm/SConstruct.Solaris.gcc64 | 350 ++ .../pgm/SConstruct.Solaris.sungcc | 337 ++ .../pgm/SConstruct.Solaris.sunstudio | 322 + 3rdparty/openpgm-svn-r1135/pgm/SConstruct.clang | 351 ++ 3rdparty/openpgm-svn-r1135/pgm/SConstruct.mingw | 331 ++ .../openpgm-svn-r1135/pgm/SConstruct.mingw-wine | 339 ++ 3rdparty/openpgm-svn-r1135/pgm/atomic_unittest.c | 166 + 3rdparty/openpgm-svn-r1135/pgm/backtrace.c | 69 + 3rdparty/openpgm-svn-r1135/pgm/checksum.c | 941 +++ 3rdparty/openpgm-svn-r1135/pgm/checksum_perftest.c | 807 +++ 3rdparty/openpgm-svn-r1135/pgm/checksum_unittest.c | 278 + 3rdparty/openpgm-svn-r1135/pgm/crossmingw.py | 144 + 3rdparty/openpgm-svn-r1135/pgm/crossmingw64.py | 140 + 3rdparty/openpgm-svn-r1135/pgm/engine.c | 282 + 3rdparty/openpgm-svn-r1135/pgm/engine.c.c89.patch | 58 + 3rdparty/openpgm-svn-r1135/pgm/engine_unittest.c | 234 + 3rdparty/openpgm-svn-r1135/pgm/error.c | 518 ++ 3rdparty/openpgm-svn-r1135/pgm/error_unittest.c | 292 + 3rdparty/openpgm-svn-r1135/pgm/examples/SConscript | 88 + .../openpgm-svn-r1135/pgm/examples/SConscript89 | 41 + 3rdparty/openpgm-svn-r1135/pgm/examples/async.c | 441 ++ 3rdparty/openpgm-svn-r1135/pgm/examples/async.h | 82 + .../openpgm-svn-r1135/pgm/examples/blocksyncrecv.c | 350 ++ 3rdparty/openpgm-svn-r1135/pgm/examples/daytime.c | 546 ++ .../pgm/examples/enonblocksyncrecv.c | 382 ++ .../pgm/examples/enonblocksyncrecvmsg.c | 382 ++ .../pgm/examples/enonblocksyncrecvmsgv.c | 397 ++ 3rdparty/openpgm-svn-r1135/pgm/examples/getopt.c | 110 + 3rdparty/openpgm-svn-r1135/pgm/examples/getopt.h | 62 + 3rdparty/openpgm-svn-r1135/pgm/examples/pgmdump.c | 279 + 3rdparty/openpgm-svn-r1135/pgm/examples/pgmping.cc | 1225 ++++ 3rdparty/openpgm-svn-r1135/pgm/examples/pgmrecv.c | 649 ++ 3rdparty/openpgm-svn-r1135/pgm/examples/pgmsend.c | 305 + 3rdparty/openpgm-svn-r1135/pgm/examples/pgmtop.c | 1031 ++++ 3rdparty/openpgm-svn-r1135/pgm/examples/ping.proto | 47 + .../pgm/examples/pnonblocksyncrecv.c | 385 ++ .../openpgm-svn-r1135/pgm/examples/purinrecv.c | 479 ++ .../openpgm-svn-r1135/pgm/examples/purinrecvcc.cc | 434 ++ .../openpgm-svn-r1135/pgm/examples/purinsend.c | 284 + .../openpgm-svn-r1135/pgm/examples/purinsendcc.cc | 269 + .../openpgm-svn-r1135/pgm/examples/shortcakerecv.c | 430 ++ .../pgm/examples/snonblocksyncrecv.c | 435 ++ 3rdparty/openpgm-svn-r1135/pgm/fec-block.txt | 66 + 3rdparty/openpgm-svn-r1135/pgm/fec.txt | 77 + 3rdparty/openpgm-svn-r1135/pgm/galois_generator.pl | 139 + 3rdparty/openpgm-svn-r1135/pgm/gcov-parse.pl | 41 + 3rdparty/openpgm-svn-r1135/pgm/gcov-seed.sh | 33 + 3rdparty/openpgm-svn-r1135/pgm/gcov.sh | 29 + 3rdparty/openpgm-svn-r1135/pgm/getifaddrs.c | 840 +++ .../openpgm-svn-r1135/pgm/getifaddrs.c.c89.patch | 218 + .../openpgm-svn-r1135/pgm/getifaddrs_unittest.c | 262 + 3rdparty/openpgm-svn-r1135/pgm/getnodeaddr.c | 196 + .../openpgm-svn-r1135/pgm/getnodeaddr.c.c89.patch | 59 + .../openpgm-svn-r1135/pgm/getnodeaddr_unittest.c | 573 ++ 3rdparty/openpgm-svn-r1135/pgm/gsi.c | 232 + 3rdparty/openpgm-svn-r1135/pgm/gsi.c.c89.patch | 53 + 3rdparty/openpgm-svn-r1135/pgm/gsi_unittest.c | 350 ++ 3rdparty/openpgm-svn-r1135/pgm/hashtable.c | 327 + .../openpgm-svn-r1135/pgm/hashtable.c.c89.patch | 47 + 3rdparty/openpgm-svn-r1135/pgm/histogram.c | 414 ++ .../openpgm-svn-r1135/pgm/histogram.c.c89.patch | 212 + 3rdparty/openpgm-svn-r1135/pgm/htdocs/404.html | 11 + 3rdparty/openpgm-svn-r1135/pgm/htdocs/base.css | 136 + .../pgm/htdocs/convert_to_macro.pl | 20 + 3rdparty/openpgm-svn-r1135/pgm/htdocs/robots.txt | 2 + .../pgm/htdocs/xhtml10_strict.doctype | 3 + 3rdparty/openpgm-svn-r1135/pgm/http.c | 1735 ++++++ 3rdparty/openpgm-svn-r1135/pgm/http_unittest.c | 186 + 3rdparty/openpgm-svn-r1135/pgm/if.c | 1598 +++++ 3rdparty/openpgm-svn-r1135/pgm/if.c.c89.patch | 376 ++ 3rdparty/openpgm-svn-r1135/pgm/if_unittest.c | 1497 +++++ .../openpgm-svn-r1135/pgm/include/impl/checksum.h | 75 + .../openpgm-svn-r1135/pgm/include/impl/engine.h | 43 + .../openpgm-svn-r1135/pgm/include/impl/features.h | 42 + .../openpgm-svn-r1135/pgm/include/impl/fixed.h | 156 + .../openpgm-svn-r1135/pgm/include/impl/framework.h | 76 + .../openpgm-svn-r1135/pgm/include/impl/galois.h | 153 + .../pgm/include/impl/getifaddrs.h | 76 + .../pgm/include/impl/getnodeaddr.h | 41 + .../openpgm-svn-r1135/pgm/include/impl/hashtable.h | 58 + .../openpgm-svn-r1135/pgm/include/impl/histogram.h | 129 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/i18n.h | 32 + .../pgm/include/impl/indextoaddr.h | 41 + .../pgm/include/impl/indextoname.h | 37 + .../pgm/include/impl/inet_network.h | 41 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/ip.h | 150 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/list.h | 43 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/math.h | 86 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/md5.h | 61 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/mem.h | 34 + .../openpgm-svn-r1135/pgm/include/impl/messages.h | 352 ++ .../pgm/include/impl/nametoindex.h | 40 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/net.h | 53 + .../openpgm-svn-r1135/pgm/include/impl/notify.h | 305 + .../pgm/include/impl/packet_parse.h | 45 + .../pgm/include/impl/packet_test.h | 40 + .../openpgm-svn-r1135/pgm/include/impl/pgmMIB.h | 28 + .../pgm/include/impl/pgmMIB_columns.h | 372 ++ .../pgm/include/impl/pgmMIB_enums.h | 64 + .../openpgm-svn-r1135/pgm/include/impl/processor.h | 61 + .../openpgm-svn-r1135/pgm/include/impl/queue.h | 51 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/rand.h | 50 + .../pgm/include/impl/rate_control.h | 54 + .../openpgm-svn-r1135/pgm/include/impl/receiver.h | 142 + .../pgm/include/impl/reed_solomon.h | 51 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/rxw.h | 223 + .../openpgm-svn-r1135/pgm/include/impl/slist.h | 52 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/sn.h | 174 + .../openpgm-svn-r1135/pgm/include/impl/sockaddr.h | 105 + .../openpgm-svn-r1135/pgm/include/impl/socket.h | 182 + .../openpgm-svn-r1135/pgm/include/impl/source.h | 75 + .../openpgm-svn-r1135/pgm/include/impl/sqn_list.h | 38 + .../openpgm-svn-r1135/pgm/include/impl/string.h | 59 + .../openpgm-svn-r1135/pgm/include/impl/thread.h | 211 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/time.h | 51 + .../openpgm-svn-r1135/pgm/include/impl/timer.h | 58 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/tsi.h | 39 + 3rdparty/openpgm-svn-r1135/pgm/include/impl/txw.h | 207 + .../pgm/include/impl/wsastrerror.h | 37 + .../openpgm-svn-r1135/pgm/include/pgm/atomic.h | 140 + .../openpgm-svn-r1135/pgm/include/pgm/backtrace.h | 33 + .../openpgm-svn-r1135/pgm/include/pgm/engine.h | 37 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/error.h | 109 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/gsi.h | 51 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/http.h | 37 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/if.h | 33 + .../openpgm-svn-r1135/pgm/include/pgm/ip/pgm.hh | 100 + .../pgm/include/pgm/ip/pgm_endpoint.hh | 171 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/list.h | 40 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/log.h | 33 + .../openpgm-svn-r1135/pgm/include/pgm/macros.h | 171 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/mem.h | 60 + .../openpgm-svn-r1135/pgm/include/pgm/messages.h | 66 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/msgv.h | 54 + .../openpgm-svn-r1135/pgm/include/pgm/packet.h | 475 ++ 3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm.h | 42 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm.hh | 33 + .../pgm/include/pgm/pgm_socket.hh | 157 + .../openpgm-svn-r1135/pgm/include/pgm/signal.h | 36 + .../openpgm-svn-r1135/pgm/include/pgm/skbuff.h | 258 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/snmp.h | 35 + .../openpgm-svn-r1135/pgm/include/pgm/socket.h | 172 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/time.h | 54 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/tsi.h | 49 + 3rdparty/openpgm-svn-r1135/pgm/include/pgm/types.h | 66 + .../openpgm-svn-r1135/pgm/include/pgm/version.h | 41 + .../openpgm-svn-r1135/pgm/include/pgm/winint.h | 198 + .../pgm/include/pgm/wininttypes.h | 254 + 3rdparty/openpgm-svn-r1135/pgm/indextoaddr.c | 98 + .../openpgm-svn-r1135/pgm/indextoaddr.c.c89.patch | 44 + .../openpgm-svn-r1135/pgm/indextoaddr_unittest.c | 302 + 3rdparty/openpgm-svn-r1135/pgm/indextoname.c | 52 + .../openpgm-svn-r1135/pgm/indextoname.c.c89.patch | 29 + 3rdparty/openpgm-svn-r1135/pgm/inet_network.c | 237 + .../openpgm-svn-r1135/pgm/inet_network.c.c89.patch | 76 + .../openpgm-svn-r1135/pgm/inet_network_unittest.c | 203 + 3rdparty/openpgm-svn-r1135/pgm/ip_unittest.c | 367 ++ 3rdparty/openpgm-svn-r1135/pgm/list.c | 146 + 3rdparty/openpgm-svn-r1135/pgm/log.c | 151 + 3rdparty/openpgm-svn-r1135/pgm/math.c | 75 + 3rdparty/openpgm-svn-r1135/pgm/math.c.c89.patch | 16 + 3rdparty/openpgm-svn-r1135/pgm/md5.c | 368 ++ 3rdparty/openpgm-svn-r1135/pgm/md5.c.c89.patch | 34 + 3rdparty/openpgm-svn-r1135/pgm/md5_unittest.c | 189 + 3rdparty/openpgm-svn-r1135/pgm/mem.c | 250 + 3rdparty/openpgm-svn-r1135/pgm/mem.c.c89.patch | 145 + 3rdparty/openpgm-svn-r1135/pgm/memcheck | 13 + 3rdparty/openpgm-svn-r1135/pgm/messages.c | 173 + .../openpgm-svn-r1135/pgm/messages.c.c89.patch | 91 + .../pgm/mibs/PGM-MIB-petrova-01.txt | 5459 +++++++++++++++++ 3rdparty/openpgm-svn-r1135/pgm/mld-semantics.txt | 52 + 3rdparty/openpgm-svn-r1135/pgm/msfec.txt | 33 + 3rdparty/openpgm-svn-r1135/pgm/nametoindex.c | 249 + .../openpgm-svn-r1135/pgm/nametoindex.c.c89.patch | 89 + 3rdparty/openpgm-svn-r1135/pgm/net-snmp.txt | 34 + 3rdparty/openpgm-svn-r1135/pgm/net.c | 181 + 3rdparty/openpgm-svn-r1135/pgm/net.c.c89.patch | 67 + 3rdparty/openpgm-svn-r1135/pgm/net_unittest.c | 375 ++ 3rdparty/openpgm-svn-r1135/pgm/options.txt | 158 + 3rdparty/openpgm-svn-r1135/pgm/packet_parse.c | 619 ++ .../openpgm-svn-r1135/pgm/packet_parse.c.c89.patch | 121 + .../openpgm-svn-r1135/pgm/packet_parse_unittest.c | 382 ++ 3rdparty/openpgm-svn-r1135/pgm/packet_test.c | 1162 ++++ .../openpgm-svn-r1135/pgm/packet_test.c.c89.patch | 401 ++ .../openpgm-svn-r1135/pgm/packet_test_unittest.c | 169 + 3rdparty/openpgm-svn-r1135/pgm/pgmMIB.c | 3212 ++++++++++ 3rdparty/openpgm-svn-r1135/pgm/pgmMIB_unittest.c | 257 + 3rdparty/openpgm-svn-r1135/pgm/plan.txt | 238 + 3rdparty/openpgm-svn-r1135/pgm/queue.c | 110 + 3rdparty/openpgm-svn-r1135/pgm/rand.c | 137 + 3rdparty/openpgm-svn-r1135/pgm/rand.c.c89.patch | 34 + 3rdparty/openpgm-svn-r1135/pgm/rate_control.c | 158 + .../openpgm-svn-r1135/pgm/rate_control.c.c89.patch | 62 + .../openpgm-svn-r1135/pgm/rate_control_unittest.c | 241 + 3rdparty/openpgm-svn-r1135/pgm/receiver.c | 2292 ++++++++ .../openpgm-svn-r1135/pgm/receiver.c.c89.patch | 887 +++ 3rdparty/openpgm-svn-r1135/pgm/receiver.c.rej | 37 + 3rdparty/openpgm-svn-r1135/pgm/receiver_unittest.c | 902 +++ 3rdparty/openpgm-svn-r1135/pgm/recv.c | 1062 ++++ 3rdparty/openpgm-svn-r1135/pgm/recv.c.c89.patch | 404 ++ 3rdparty/openpgm-svn-r1135/pgm/recv_unittest.c | 1600 +++++ 3rdparty/openpgm-svn-r1135/pgm/reed_solomon.c | 576 ++ .../openpgm-svn-r1135/pgm/reed_solomon.c.c89.patch | 467 ++ .../openpgm-svn-r1135/pgm/reed_solomon_unittest.c | 305 + 3rdparty/openpgm-svn-r1135/pgm/rxw.c | 2233 +++++++ 3rdparty/openpgm-svn-r1135/pgm/rxw.c.c89.patch | 565 ++ 3rdparty/openpgm-svn-r1135/pgm/rxw_unittest.c | 1844 ++++++ 3rdparty/openpgm-svn-r1135/pgm/signal.c | 179 + 3rdparty/openpgm-svn-r1135/pgm/signal_unittest.c | 115 + 3rdparty/openpgm-svn-r1135/pgm/skbuff.c | 115 + 3rdparty/openpgm-svn-r1135/pgm/slist.c | 166 + 3rdparty/openpgm-svn-r1135/pgm/snmp.c | 222 + 3rdparty/openpgm-svn-r1135/pgm/snmp_unittest.c | 184 + 3rdparty/openpgm-svn-r1135/pgm/sockaddr.c | 1193 ++++ .../openpgm-svn-r1135/pgm/sockaddr.c.c89.patch | 75 + 3rdparty/openpgm-svn-r1135/pgm/socket.c | 2150 +++++++ 3rdparty/openpgm-svn-r1135/pgm/socket.c.c89.patch | 403 ++ 3rdparty/openpgm-svn-r1135/pgm/socket_unittest.c | 1293 ++++ 3rdparty/openpgm-svn-r1135/pgm/source.c | 2345 ++++++++ 3rdparty/openpgm-svn-r1135/pgm/source.c.c89.patch | 1021 ++++ 3rdparty/openpgm-svn-r1135/pgm/source.c.orig | 2344 ++++++++ 3rdparty/openpgm-svn-r1135/pgm/source.c.rej | 17 + 3rdparty/openpgm-svn-r1135/pgm/source_unittest.c | 1248 ++++ 3rdparty/openpgm-svn-r1135/pgm/string.c | 486 ++ 3rdparty/openpgm-svn-r1135/pgm/string.c.c89.patch | 39 + 3rdparty/openpgm-svn-r1135/pgm/test/PGM/Test.pm | 394 ++ 3rdparty/openpgm-svn-r1135/pgm/test/SConscript | 15 + 3rdparty/openpgm-svn-r1135/pgm/test/ambient_spm.pl | 87 + 3rdparty/openpgm-svn-r1135/pgm/test/apdu.pl | 58 + 3rdparty/openpgm-svn-r1135/pgm/test/apdu_parity.pl | 59 + 3rdparty/openpgm-svn-r1135/pgm/test/app.c | 1068 ++++ 3rdparty/openpgm-svn-r1135/pgm/test/async.c | 579 ++ 3rdparty/openpgm-svn-r1135/pgm/test/async.h | 76 + 3rdparty/openpgm-svn-r1135/pgm/test/dump-json.c | 1292 ++++ 3rdparty/openpgm-svn-r1135/pgm/test/dump-json.h | 33 + .../openpgm-svn-r1135/pgm/test/heartbeat_spm.pl | 58 + 3rdparty/openpgm-svn-r1135/pgm/test/monitor.c | 349 ++ 3rdparty/openpgm-svn-r1135/pgm/test/nak.pl | 68 + .../openpgm-svn-r1135/pgm/test/nak_cancellation.pl | 163 + 3rdparty/openpgm-svn-r1135/pgm/test/nak_list.pl | 72 + 3rdparty/openpgm-svn-r1135/pgm/test/nak_parity.pl | 75 + 3rdparty/openpgm-svn-r1135/pgm/test/nak_repeat.pl | 71 + 3rdparty/openpgm-svn-r1135/pgm/test/ncf.pl | 68 + .../openpgm-svn-r1135/pgm/test/ncf_cancellation.pl | 149 + 3rdparty/openpgm-svn-r1135/pgm/test/ncf_list.pl | 74 + .../openpgm-svn-r1135/pgm/test/ncf_suppression.pl | 103 + 3rdparty/openpgm-svn-r1135/pgm/test/odata.pl | 45 + .../openpgm-svn-r1135/pgm/test/odata_completion.pl | 89 + 3rdparty/openpgm-svn-r1135/pgm/test/odata_jump.pl | 73 + .../pgm/test/odata_jump_parity.pl | 83 + .../openpgm-svn-r1135/pgm/test/odata_number.pl | 60 + 3rdparty/openpgm-svn-r1135/pgm/test/odata_rate.pl | 69 + .../openpgm-svn-r1135/pgm/test/odata_reception.pl | 61 + .../openpgm-svn-r1135/pgm/test/on-demand_spm.pl | 49 + .../openpgm-svn-r1135/pgm/test/outofwindow_ncf.pl | 105 + .../openpgm-svn-r1135/pgm/test/rdata_completion.pl | 89 + .../pgm/test/rdata_completion_parity.pl | 97 + .../pgm/test/rdata_completion_parity_var_pktlen.pl | 97 + 3rdparty/openpgm-svn-r1135/pgm/test/rdata_jump.pl | 73 + .../openpgm-svn-r1135/pgm/test/rdata_reception.pl | 61 + 3rdparty/openpgm-svn-r1135/pgm/test/sim.c | 2301 ++++++++ 3rdparty/openpgm-svn-r1135/pgm/test/spm.pl | 43 + 3rdparty/openpgm-svn-r1135/pgm/test/spm_jump.pl | 62 + 3rdparty/openpgm-svn-r1135/pgm/test/spm_jump2.pl | 61 + .../openpgm-svn-r1135/pgm/test/spm_reception.pl | 60 + 3rdparty/openpgm-svn-r1135/pgm/test/spmr.pl | 75 + .../openpgm-svn-r1135/pgm/test/spmr_after_spm.pl | 80 + .../openpgm-svn-r1135/pgm/test/spmr_from_odata.pl | 55 + .../openpgm-svn-r1135/pgm/test/spmr_suppression.pl | 60 + .../openpgm-svn-r1135/pgm/test/sudoers.example | 26 + 3rdparty/openpgm-svn-r1135/pgm/test/test.conf.pl | 27 + 3rdparty/openpgm-svn-r1135/pgm/thread.c | 457 ++ 3rdparty/openpgm-svn-r1135/pgm/thread.c.c89.patch | 137 + 3rdparty/openpgm-svn-r1135/pgm/time.c | 774 +++ 3rdparty/openpgm-svn-r1135/pgm/time.c.c89.patch | 115 + 3rdparty/openpgm-svn-r1135/pgm/time_unittest.c | 188 + 3rdparty/openpgm-svn-r1135/pgm/timer.c | 227 + 3rdparty/openpgm-svn-r1135/pgm/timer.c.c89.patch | 63 + 3rdparty/openpgm-svn-r1135/pgm/timer_unittest.c | 355 ++ .../pgm/token and leaky bucket.txt | 12 + 3rdparty/openpgm-svn-r1135/pgm/tsi.c | 119 + 3rdparty/openpgm-svn-r1135/pgm/tsi.c.c89.patch | 33 + 3rdparty/openpgm-svn-r1135/pgm/tsi_unittest.c | 185 + 3rdparty/openpgm-svn-r1135/pgm/txw.c | 767 +++ 3rdparty/openpgm-svn-r1135/pgm/txw.c.c89.patch | 223 + 3rdparty/openpgm-svn-r1135/pgm/txw_unittest.c | 743 +++ 3rdparty/openpgm-svn-r1135/pgm/valgrind.supp | 147 + .../openpgm-svn-r1135/pgm/version_generator.py | 52 + .../pgm/win/mingw32-runtime_3.13-1openpgm3.diff | 136 + .../pgm/win/mingw32-runtime_3.15.2-0openpgm1.diff | 135 + ...mingw-w64-bin_x86-64-linux_4.4.1-1openpgm1.diff | 53 + 3rdparty/openpgm-svn-r1135/pgm/wsastrerror.c | 372 ++ 592 files changed, 101736 insertions(+), 91122 deletions(-) delete mode 100644 3rdparty/01-libpgm-fix-switch-fallthrough.patch delete mode 100644 3rdparty/openpgm-svn-r1085/doc/draft-ietf-rmt-bb-pgmcc-03.txt delete mode 100644 3rdparty/openpgm-svn-r1085/doc/rfc3208.txt delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/COPYING delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/INSTALL delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/LICENSE delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/README delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgm delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgm89 delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmex delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmhttp delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmsnmp delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.097 delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.intelc delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.mingw64 delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.sunstudio delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.Debian4 delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.FreeBSD80 delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.OpenSolaris delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.RHEL4 delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.gcc64 delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.sungcc delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.sunstudio delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.clang delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.mingw delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/SConstruct.mingw-wine delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/atomic_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/backtrace.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/checksum.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/checksum_perftest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/checksum_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/crossmingw.py delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/crossmingw64.py delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/engine.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/engine_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/error.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/error_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/SConscript delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/SConscript89 delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/async.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/async.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/blocksyncrecv.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/daytime.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecv.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecvmsg.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecvmsgv.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/getopt.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/getopt.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/pgmdump.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/pgmping.cc delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/pgmrecv.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/pgmsend.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/pgmtop.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/ping.proto delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/pnonblocksyncrecv.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/purinrecv.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/purinrecvcc.cc delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/purinsend.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/purinsendcc.cc delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/shortcakerecv.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/examples/snonblocksyncrecv.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/fec-block.txt delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/fec.txt delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/galois_generator.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/gcov-parse.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/gcov-seed.sh delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/gcov.sh delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/getifaddrs.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/getifaddrs_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/getnodeaddr.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/getnodeaddr_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/gsi.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/gsi_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/hashtable.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/histogram.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/htdocs/404.html delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/htdocs/base.css delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/htdocs/convert_to_macro.pl delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/htdocs/robots.txt delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/htdocs/xhtml10_strict.doctype delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/http.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/http_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/if.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/if_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/checksum.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/engine.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/features.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/fixed.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/framework.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/galois.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/getifaddrs.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/getnodeaddr.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/hashtable.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/histogram.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/i18n.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/indextoaddr.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/indextoname.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/inet_network.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/ip.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/list.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/math.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/md5.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/mem.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/messages.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/nametoindex.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/net.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/notify.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/packet_parse.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/packet_test.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB_columns.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB_enums.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/processor.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/queue.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/rand.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/rate_control.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/receiver.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/reed_solomon.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/rxw.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/slist.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/sn.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/sockaddr.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/socket.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/source.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/sqn_list.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/string.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/thread.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/time.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/timer.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/tsi.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/txw.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/impl/wsastrerror.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/atomic.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/backtrace.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/engine.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/error.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/gsi.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/http.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/if.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/ip/pgm.hh delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/ip/pgm_endpoint.hh delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/list.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/log.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/macros.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/mem.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/messages.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/msgv.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/packet.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm.hh delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm_socket.hh delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/signal.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/skbuff.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/snmp.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/socket.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/time.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/tsi.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/types.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/version.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/winint.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/include/pgm/wininttypes.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/indextoaddr.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/indextoaddr_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/indextoname.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/inet_network.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/inet_network_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/ip_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/list.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/log.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/math.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/md5.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/md5_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/mem.c delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/memcheck delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/messages.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/mibs/PGM-MIB-petrova-01.txt delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/mld-semantics.txt delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/msfec.txt delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/nametoindex.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/net-snmp.txt delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/net.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/net_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/options.txt delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/packet_parse.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/packet_parse_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/packet_test.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/packet_test_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/pgmMIB.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/pgmMIB_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/plan.txt delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/queue.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/rand.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/rate_control.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/rate_control_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/receiver.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/receiver_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/recv.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/recv_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/reed_solomon.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/reed_solomon_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/rxw.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/rxw_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/signal.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/signal_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/skbuff.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/slist.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/snmp.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/snmp_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/sockaddr.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/socket.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/socket_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/source.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/source_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/string.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/test/PGM/Test.pm delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/test/SConscript delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/ambient_spm.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/apdu.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/apdu_parity.pl delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/test/app.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/test/async.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/test/async.h delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/test/dump-json.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/test/dump-json.h delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/heartbeat_spm.pl delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/test/monitor.c delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/nak.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/nak_cancellation.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/nak_list.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/nak_parity.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/nak_repeat.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/ncf.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/ncf_cancellation.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/ncf_list.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/ncf_suppression.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/odata.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/odata_completion.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/odata_jump.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/odata_jump_parity.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/odata_number.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/odata_rate.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/odata_reception.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/on-demand_spm.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/outofwindow_ncf.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion_parity.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion_parity_var_pktlen.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/rdata_jump.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/rdata_reception.pl delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/test/sim.c delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/spm.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/spm_jump.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/spm_jump2.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/spm_reception.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/spmr.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/spmr_after_spm.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/spmr_from_odata.pl delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/test/spmr_suppression.pl delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/test/sudoers.example delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/test/test.conf.pl delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/thread.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/time.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/time_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/timer.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/timer_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/token and leaky bucket.txt delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/tsi.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/tsi_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/txw.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/txw_unittest.c delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/valgrind.supp delete mode 100755 3rdparty/openpgm-svn-r1085/pgm/version_generator.py delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/win/mingw32-runtime_3.13-1openpgm3.diff delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/win/mingw32-runtime_3.15.2-0openpgm1.diff delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/win64/mingw-w64-bin_x86-64-linux_4.4.1-1openpgm1.diff delete mode 100644 3rdparty/openpgm-svn-r1085/pgm/wsastrerror.c create mode 100644 3rdparty/openpgm-svn-r1135-0001-sigsegv-in-txw.patch create mode 100644 3rdparty/openpgm-svn-r1135-0002-correct-checksum-calculation.patch create mode 100644 3rdparty/openpgm-svn-r1135-0003-fix-rdata-congestion-control.patch create mode 100644 3rdparty/openpgm-svn-r1135/doc/draft-ietf-rmt-bb-pgmcc-03.txt create mode 100644 3rdparty/openpgm-svn-r1135/doc/rfc3208.txt create mode 100644 3rdparty/openpgm-svn-r1135/pgm/COPYING create mode 100644 3rdparty/openpgm-svn-r1135/pgm/INSTALL create mode 100644 3rdparty/openpgm-svn-r1135/pgm/LICENSE create mode 100644 3rdparty/openpgm-svn-r1135/pgm/README create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgm create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgm89 create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmex create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmhttp create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmsnmp create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.097 create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.intelc create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.mingw64 create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.sunstudio create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.Debian4 create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.FreeBSD80 create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.OpenSolaris create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.RHEL4 create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.gcc64 create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.sungcc create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.sunstudio create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.clang create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.mingw create mode 100644 3rdparty/openpgm-svn-r1135/pgm/SConstruct.mingw-wine create mode 100644 3rdparty/openpgm-svn-r1135/pgm/atomic_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/backtrace.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/checksum.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/checksum_perftest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/checksum_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/crossmingw.py create mode 100644 3rdparty/openpgm-svn-r1135/pgm/crossmingw64.py create mode 100644 3rdparty/openpgm-svn-r1135/pgm/engine.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/engine.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/engine_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/error.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/error_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/SConscript create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/SConscript89 create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/async.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/async.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/blocksyncrecv.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/daytime.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecv.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecvmsg.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecvmsgv.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/getopt.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/getopt.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/pgmdump.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/pgmping.cc create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/pgmrecv.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/pgmsend.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/pgmtop.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/ping.proto create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/pnonblocksyncrecv.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/purinrecv.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/purinrecvcc.cc create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/purinsend.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/purinsendcc.cc create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/shortcakerecv.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/examples/snonblocksyncrecv.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/fec-block.txt create mode 100644 3rdparty/openpgm-svn-r1135/pgm/fec.txt create mode 100755 3rdparty/openpgm-svn-r1135/pgm/galois_generator.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/gcov-parse.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/gcov-seed.sh create mode 100755 3rdparty/openpgm-svn-r1135/pgm/gcov.sh create mode 100644 3rdparty/openpgm-svn-r1135/pgm/getifaddrs.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/getifaddrs.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/getifaddrs_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/getnodeaddr.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/getnodeaddr.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/getnodeaddr_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/gsi.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/gsi.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/gsi_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/hashtable.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/hashtable.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/histogram.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/histogram.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/htdocs/404.html create mode 100644 3rdparty/openpgm-svn-r1135/pgm/htdocs/base.css create mode 100755 3rdparty/openpgm-svn-r1135/pgm/htdocs/convert_to_macro.pl create mode 100644 3rdparty/openpgm-svn-r1135/pgm/htdocs/robots.txt create mode 100644 3rdparty/openpgm-svn-r1135/pgm/htdocs/xhtml10_strict.doctype create mode 100644 3rdparty/openpgm-svn-r1135/pgm/http.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/http_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/if.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/if.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/if_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/checksum.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/engine.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/features.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/fixed.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/framework.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/galois.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/getifaddrs.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/getnodeaddr.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/hashtable.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/histogram.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/i18n.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/indextoaddr.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/indextoname.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/inet_network.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/ip.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/list.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/math.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/md5.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/mem.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/messages.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/nametoindex.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/net.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/notify.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/packet_parse.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/packet_test.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB_columns.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB_enums.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/processor.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/queue.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/rand.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/rate_control.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/receiver.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/reed_solomon.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/rxw.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/slist.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/sn.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/sockaddr.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/socket.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/source.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/sqn_list.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/string.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/thread.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/time.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/timer.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/tsi.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/txw.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/impl/wsastrerror.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/atomic.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/backtrace.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/engine.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/error.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/gsi.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/http.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/if.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/ip/pgm.hh create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/ip/pgm_endpoint.hh create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/list.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/log.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/macros.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/mem.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/messages.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/msgv.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/packet.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm.hh create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm_socket.hh create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/signal.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/skbuff.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/snmp.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/socket.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/time.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/tsi.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/types.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/version.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/winint.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/include/pgm/wininttypes.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/indextoaddr.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/indextoaddr.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/indextoaddr_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/indextoname.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/indextoname.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/inet_network.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/inet_network.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/inet_network_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/ip_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/list.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/log.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/math.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/math.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/md5.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/md5.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/md5_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/mem.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/mem.c.c89.patch create mode 100755 3rdparty/openpgm-svn-r1135/pgm/memcheck create mode 100644 3rdparty/openpgm-svn-r1135/pgm/messages.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/messages.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/mibs/PGM-MIB-petrova-01.txt create mode 100644 3rdparty/openpgm-svn-r1135/pgm/mld-semantics.txt create mode 100644 3rdparty/openpgm-svn-r1135/pgm/msfec.txt create mode 100644 3rdparty/openpgm-svn-r1135/pgm/nametoindex.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/nametoindex.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/net-snmp.txt create mode 100644 3rdparty/openpgm-svn-r1135/pgm/net.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/net.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/net_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/options.txt create mode 100644 3rdparty/openpgm-svn-r1135/pgm/packet_parse.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/packet_parse.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/packet_parse_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/packet_test.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/packet_test.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/packet_test_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/pgmMIB.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/pgmMIB_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/plan.txt create mode 100644 3rdparty/openpgm-svn-r1135/pgm/queue.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/rand.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/rand.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/rate_control.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/rate_control.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/rate_control_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/receiver.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/receiver.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/receiver.c.rej create mode 100644 3rdparty/openpgm-svn-r1135/pgm/receiver_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/recv.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/recv.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/recv_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/reed_solomon.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/reed_solomon.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/reed_solomon_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/rxw.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/rxw.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/rxw_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/signal.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/signal_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/skbuff.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/slist.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/snmp.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/snmp_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/sockaddr.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/sockaddr.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/socket.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/socket.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/socket_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/source.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/source.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/source.c.orig create mode 100644 3rdparty/openpgm-svn-r1135/pgm/source.c.rej create mode 100644 3rdparty/openpgm-svn-r1135/pgm/source_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/string.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/string.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/test/PGM/Test.pm create mode 100644 3rdparty/openpgm-svn-r1135/pgm/test/SConscript create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/ambient_spm.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/apdu.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/apdu_parity.pl create mode 100644 3rdparty/openpgm-svn-r1135/pgm/test/app.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/test/async.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/test/async.h create mode 100644 3rdparty/openpgm-svn-r1135/pgm/test/dump-json.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/test/dump-json.h create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/heartbeat_spm.pl create mode 100644 3rdparty/openpgm-svn-r1135/pgm/test/monitor.c create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/nak.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/nak_cancellation.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/nak_list.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/nak_parity.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/nak_repeat.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/ncf.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/ncf_cancellation.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/ncf_list.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/ncf_suppression.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/odata.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/odata_completion.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/odata_jump.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/odata_jump_parity.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/odata_number.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/odata_rate.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/odata_reception.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/on-demand_spm.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/outofwindow_ncf.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion_parity.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion_parity_var_pktlen.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/rdata_jump.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/rdata_reception.pl create mode 100644 3rdparty/openpgm-svn-r1135/pgm/test/sim.c create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/spm.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/spm_jump.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/spm_jump2.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/spm_reception.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/spmr.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/spmr_after_spm.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/spmr_from_odata.pl create mode 100755 3rdparty/openpgm-svn-r1135/pgm/test/spmr_suppression.pl create mode 100644 3rdparty/openpgm-svn-r1135/pgm/test/sudoers.example create mode 100644 3rdparty/openpgm-svn-r1135/pgm/test/test.conf.pl create mode 100644 3rdparty/openpgm-svn-r1135/pgm/thread.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/thread.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/time.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/time.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/time_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/timer.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/timer.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/timer_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/token and leaky bucket.txt create mode 100644 3rdparty/openpgm-svn-r1135/pgm/tsi.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/tsi.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/tsi_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/txw.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/txw.c.c89.patch create mode 100644 3rdparty/openpgm-svn-r1135/pgm/txw_unittest.c create mode 100644 3rdparty/openpgm-svn-r1135/pgm/valgrind.supp create mode 100755 3rdparty/openpgm-svn-r1135/pgm/version_generator.py create mode 100644 3rdparty/openpgm-svn-r1135/pgm/win/mingw32-runtime_3.13-1openpgm3.diff create mode 100644 3rdparty/openpgm-svn-r1135/pgm/win/mingw32-runtime_3.15.2-0openpgm1.diff create mode 100644 3rdparty/openpgm-svn-r1135/pgm/win64/mingw-w64-bin_x86-64-linux_4.4.1-1openpgm1.diff create mode 100644 3rdparty/openpgm-svn-r1135/pgm/wsastrerror.c (limited to '3rdparty') diff --git a/3rdparty/01-libpgm-fix-switch-fallthrough.patch b/3rdparty/01-libpgm-fix-switch-fallthrough.patch deleted file mode 100644 index 23dfc9c..0000000 --- a/3rdparty/01-libpgm-fix-switch-fallthrough.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Naur pgm/socket.c pgm-fixed/socket.c ---- pgm/socket.c 2010-05-22 06:42:00.000000000 +0200 -+++ pgm-fixed/socket.c 2010-07-14 19:24:43.710669589 +0200 -@@ -641,6 +641,7 @@ - break; - sock->spmr_expiry = *(const int*)optval; - status = TRUE; -+ break; - - /* size of receive window in sequence numbers. - * 0 < rxw_sqns < one less than half sequence space diff --git a/3rdparty/openpgm-svn-r1085/doc/draft-ietf-rmt-bb-pgmcc-03.txt b/3rdparty/openpgm-svn-r1085/doc/draft-ietf-rmt-bb-pgmcc-03.txt deleted file mode 100644 index 6f1869c..0000000 --- a/3rdparty/openpgm-svn-r1085/doc/draft-ietf-rmt-bb-pgmcc-03.txt +++ /dev/null @@ -1,1226 +0,0 @@ - -Internet Engineering Task Force RMT WG -INTERNET-DRAFT Luigi Rizzo/U. Pisa -draft-ietf-rmt-bb-pgmcc-03.txt Gianluca Iannaccone/Intel - Lorenzo Vicisano/Cisco - Mark Handley/UCL - 12 July 2004 - Expires: January 2005 - - - PGMCC single rate multicast congestion control: - Protocol Specification - - - -Status of this Document - -This document is an Internet-Draft and is in full conformance with all -provisions of Section 10 of RFC2026. - -Internet-Drafts are working documents of the Internet Engineering Task -Force (IETF), its areas, and its working groups. Note that other groups -may also distribute working documents as Internet-Drafts. - -Internet-Drafts are valid for a maximum of six months and may be -updated, replaced, or obsoleted by other documents at any time. It is -inappropriate to use Internet-Drafts as reference material or to cite -them other than as a "work in progress". - -The list of current Internet-Drafts can be accessed at -http://www.ietf.org/ietf/1id-abstracts.txt - -To view the list Internet-Draft Shadow Directories, see -http://www.ietf.org/shadow.html. - -This document is a product of the IETF RMT WG. Comments should be -addressed to the authors, or the WG's mailing list at rmt@lbl.gov. - - - Abstract - - - This document describes PGMCC, a single rate multicast - congestion control scheme which is TCP-friendly and achieves - scalability, stability and fast response to variations in - network conditions. PGMCC is suitable for both non-reliable - - - -Rizzo/Iannaccone/Vicisano/Handley [Page 1] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - - and reliable data transfers. It is mainly designed for NAK- - based multicast protocols, and uses a window-based, TCP-like - control loop using positive ACKs between one representative of - the receiver group (the ACKER) and the sender. The ACKER is - selected dynamically and may change over time. - - PGMCC is made of two components: a window-based control loop, - which closely mimics TCP behavior, and a fast and low-overhead - procedure to select (and track changes of) the ACKER. The - scheme is robust to measurement errors, and supports fast - response to changes in the receiver set and/or network - conditions. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Rizzo/Iannaccone/Vicisano/Handley [Page 2] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - - Table of Contents - - - 1. Introduction. . . . . . . . . . . . . . . . . . . . . . 4 - 1.1. Terminology. . . . . . . . . . . . . . . . . . . . . 4 - 2. Protocol Overview . . . . . . . . . . . . . . . . . . . 4 - 2.1. Packet Contents. . . . . . . . . . . . . . . . . . . 6 - 2.1.1. Data Packets. . . . . . . . . . . . . . . . . . . 6 - 2.1.2. Feedback Packets. . . . . . . . . . . . . . . . . 7 - 2.1.3. Field sizes and formats . . . . . . . . . . . . . 8 - 2.2. Window-based controller. . . . . . . . . . . . . . . 9 - 2.3. Acker Selection. . . . . . . . . . . . . . . . . . . 11 - 2.3.1. Initial Acker election. . . . . . . . . . . . . . 11 - 2.3.2. Acker dropouts. . . . . . . . . . . . . . . . . . 12 - 2.4. TCP Throughput Equation. . . . . . . . . . . . . . . 12 - 2.5. RTT measurement. . . . . . . . . . . . . . . . . . . 13 - 2.5.1. Explicit Timestamp. . . . . . . . . . . . . . . . 13 - 2.5.2. Implicit timestamp. . . . . . . . . . . . . . . . 13 - 2.5.3. Sequence numbers. . . . . . . . . . . . . . . . . 14 - 2.5.4. Recommendations . . . . . . . . . . . . . . . . . 15 - 2.6. Loss rate measurement. . . . . . . . . . . . . . . . 15 - 2.7. Timeouts . . . . . . . . . . . . . . . . . . . . . . 16 - 2.8. Interaction with feedback suppression - schemes . . . . . . . . . . . . . . . . . . . . . . . . . 16 - 2.9. Interaction with ECN . . . . . . . . . . . . . . . . 17 - 3. Procedures - Sender . . . . . . . . . . . . . . . . . . 17 - 4. Procedures -- Receiver. . . . . . . . . . . . . . . . . 18 - 5. Security Considerations . . . . . . . . . . . . . . . . 19 - 6. Authors' Addresses. . . . . . . . . . . . . . . . . . . 20 - 7. Acknowledgments . . . . . . . . . . . . . . . . . . . . 20 - 8. Full Copyright Statement. . . . . . . . . . . . . . . . 21 - - - - - - - - - - - - - - - - - - - - -Rizzo/Iannaccone/Vicisano/Handley [Page 3] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -1. Introduction - -This document describes PGMCC, a single rate multicast congestion -control scheme which is TCP-friendly and achieves scalability, stability -and fast response to variations in network conditions. - -PGMCC is designed for multicast sessions with one sender and one or more -receivers, and is a good match for transport protocols using negative -acknowledgements (NAKs) to collect feedback from the receivers. The -congestion control scheme implemented by PGMCC closely mimics the -congestion-control behavior of TCP, as it uses a window-based control -loop which is run between the sender and a selected receiver called the -ACKER. The role of the ACKER is to provide timely feedback in the same -way as a TCP receiver; additionally, the ACKER is selected dynamically -among the receivers as the one which would experience the lowest -throughput if separate TCP sessions were run between the sender and each -of the receivers. - -Scalability in PGMCC comes from the use of negative acknowledgements -(NAKs) for collecting feedback from receivers other than the ACKER. As -a consequence, the usual techniques for NAK suppression and aggregation -can be used to reduce the amount of feedback to the source and improve -the scalability of the scheme. - -PGMCC is designed to completely decouple congestion control from data -integrity. As a consequence, the scheme can work with both reliable data -transfer and unreliable communication protocols such as those used for -video or audio streaming. - -While designed with multicast in mind, PGMCC can be equally used as a -replacement for TCP for unicast sessions which require a lower degree of -reliability than what TCP offers. - - -1.1. Terminology - -In this document, the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", -"SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and -"OPTIONAL" are to be interpreted as described in RFC 2119 and indicate -requirement levels for compliant PGMCC implementations. - - -2. Protocol Overview - -PGMCC is based on two separate but complementary mechanisms: - - o A window-based control loop which closely emulates TCP congestion - control. - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2. [Page 4] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - - The window-based control loop is simply an adaptation of the TCP - congestion control scheme to transport protocols where missing - (because of network errors or congestion) data packets are not - necessarily retransmitted, and so the congestion control scheme - cannot rely on cumulative acknowledgements. In PGMCC, the - ``congestion window'' is simulated using a token-based scheme which - permits congestion control to be decoupled from retransmission - state. One of the receivers in the group operates as the ACKER, i.e. - the node in charge of sending positive acknowledgements back to the - source and thus controlling the rate of the transfer. - - - o A procedure to select the ACKER. - The purpose of this procedure is to make sure that, in presence of - multiple receivers, the ACKER is dynamically selected to be the - receiver which would have the lowest throughput if separate TCP - sessions were run between the sender and each receiver. - For the acker selection mechanism, PGMCC uses a throughput equation - to determine the expected throughput for a given receiver as a - function of the loss rate and round-trip time. Unlike other schemes - [2], the TCP throughput equation is not used to determine the actual - sending rate, which is completely controlled by the window-based - control loop. - - -In principle, PGMCC's congestion control mechanism works as follows: - - - o Receivers measure the loss rate and feed this information back to - the sender, either in ACK or NAK messages. - - - o The sender also uses these feedback messages to measure the round- - trip time (RTT) to each receiver. - - - o The loss rate and RTT are then fed into PGMCC's throughput equation, - to determine the expected throughput to that receiver. - - - o The sender then selects as the acker the receiver with the lowest - expected throughput, as computed by the equation. - -The dynamics of the acker selection mechanism are sensitive to how the -measurements are performed and applied. In the rest of this document we -suggest specific mechanisms to perform and apply these measurements. -Other mechanisms are possible, but it is important to understand how the -interactions between mechanisms affect the dynamics of PGMCC. - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2. [Page 5] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -2.1. Packet Contents - -Before specifying the sender and receiver functionality, we describe the -information required by PGMCC to perform its tasks. This information is -carried in the data packets sent by the sender, and in the feedback -packets sent by the receiver. As PGMCC will be used along with some -transport protocol, the actual data and feedback packets will contain -further information for use by the protocol itself. For this reason, we -do not specify packet formats, as these depend on the details of the -transport protocol used. - -Note that the requirements of the transport protocol in terms of packet -generation may differ from those of PGMCC. As an example, most NAK-based -reliable multicast protocols do not use positive acknowledgements, but -PGMCC requires ACKs for clocking out data packets; unreliable transport -protocols might have no interest in generating NAKs for data integrity -purposes, yet PGMCC depends on NAKs reaching the data sender in order to -elect the ACKER. - - -Implementors may decide to insert PGMCC-related information in already -existing protocol packets whenever possible, but in cases such as the -ones described in the previous paragraph, it might be necessary to -define and generate new packets exclusively for congestion control -purposes. As an example, in a prototype implementation of PGMCC on top -of the PGM protocol [7], some of the information used by PGMCC is -already present in the original protocol packets, and PGMCC-specific -information is carried as PGM options in ODATA and NAK packets. However, -a new packet type has been defined for ACKs, which are generated -according to the rules defined in this document. - - -2.1.1. Data Packets - -Each data packet sent by the data sender contains the following -information: - - - o A SEQUENCE NUMBER. This number is incremented by one for each data - packet transmitted. The field must be sufficiently large that it - does not wrap causing two different packets with the same sequence - number to be in the receiver's recent packet history at the same - time. - - - o A TIMESTAMP (or equivalent information, see Section 2.5) indicating - when the packet with this sequence number has been sent. There is - no requirement for synchronized clocks between the sender and the - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2.1.1. [Page 6] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - - receivers. The timestamp is used to measure network round-trip - times, so needs sufficient resolution for this task. A resolution - of 1ms would be adequate. - - - o The ACKER IDENTITY, i.e. the identity of the receiver in charge of - sending an acknowledgement for this data packet. The ACKER is - elected as a result of the process described in Section 2.3. - A special value is used to indicate that no ACKER is designated for - this packet -- this can happen at the beginning of a session or when - the current ACKER leaves the group. Receivers interpret this value - as a request to elect a new acker. - - -2.1.2. Feedback Packets - -There are two types of feedback packets used by PGMCC: ACK packets and -NAK packets. -ACK packets are generated by the current ACKER, and are used to detect -loss or successful delivery of packets, and to regulate the throughput -accordingly. ACK packets also contain information used to determine the -TCP-equivalent throughput for the ACKER. -NAK packets are sent by any receiver who experiences loss. They contain -information used to determine the TCP-equivalent throughput for that -receiver. In an actual protocol instantiation (such as PGM [7]), NAK -packets might also be used by the protocol to request the retransmission -of specific packets, and indicate the identity of the packet being -requested. - -Both ACK and NAK packets are sent by data receivers, and contain the -following information: - - - o The TIMESTAMP (or equivalent information) derived from the most - recently received data packet according to one of the techniques - described in Section 2.5. - This value is used by the sender to measure the RTT to the receiver - who generated this feedback packet. - - - o ``p'', the receiver's current estimate of the LOSS RATE. The loss - rate is measured by receivers as described in Section 2.6 - -In addition to the above, ACK packets (sent by the acker designated in -the corresponding data packets) must also contain the following -information: - - - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2.1.2. [Page 7] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - - o RX_MAX, the highest sequence number among received data packets - (taking care to deal with sequence number wrapping correctly). - - o ACK_BITMAP, a bitmap indicating the receive status of the latest N - (typically N=32) data packets with sequence numbers RX_MAX-(N-1) to - RX_MAX. - - -This information is used by the sender to record which packets have been -received or lost, and manipulate the transmit window accordingly. Note -that each ACK packet contains information about multiple packets, and -this increases the robustness of the scheme to loss of ACK packets. -This is necessary because ACKs are not sent reliably (unlike TCP's ACKs, -which are cumulative). - - -2.1.3. Field sizes and formats - -The following sizes and formats are suggested for the various fields -used by PGMCC and transmitted over the network: - - - o SEQUENCE NUMBERS - 32 bit, unsigned, network order. - - - o TIMESTAMPS - 32 bit, unsigned, network order. A resolution of 1ms or better is - desirable. - - - o ACKER IDENTITY - Same size and format of a network layer address (e.g. 32 bit for - IPv4). Note though that using an IP address for the Acker Identify - will cause problems with NAT traversal. Transport protocol - designers might examine the SSRC mechanism used by RTP [6] as an - alternative form of node identifier that could be used as Acker - Identity. - - - o LOSS RATE (``p'') - 16-bit unsigned integer, in network format, with 0 indicating no - loss and 2^16-1 indicating 100% loss. - - - o ACK BITMAP - 32-bit, in network format, with least significant bit indicating - receive status of packet RX_MAX. - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2.1.3. [Page 8] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -2.2. Window-based controller - -In a window-based congestion control scheme such as TCP, the -``congestion window'' represents, among other things, the maximum amount -of packets in flight at any time, which in turn controls the throughput -of the session. The sender keeps track of the actual number of packets -in flight, basing on its transmissions and the reception of -acknowledgements. - -The sender may dynamically change the size of the window, according to -the congestion control scheme being used. In TCP, and PGMCC, an -``Additive Increase Multiplicative Decrease'' (AIMD) scheme is used: in -absence of loss, the window is increased by some fixed amount (typically -one packet) per round trip time (RTT), whereas upon loss the window is -reduced to a fraction of its original value (typically halved) in each -RTT in which a loss event is experienced. - -In PGMCC the window is managed using a token-based mechanism, controlled -by two variables: - - o A ``Window Size'', W, which describes the current window size in - packets. - - o A ``Token Count'', T, which indicates the number of packets that can - be transmitted. T is bounded above by W. It is decremented every - time a packet is transmitted, and incremented every time an ACK is - received, according to the rules below. - -Note that these two variables need to hold non-integer data. Typically -a fixed point representation with at least 16 bits for both integer and -fractional parts would be acceptable for implementation purposes. - -The information contained in each ACK is used to determine how many new -packets are acknowledged by that ACK, and whether there are -unacknowledged packets which were not reported in previous ACKs. The -sender also schedules a timeout to react in case no ACKs are received. - -The sender behaves as follows: - - - o INITIALIZATION - At startup, or after a timeout, both W and T are set to 1. - - - o ACK RECEPTION, NO LOSS DETECTED - If the incoming ACK reports new acknowledged packets, and no loss - (as defined in the next paragraph) is detected, then the window is - inflated by one packet per RTT. - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2.2. [Page 9] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - - NOTE: during the slow-start phase, TCP opens the window - exponentially up to the SSTHRESH value, which is computed by TCP - according to the dynamics of the session and updated upon losses. - - We do recommend that PGMCC uses a similar strategy, but using a - fixed, small value for SSTHRESH (e.g. 4 packets). In fact, due to - the dynamicity of the ACKER, which might change on every single - packet, it is hard to compute a reliable estimate of the SSTHRESH - without keeping state for multiple receivers, and the benefits are - small in any event. - - In summary, the reaction to ACK reception on no loss modifies T and - W as follows (here, N is the number of new packets acknowledged by - the incoming ACK): - - if (W < SSTHRESH) then - D = min(N, SSTHRESH - W) // use the first D acks for - exp.opening - N = N - D // and the remaining ones for - linear opening - T = T + 2*D - W = W + D - endif - // do linear window opening with the remaining acks - T = T + N * ( 1 + 1/W ) - W = W + N/W - - - o PACKET TRANSMISSION - One token is consumed for each packet transmitted: - - T = T - 1 - - - o ACK RECEPTION, LOSS DETECTED - If the incoming ACK reports an unacknowledged data packet which is - followed by at least 3 acknowledged data packets, then the packet is - assumed to be lost and PGMCC reacts by halving the window, in the - same way as TCP after 3 duplicate acknowledgements. This is - achieved by modifying T and W as follows: - - T = T - W/2 , W = W/2 - - to simulate the multiplicative decrease. - Additionally, all window manipulation is suspended for the - subsequent RTT. This is achieved by recording the current transmit - sequence number, and canceling any further manipulation of the - window until feedback is received for the next transmitted packet, - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2.2. [Page 10] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - - or until a timeout occurs. - - - - -2.3. Acker Selection - -The ACKER selection process in PGMCC aims at locating the receiver which -would have the lowest throughput if each receiver were using a separate -TCP connection to transfer data. - -Because the steady-state throughput of a TCP connection can be -characterized in a reasonably accurate way in terms of its loss rate and -round trip time [3], the throughput for each receiver can be estimated -by using these two parameters. - -Whenever an ACK or NAK packet from any of the receivers reaches it, the -sender is able to compute the expected throughput T_i for that receiver -by using the equation shown in Section 2.4, with the round trip time RTT -and loss rate p and measured as described in Sections 2.5 and 2.6, -respectively. At any given time, the sender stores the expected -throughput for the current ACKER, T_acker. This value is updated every -time an ACK or NAK from the current ACKER is received (note that, after -a new ACKER is selected, the sender will typically receive ACKs from the -old ACKER for one RTT, and the feedback from different ACKERs might be -interleaved if the paths leading to them have different round trip -times). - -Whenever an ACK or NAK is received from another node i (a previous ACKER -or some other receiver), the expected throughput T_i for that node is -computed, and compared with T_acker. Node i is selected as the new -acker if - - T_i < C * T_acker - -where the constant C between 0 and 1 provides some hysteresis and avoids -too frequent oscillations in the choice of the ACKER. A suggested value -for C is 0.75. - -Note that, from an implementation point of view (see Section 2.4), it is -more convenient to compute T_i ^(-2), so the above equation must be -modified accordingly. - - -2.3.1. Initial Acker election - -Upon reception of a data packet reporting that no acker is currently -selected, receivers generate a dummy NAK report which is used to elect - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2.3.1. [Page 11] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -the initial acker. The NAK is sent with the usual feedback suppression -mechanism dictated by the transport protocol (possibly with shorter time -constants) to avoid feedback implosion, and the sender will select the -source of the first incoming NAK as the new ACKER. - - -2.3.2. Acker dropouts - - -If the ACKER decides to disconnect from the session, it can cause the -session to stop. To avoid this, it is recommended that an ACKER deciding -to leave the session informs the sender by sending an ACK packet (or a -duplicate) carrying an "ACKER_LEAVING" option. The reception of this -packet by the sender will in turn trigger an initial acker election -phase. - - - -2.4. TCP Throughput Equation - -Any realistic equation of TCP throughput as a function of loss event -rate and RTT should be suitable for use in PGMCC. Unlike other schemes -[2] where the throughput equation directly controls the transmit rate, -in PGMCC the equation is used only for acker selection purposes, and the -throughput values are only compared among themselves. As a consequence, -we can use the following equation, derived from the one presented in [3] -by setting RTO = 4 * RTT (as it is common practice): - - M = 1/T = RTT_i * sqrt(p) * (1 + 9*p * (1 + 32*(p)^2)) - - -where - - M = 1/T is proportional to the inverse of the throughput for the - receiver under consideration; - - RTT is the round trip time for the receiver under consideration; - - p is the loss rate for the receiver under consideration, between 0 - and 1.0; - -and multiplying constants are omitted. - -The above equation is accurate on a wide range of loss rates, and also -covers situations where retransmission timeouts have a significant -impact on the throughput of the protocol. - -Note that when p=0, the equation yields 1/T = M = 0. This does not - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2.4. [Page 12] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -constitute a problem as we can still compare the M values computed for -different receivers to determine the acker. Also note that it is easier -to compute M^2 instead of M, because the former does not require the use -of sqrt(). - -In future, different throughput equations may be substituted for this -equation. The requirement is that the throughput equation be a -reasonable approximation of the sending rate of TCP for conformant TCP -congestion control. - -The parameters p and RTT need to be measured or calculated by a PGMCC -implementation. The measurement of RTT is specified in Section 2.5; the -measurement of p is specified in Section 2.6. - -2.5. RTT measurement - -In PGMCC, the RTT is measured by the sender making use of the timestamp -(or equivalent information) echoed back by each receiver in feedback -messages. Three procedures are possible to measure the RTT, as follows. -In no case is it required to have clock synchronization between sender -and receivers. - - -2.5.1. Explicit Timestamp - -This first technique relies on the transmission of a timestamp TS_j with -each data packet j. -The receiver will record the most recently received timestamp, and will -echo it back to the source when generating an ACK or a NAK. If the -feedback is delayed, the time elapsed between the reception of the -timestamp and the generation of the feedback should be added to the -echoed timestamp. -The sender computes the RTT by subtracting the received timestamp from -the current value of the clock. - -The resolution of the timestamp value should be good enough for -reasonable precision measurement of typical network round trip times. If -receivers need to apply correction for delayed feedback, it is necessary -that receivers know the resolution of the timestamp clock. A suggested -value is 1ms. - - -2.5.2. Implicit timestamp - -With this technique, the sender will record a timestamp TS_j for each -transmitted data packet j, but the timestamp will not be transmitted -with the packet itself. -The receiver will record the most recently received sequence number, and - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2.5.2. [Page 13] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -will echo it back to the source when generating an ACK or a NAK. -The sender computes the RTT by looking up the timestamp associated with -the sequence number received in the feedback packet, and subtracting it -from the current clock value. - -If the feedback from the receiver is delayed, as it is commonly the case -for NAKs, the receiver can compute, and send back to the source, a -correction term corresponding to the time elapsed between the reception -of the timestamp and the generation of the feedback. The correction term -will then be subtracted by the sender in order to obtain the correct -estimate of the RTT. - -This RTT measurement technique is equivalent to the previous one, but it -saves some space in data packets as the timestamp does not need to be -sent explicitly. Feedback packets might become larger if the correction -value is transmitted explicitly; but in many cases, the sequence number -will already be present for other reasons (e.g. ACK packets), and -wherever space is a concern the sequence number and the correction term -can be packed in a single 32-bit word without loss of precision. - - -2.5.3. Sequence numbers - -This technique is the least precise, but it does not rely on the -presence of a high resolution clock on the nodes. -The sender will not compute any timestamp, and just send data packets -with their sequence number j. -The receiver will record the most recently received sequence number, and -will echo it back to the source when generating an ACK or a NAK. -The sender computes the RTT as the difference between the most recently -sent sequence number and the sequence number received from the ACK or -NAK packet. - -Note that in this case the RTT is not measured in seconds, but in -"sequence numbers", which are monotonically, but not uniformly, -increasing with time. The two measurements are equivalent if the sender -transmits at a constant rate. When the data rate changes over time (as -it is normally happens, given that PGMCC controls the actual data rate), -then the "measured" RTT values grow with the actual transmit rate. This -can influence the correctness of the results when comparing two -measurement done over different and only partially overlapping time (and -sequence number) intervals where the transmit rate incurs a significant -change. - - - - - - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2.5.3. [Page 14] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -2.5.4. Recommendations - -Whenever possible, the measurement of the RTT should be carried out -using either explicit or implicit timestamps, and by keeping track of -the "correction term" (the delay between data reception and feedback -generation). - -If the receiver does not have a clock with a suitable resolution, the -correction term might not be present (or be inaccurate). In this case -the timestamps received by the sender on NAK packets might be in error, -in the worst case, by as much as the packet interarrival time. This -error will normally not be present on ACK packets, which are sent -immediately. A suitable correction should be applied by the sender in -order to avoid systematic errors. - -The measurement based on sequence numbers is less accurate, but also -less sensitive to errors due to the lack of the correction term. In -fact, the measurement error induced by the lack of the correction term -can be at most one unit. This suggests that, when the correction term -is not available, measurements based on sequence numbers should be -favoured. Simulations have shown that the acker selection mechanism -performs moderately better when the RTT measurement is based on -timestamps, but performance is reasonably good also with measurements -based on sequence numbers. - - - -2.6. Loss rate measurement - - -The loss measurement in PGMCC is entirely performed by receivers. The -measurement results do not directly influence the transmit rate, but are -only used for comparison purposes. As a consequence, the scheme is -reasonably robust to different measurement techniques, as long as they -are not influenced too strongly by single loss events. - -The main method suggested for loss measurement is Exponentially Weighted -Moving Average (EWMA), which is formally equivalent to a single-pole -digital low pass filter applied to a binary signal x_i, where x_i = 1 if -packet i is lost, x_i = 0 if packet i is successfully received. - -The loss rate p_i upon reception or detection of loss of packet i is -computed as - - - p_i = c_p * p_{i-1} + (1 - c_p ) * p_i - where the constant c_p between 0 and 1 is related to the bandpass of -the filter. Experiments have shown good performance with c = 500/65536, - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2.6. [Page 15] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -and computations performed with fixed point arithmetic and 16 fractional -digits. - -As an alternative to EWMA, the technique used in TFRC [2] can be -adopted. Simulations have shown a moderate improvement in the acker -selection mechanism by measuring loss using the TFRC loss estimator, -which is however slightly more expensive to compute than the EWMA loss -estimator in presence of packet reordering. - - -2.7. Timeouts - - -When a packet is transmitted, the sender schedules a timeout to prevent -stalls upon loss of ACKs or disconnection of the ACKER. In TCP, which -has a similar problem, the timeout value is computed by accumulating -statistics (SRTT and RTTVAR) on RTT samples, starting from a default -initial value (3s) when no RTT samples are available. - -PGMCC can use a similar scheme to compute the timeouts, remembering that -upon ACKER changes (which may be very frequent), the computation of SRTT -and RTTVAR must be restarted from the beginning, unless the sender -decides to keep state for at least a small number of recent ackers. - -Because the ACKER can leave the group without notifying the sender, -after a number of successive timeouts the sender MUST force the election -of a new ACKER. We recommend this new election to be performed after -two successive timeouts. - - -2.8. Interaction with feedback suppression schemes - - -Several schemes are used by NAK-based multicast protocols to reduce the -amount of feedback directed toward the source and make the protocol -scale with large populations of receivers. Such schemes typically rely -on randomly delaying NAK generation, and suppressing pending NAKs when -an equivalent NAK or a retransmission is heard; or, intermediate nodes -such as routers can implement some form of feedback aggregation and -filtering. - -Such schemes might prevent NAKs from potential ACKER candidates from -reaching the source. This filtering might impact the speed at which -PGMCC selects the correct ACKER, though initial experience from -simulations seem to suggest that PGMCC behavior is not severely affected -by NAK suppression schemes. - - - - - -Rizzo/Iannaccone/Vicisano/Handley Section 2.8. [Page 16] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -2.9. Interaction with ECN - - -PGMCC can use ECN notifications in much the same way as actual losses, -and use such notifications to control the throughput of the session. - -At the receiver, ECN-marked data packets can be considered as lost -packets for the purpose of loss rate computation and ACK/NAK generation. -If the ACKER sends an ACK for ECN-marked packets, that ACK MUST report -that the packet being acknowledged that was ECN marked. Similarly the -ACKER must indicate in the ACK packet's received packets bitmap that the -packet was ECN-marked, or that the packet was lost. - -We note that to support use of the ECN nonce, the ACK packet's received -packets bitmap would require two bits per packet being reported. - - -3. Procedures - Sender - -The following pseudo-code specifies the complete behavior of the sender -in PGMCC. - - -initialization: - T = 1 ; W = 1 ; /* initialize window and number of tokens */ - RETRY = 0 ; /* number of consecutive timeouts so far */ - < initialize p, RTT for acker to default values > - ACKER = NO_ACKER; /* no acker is known */ - < initialize sequence numbers > - QUEUED = 0; /* packets waiting to be transmitted */ - -on transmission request: - send_packet() ; - -on timeout expiration : - T = 1 ; W = 1 ; /* initialize window and number of tokens */ - if (RETRY < RETRY_MAX) - RETRY = RETRY + 1 - else - ACKER = NO_ACKER ; /* old acker is not valid anymore */ - send_packet() ; - - - - - - - - - - -Rizzo/Iannaccone/Vicisano/Handley Section 3. [Page 17] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -on ACK/NAK reception from receiver I : - < compute p and RTT for source of this ACK, see Sec. 2.5 and 2.6 > - RETRY = 0 ; - if (ACKER == NO_ACKER) { /* select current as acker is no other known */ - ACKER = I ; - T = T + 1 ; - } - if (ACKER != I) - < select acker according to Sec. 2.3 > ; - else { - - if (packet_type == ACK) { - < update_window according to Sec.2.2 > - send_packet ; - if (ack_pending) - update_timeout ; - } -} - -send_packet() { - if (QUEUED > 0 && T >= 1) { - < transmit one packet > - T = T - 1 ; - QUEUED = QUEUED - 1 ; - } - if ( ) - -} - - - -4. Procedures -- Receiver - -The following pseudo-code specifies the complete behavior of the -receiver in PGMCC. - -A receiver only transmits an ACK packet when it receives a data packet -for which the receiver is designated as the ACKER by the data packet -itself. A receiver can transmit a NAK packet after it has detected that -a data packet is missing and a suitable delay has passed, as dictated by -the feedback suppression rules of the protocol in use. - -The data packet contains acknowledgement status about the most recent 32 -sequence numbers known to the receiver. - - - - - - - -Rizzo/Iannaccone/Vicisano/Handley Section 4. [Page 18] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -on initialization/session setup: - < initialize state variables and ACK bitmap > - -on DATA packet reception: - < update p measurement according to Sec.2.6 > - < record timestamp and packet reception time > - if (ACKER == this_node) { - < send an immediate ACK > - } - if ( ) - < schedule a timeout for NAK transmission > - -on NAK reception: - < suppress any pending NAK transmission for the sequence - number indicated in the NAK > - -on timeout: - if ( < there are missing and unacknowledged packets > ) { - < send a NAK for one or more of the missing packets > - < mark such packets as acknowledged > - if ( ) - < schedule a timeout for NAK transmission > - } - - -5. Security Considerations - -PGMCC is not a transport protocol in its own right, but a congestion -control mechanism that is intended to be used in conjunction with a -transport protocol. Therefore security primarily needs to be considered -in the context of a specific transport protocol and its authentication -mechanisms. - -Congestion control mechanisms can potentially be exploited to create -denial of service. This may occur through spoofed feedback. Thus any -transport protocol that uses PGMCC should take care to ensure that -feedback is only accepted from the receiver of the data. The precise -mechanism to achieve this will however depend on the transport protocol -itself. - -In addition, congestion control mechanisms may potentially be -manipulated by a greedy receiver that wishes to receive more than its -fair share of network bandwidth. A receiver might do this by first -reporting inflated loss and RTT samples, in order to get selected as the -ACKER, and then generating ACK at the desired rate (including possibly -claiming to have received packets that in fact were lost due to -congestion). Possible defenses against such a receiver could be based -on the sender verifying the correctness of the loss and RTT samples - - - -Rizzo/Iannaccone/Vicisano/Handley Section 5. [Page 19] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -supplied by the receiver. A PGMCC sender SHOULD compare the receiver -reports on loss rate and RTT with the information derived directly from -the incoming stream of ACKs. In case of discrepancy of the reports, a -PGMCC sender SHOULD mark the current acker as ineligible and initiate a -new acker election. The decision on how large that discrepancy should be -before initiating a new acker election is left to the implementation. - -Also, the sender MAY include some form of nonce that the receiver must -feed back to the sender to prove receipt. However, the details of such a -nonce would depend on the transport protocol, and in particular on -whether the transport protocol is reliable or unreliable. - - -6. Authors' Addresses - - Luigi Rizzo - luigi@iet.unipi.it - Dip. Ing. dell'Informazione, - Univ. di Pisa - via Diotisalvi 2, 56122 Pisa, Italy - - Gianluca Iannaccone - gianluca.iannaccone@intel.com - Intel Research - 15 JJ Thomson Avenue, Cambridge CB3 0FD, UK - - Lorenzo Vicisano - lorenzo@cisco.com - cisco Systems, Inc. - 170 West Tasman Dr., - San Jose, CA, USA, 95134 - - Mark Handley - m.handley@cs.ucl.ac.uk - University College London, - Gower Street, London WC1E 6BT, UK - - -7. Acknowledgments - -We would like to acknowledge feedback and discussions on equation-based -congestion control with a wide range of people, including members of the -Reliable Multicast Research Group, the Reliable Multicast Transport -Working Group, and the End-to-End Research Group. - - - - - - - -Rizzo/Iannaccone/Vicisano/Handley Section 7. [Page 20] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -[1] Bradner, S., Key words for use in RFCs to Indicate Requirement -Levels (IETF RFC 2119) http://www.rfc-editor.org/rfc/rfc2119.txt - -[2] Floyd, S., Handley, M., Padhye, J., Widmer, J., "Equation-Based -Congestion Control for Unicast Applications", ACM SIGCOMM 2000, -Stockholm, Aug. 2000 - -[3] Padhye, J. and Firoiu, V. and Towsley, D. and Kurose, J., "Modeling -TCP Throughput: A Simple Model and its Empirical Validation", Proc ACM -SIGCOMM 1998. - -[4] Mankin, A., Romanow, A., Brander, S., Paxson, V., "IETF Criteria for -Evaluating Reliable Multicast Transport and Application Protocols," -RFC2357, June 1998. - -[5] Rizzo, L., "pgmcc: a TCP-friendly single-rate multicast congestion -control scheme", ACM SIGCOMM 2000, Stockholm, Aug.2000 - -[6] Schulzrinne, H., Casner, S., Frederick, R., Jacobson, V., "RTP: A -Transport Protocol for Real-Time Applications", RFC 1889, Jan 1996. - -[7] Speakman, T., Crowcroft, J., Gemmell, J., Farinacci, D. , Lin, S., -Leshchiner, D., Luby, M., Montgomery, T. , Rizzo, L., Tweedly, A., -Bhaskar, N., Edmonstone, R., Sumanasekera, R., Vicisano, L., PGM -Reliable Transport Protocol Specification, RFC 3208, December 2001. -rfc3208.txt also available at ftp://ftp.rfc-editor.org/in- -notes/rfc3208.txt - - - - -8. Full Copyright Statement - -Copyright (C) The Internet Society (2000). All Rights Reserved. - -This document and translations of it may be copied and furnished to -others, and derivative works that comment on or otherwise explain it or -assist in its implementation may be prepared, copied, published and -distributed, in whole or in part, without restriction of any kind, -provided that the above copyright notice and this paragraph are included -on all such copies and derivative works. However, this document itself -may not be modified in any way, such as by removing the copyright notice -or references to the Internet Society or other Internet organizations, -except as needed for the purpose of developing Internet standards in -which case the procedures for copyrights defined in the Internet -languages other than English. - - - - - -Rizzo/Iannaccone/Vicisano/Handley Section 8. [Page 21] - -INTERNET-DRAFT Expires: January 2005 July 2004 - - -The limited permissions granted above are perpetual and will not be -revoked by the Internet Society or its successors or assigns. - -This document and the information contained herein is provided on an "AS -IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK -FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT -INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR -FITNESS FOR A PARTICULAR PURPOSE." - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Rizzo/Iannaccone/Vicisano/Handley Section 8. [Page 22] diff --git a/3rdparty/openpgm-svn-r1085/doc/rfc3208.txt b/3rdparty/openpgm-svn-r1085/doc/rfc3208.txt deleted file mode 100644 index fb82c26..0000000 --- a/3rdparty/openpgm-svn-r1085/doc/rfc3208.txt +++ /dev/null @@ -1,6219 +0,0 @@ - - - - - - -Network Working Group T. Speakman -Request for Comments: 3208 Cisco Systems -Category: Experimental J. Crowcroft - UCL - J. Gemmell - Microsoft - D. Farinacci - Procket Networks - S. Lin - Juniper Networks - D. Leshchiner - TIBCO Software - M. Luby - Digital Fountain - T. Montgomery - Talarian Corporation - L. Rizzo - University of Pisa - A. Tweedly - N. Bhaskar - R. Edmonstone - R. Sumanasekera - L. Vicisano - Cisco Systems - December 2001 - - - PGM Reliable Transport Protocol Specification - -Status of this Memo - - This memo defines an Experimental Protocol for the Internet - community. It does not specify an Internet standard of any kind. - Discussion and suggestions for improvement are requested. - Distribution of this memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2001). All Rights Reserved. - -Abstract - - Pragmatic General Multicast (PGM) is a reliable multicast transport - protocol for applications that require ordered or unordered, - duplicate-free, multicast data delivery from multiple sources to - multiple receivers. PGM guarantees that a receiver in the group - either receives all data packets from transmissions and repairs, or - is able to detect unrecoverable data packet loss. PGM is - - - -Speakman, et. al. Experimental [Page 1] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - specifically intended as a workable solution for multicast - applications with basic reliability requirements. Its central design - goal is simplicity of operation with due regard for scalability and - network efficiency. - -Table of Contents - - 1. Introduction and Overview .................................. 3 - 2. Architectural Description .................................. 9 - 3. Terms and Concepts ......................................... 12 - 4. Procedures - General ....................................... 18 - 5. Procedures - Sources ....................................... 19 - 6. Procedures - Receivers ..................................... 22 - 7. Procedures - Network Elements .............................. 27 - 8. Packet Formats ............................................. 31 - 9. Options .................................................... 40 - 10. Security Considerations .................................... 56 - 11. Appendix A - Forward Error Correction ...................... 58 - 12. Appendix B - Support for Congestion Control ................ 72 - 13. Appendix C - SPM Requests .................................. 79 - 14. Appendix D - Poll Mechanism ................................ 82 - 15. Appendix E - Implosion Prevention .......................... 92 - 16. Appendix F - Transmit Window Example ....................... 98 - 17 Appendix G - Applicability Statement ....................... 103 - 18. Abbreviations .............................................. 105 - 19. Acknowledgments ............................................ 106 - 20. References ................................................. 106 - 21. Authors' Addresses.......................................... 108 - 22. Full Copyright Statement ................................... 111 - -Nota Bene: - - The publication of this specification is intended to freeze the - definition of PGM in the interest of fostering both ongoing and - prospective experimentation with the protocol. The intent of that - experimentation is to provide experience with the implementation and - deployment of a reliable multicast protocol of this class so as to be - able to feed that experience back into the longer-term - standardization process underway in the Reliable Multicast Transport - Working Group of the IETF. Appendix G provides more specific detail - on the scope and status of some of this experimentation. Reports of - experiments include [16-23]. Additional results and new - experimentation are encouraged. - - - - - - - - -Speakman, et. al. Experimental [Page 2] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -1. Introduction and Overview - - A variety of reliable protocols have been proposed for multicast data - delivery, each with an emphasis on particular types of applications, - network characteristics, or definitions of reliability ([1], [2], - [3], [4]). In this tradition, Pragmatic General Multicast (PGM) is a - reliable transport protocol for applications that require ordered or - unordered, duplicate-free, multicast data delivery from multiple - sources to multiple receivers. - - PGM is specifically intended as a workable solution for multicast - applications with basic reliability requirements rather than as a - comprehensive solution for multicast applications with sophisticated - ordering, agreement, and robustness requirements. Its central design - goal is simplicity of operation with due regard for scalability and - network efficiency. - - PGM has no notion of group membership. It simply provides reliable - multicast data delivery within a transmit window advanced by a source - according to a purely local strategy. Reliable delivery is provided - within a source's transmit window from the time a receiver joins the - group until it departs. PGM guarantees that a receiver in the group - either receives all data packets from transmissions and repairs, or - is able to detect unrecoverable data packet loss. PGM supports any - number of sources within a multicast group, each fully identified by - a globally unique Transport Session Identifier (TSI), but since these - sources/sessions operate entirely independently of each other, this - specification is phrased in terms of a single source and extends - without modification to multiple sources. - - More specifically, PGM is not intended for use with applications that - depend either upon acknowledged delivery to a known group of - recipients, or upon total ordering amongst multiple sources. - - Rather, PGM is best suited to those applications in which members may - join and leave at any time, and that are either insensitive to - unrecoverable data packet loss or are prepared to resort to - application recovery in the event. Through its optional extensions, - PGM provides specific mechanisms to support applications as disparate - as stock and news updates, data conferencing, low-delay real-time - video transfer, and bulk data transfer. - - In the following text, transport-layer originators of PGM data - packets are referred to as sources, transport-layer consumers of PGM - data packets are referred to as receivers, and network-layer entities - in the intervening network are referred to as network elements. - - - - - -Speakman, et. al. Experimental [Page 3] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Unless otherwise specified, the term "repair" will be used to - indicate both the actual retransmission of a copy of a missing packet - or the transmission of an FEC repair packet. - -Terminology - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in RFC 2119 [14] and - indicate requirement levels for compliant PGM implementations. - -1.1. Summary of Operation - - PGM runs over a datagram multicast protocol such as IP multicast [5]. - In the normal course of data transfer, a source multicasts sequenced - data packets (ODATA), and receivers unicast selective negative - acknowledgments (NAKs) for data packets detected to be missing from - the expected sequence. Network elements forward NAKs PGM-hop-by- - PGM-hop to the source, and confirm each hop by multicasting a NAK - confirmation (NCF) in response on the interface on which the NAK was - received. Repairs (RDATA) may be provided either by the source - itself or by a Designated Local Repairer (DLR) in response to a NAK. - - Since NAKs provide the sole mechanism for reliability, PGM is - particularly sensitive to their loss. To minimize NAK loss, PGM - defines a network-layer hop-by-hop procedure for reliable NAK - forwarding. - - Upon detection of a missing data packet, a receiver repeatedly - unicasts a NAK to the last-hop PGM network element on the - distribution tree from the source. A receiver repeats this NAK until - it receives a NAK confirmation (NCF) multicast to the group from that - PGM network element. That network element responds with an NCF to - the first occurrence of the NAK and any further retransmissions of - that same NAK from any receiver. In turn, the network element - repeatedly forwards the NAK to the upstream PGM network element on - the reverse of the distribution path from the source of the original - data packet until it also receives an NCF from that network element. - Finally, the source itself receives and confirms the NAK by - multicasting an NCF to the group. - - While NCFs are multicast to the group, they are not propagated by PGM - network elements since they act as hop-by-hop confirmations. - - - - - - - - -Speakman, et. al. Experimental [Page 4] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - To avoid NAK implosion, PGM specifies procedures for subnet-based NAK - suppression amongst receivers and NAK elimination within network - elements. The usual result is the propagation of just one copy of a - given NAK along the reverse of the distribution path from any network - with directly connected receivers to a source. - - The net effect is that unicast NAKs return from a receiver to a - source on the reverse of the path on which ODATA was forwarded, that - is, on the reverse of the distribution tree from the source. More - specifically, they return through exactly the same sequence of PGM - network elements through which ODATA was forwarded, but in reverse. - The reasons for handling NAKs this way will become clear in the - discussion of constraining repairs, but first it's necessary to - describe the mechanisms for establishing the requisite source path - state in PGM network elements. - - To establish source path state in PGM network elements, the basic - data transfer operation is augmented by Source Path Messages (SPMs) - from a source, periodically interleaved with ODATA. SPMs function - primarily to establish source path state for a given TSI in all PGM - network elements on the distribution tree from the source. PGM - network elements use this information to address returning unicast - NAKs directly to the upstream PGM network element toward the source, - and thereby insure that NAKs return from a receiver to a source on - the reverse of the distribution path for the TSI. - - SPMs are sent by a source at a rate that serves to maintain up-to- - date PGM neighbor information. In addition, SPMs complement the role - of DATA packets in provoking further NAKs from receivers, and - maintaining receive window state in the receivers. - - As a further efficiency, PGM specifies procedures for the constraint - of repairs by network elements so that they reach only those network - segments containing group members that did not receive the original - transmission. As NAKs traverse the reverse of the ODATA path - (upward), they establish repair state in the network elements which - is used in turn to constrain the (downward) forwarding of the - corresponding RDATA. - - Besides procedures for the source to provide repairs, PGM also - specifies options and procedures that permit designated local - repairers (DLRs) to announce their availability and to redirect - repair requests (NAKs) to themselves rather than to the original - source. In addition to these conventional procedures for loss - recovery through selective ARQ, Appendix A specifies Forward Error - Correction (FEC) procedures for sources to provide and receivers to - request general error correcting parity packets rather than selective - retransmissions. - - - -Speakman, et. al. Experimental [Page 5] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Finally, since PGM operates without regular return traffic from - receivers, conventional feedback mechanisms for transport flow and - congestion control cannot be applied. Appendix B specifies a TCP- - friendly, NE-based solution for PGM congestion control, and cites a - reference to a TCP-friendly, end-to-end solution for PGM congestion - control. - - In its basic operation, PGM relies on a purely rate-limited - transmission strategy in the source to bound the bandwidth consumed - by PGM transport sessions and to define the transmit window - maintained by the source. - - PGM defines four basic packet types: three that flow downstream - (SPMs, DATA, NCFs), and one that flows upstream (NAKs). - -1.2. Design Goals and Constraints - - PGM has been designed to serve that broad range of multicast - applications that have relatively simple reliability requirements, - and to do so in a way that realizes the much advertised but often - unrealized network efficiencies of multicast data transfer. The - usual impediments to realizing these efficiencies are the implosion - of negative and positive acknowledgments from receivers to sources, - repair latency from the source, and the propagation of repairs to - disinterested receivers. - -1.2.1. Reliability. - - Reliable data delivery across an unreliable network is conventionally - achieved through an end-to-end protocol in which a source (implicitly - or explicitly) solicits receipt confirmation from a receiver, and the - receiver responds positively or negatively. While the frequency of - negative acknowledgments is a function of the reliability of the - network and the receiver's resources (and so, potentially quite low), - the frequency of positive acknowledgments is fixed at at least the - rate at which the transmit window is advanced, and usually more - often. - - Negative acknowledgments primarily determine repairs and reliability. - Positive acknowledgments primarily determine transmit buffer - management. - - When these principles are extended without modification to multicast - protocols, the result, at least for positive acknowledgments, is a - burden of positive acknowledgments transmitted to the source that - quickly threatens to overwhelm it as the number of receivers grows. - More succinctly, ACK implosion keeps ACK-based reliable multicast - protocols from scaling well. - - - -Speakman, et. al. Experimental [Page 6] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - One of the goals of PGM is to get as strong a definition of - reliability as possible from as simple a protocol as possible. ACK - implosion can be addressed in a variety of effective but complicated - ways, most of which require re-transmit capability from other than - the original source. - - An alternative is to dispense with positive acknowledgments - altogether, and to resort to other strategies for buffer management - while retaining negative acknowledgments for repairs and reliability. - The approach taken in PGM is to retain negative acknowledgments, but - to dispense with positive acknowledgments and resort instead to - timeouts at the source to manage transmit resources. - - The definition of reliability with PGM is a direct consequence of - this design decision. PGM guarantees that a receiver either receives - all data packets from transmissions and repairs, or is able to detect - unrecoverable data packet loss. - - PGM includes strategies for repeatedly provoking NAKs from receivers, - and for adding reliability to the NAKs themselves. By reinforcing - the NAK mechanism, PGM minimizes the probability that a receiver will - detect a missing data packet so late that the packet is unavailable - for repair either from the source or from a designated local repairer - (DLR). Without ACKs and knowledge of group membership, however, PGM - cannot eliminate this possibility. - -1.2.2. Group Membership - - A second consequence of eliminating ACKs is that knowledge of group - membership is neither required nor provided by the protocol. - Although a source may receive some PGM packets (NAKs for instance) - from some receivers, the identity of the receivers does not figure in - the processing of those packets. Group membership MAY change during - the course of a PGM transport session without the knowledge of or - consequence to the source or the remaining receivers. - -1.2.3. Efficiency - - While PGM avoids the implosion of positive acknowledgments simply by - dispensing with ACKs, the implosion of negative acknowledgments is - addressed directly. - - Receivers observe a random back-off prior to generating a NAK during - which interval the NAK is suppressed (i.e. it is not sent, but the - receiver acts as if it had sent it) by the receiver upon receipt of a - matching NCF. In addition, PGM network elements eliminate duplicate - NAKs received on different interfaces on the same network element. - - - - -Speakman, et. al. Experimental [Page 7] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - The combination of these two strategies usually results in the source - receiving just a single NAK for any given lost data packet. - - Whether a repair is provided from a DLR or the original source, it is - important to constrain that repair to only those network segments - containing members that negatively acknowledged the original - transmission rather than propagating it throughout the group. PGM - specifies procedures for network elements to use the pattern of NAKs - to define a sub-tree within the group upon which to forward the - corresponding repair so that it reaches only those receivers that - missed it in the first place. - -1.2.4. Simplicity - - PGM is designed to achieve the greatest improvement in reliability - (as compared to the usual UDP) with the least complexity. As a - result, PGM does NOT address conference control, global ordering - amongst multiple sources in the group, nor recovery from network - partitions. - -1.2.5. Operability - - PGM is designed to function, albeit with less efficiency, even when - some or all of the network elements in the multicast tree have no - knowledge of PGM. To that end, all PGM data packets can be - conventionally multicast routed by non-PGM network elements with no - loss of functionality, but with some inefficiency in the propagation - of RDATA and NCFs. - - In addition, since NAKs are unicast to the last-hop PGM network - element and NCFs are multicast to the group, NAK/NCF operation is - also consistent across non-PGM network elements. Note that for NAK - suppression to be most effective, receivers should always have a PGM - network element as a first hop network element between themselves and - every path to every PGM source. If receivers are several hops - removed from the first PGM network element, the efficacy of NAK - suppression may degrade. - -1.3. Options - - In addition to the basic data transfer operation described above, PGM - specifies several end-to-end options to address specific application - requirements. PGM specifies options to support fragmentation, late - joining, redirection, Forward Error Correction (FEC), reachability, - and session synchronization/termination/reset. Options MAY be - appended to PGM data packet headers only by their original - transmitters. While they MAY be interpreted by network elements, - options are neither added nor removed by network elements. - - - -Speakman, et. al. Experimental [Page 8] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - All options are receiver-significant (i.e., they must be interpreted - by receivers). Some options are also network-significant (i.e., they - must be interpreted by network elements). - - Fragmentation MAY be used in conjunction with data packets to allow a - transport-layer entity at the source to break up application-layer - data packets into multiple PGM data packets to conform with the - maximum transmission unit (MTU) supported by the network layer. - - Late joining allows a source to indicate whether or not receivers may - request all available repairs when they initially join a particular - transport session. - - Redirection MAY be used in conjunction with Poll Responses to allow a - DLR to respond to normal NCFs or POLLs with a redirecting POLR - advertising its own address as an alternative re-transmitter to the - original source. - - FEC techniques MAY be applied by receivers to use source-provided - parity packets rather than selective retransmissions to effect loss - recovery. - -2. Architectural Description - - As an end-to-end transport protocol, PGM specifies packet formats and - procedures for sources to transmit and for receivers to receive data. - To enhance the efficiency of this data transfer, PGM also specifies - packet formats and procedures for network elements to improve the - reliability of NAKs and to constrain the propagation of repairs. The - division of these functions is described in this section and expanded - in detail in the next section. - -2.1. Source Functions - - Data Transmission - - Sources multicast ODATA packets to the group within the - transmit window at a given transmit rate. - - Source Path State - - Sources multicast SPMs to the group, interleaved with ODATA if - present, to establish source path state in PGM network - elements. - - - - - - - -Speakman, et. al. Experimental [Page 9] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - NAK Reliability - - Sources multicast NCFs to the group in response to any NAKs - they receive. - - Repairs - - Sources multicast RDATA packets to the group in response to - NAKs received for data packets within the transmit window. - - Transmit Window Advance - - Sources MAY advance the trailing edge of the window according - to one of a number of strategies. Implementations MAY support - automatic adjustments such as keeping the window at a fixed - size in bytes, a fixed number of packets or a fixed real time - duration. In addition, they MAY optionally delay window - advancement based on NAK-silence for a certain period. Some - possible strategies are outlined later in this document. - -2.2. Receiver Functions - - Source Path State - - Receivers use SPMs to determine the last-hop PGM network - element for a given TSI to which to direct their NAKs. - - Data Reception - - Receivers receive ODATA within the transmit window and - eliminate any duplicates. - - Repair Requests - - Receivers unicast NAKs to the last-hop PGM network element (and - MAY optionally multicast a NAK with TTL of 1 to the local - group) for data packets within the receive window detected to - be missing from the expected sequence. A receiver MUST - repeatedly transmit a given NAK until it receives a matching - NCF. - - NAK Suppression - - Receivers suppress NAKs for which a matching NCF or NAK is - received during the NAK transmit back-off interval. - - - - - - -Speakman, et. al. Experimental [Page 10] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Receive Window Advance - - Receivers immediately advance their receive windows upon - receipt of any PGM data packet or SPM within the transmit - window that advances the receive window. - -2.3. Network Element Functions - - Network elements forward ODATA without intervention. - - Source Path State - - Network elements intercept SPMs and use them to establish - source path state for the corresponding TSI before multicast - forwarding them in the usual way. - - NAK Reliability - - Network elements multicast NCFs to the group in response to any - NAK they receive. For each NAK received, network elements - create repair state recording the transport session identifier, - the sequence number of the NAK, and the input interface on - which the NAK was received. - - Constrained NAK Forwarding - - Network elements repeatedly unicast forward only the first copy - of any NAK they receive to the upstream PGM network element on - the distribution path for the TSI until they receive an NCF in - response. In addition, they MAY optionally multicast this NAK - upstream with TTL of 1. - - Nota Bene: Once confirmed by an NCF, network elements discard NAK - packets; NAKs are NOT retained in network elements beyond this - forwarding operation, but state about the reception of them is - stored. - - NAK Elimination - - Network elements discard exact duplicates of any NAK for which - they already have repair state (i.e., that has been forwarded - either by themselves or a neighboring PGM network element), and - respond with a matching NCF. - - - - - - - - -Speakman, et. al. Experimental [Page 11] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Constrained RDATA Forwarding - - Network elements use NAKs to maintain repair state consisting - of a list of interfaces upon which a given NAK was received, - and they forward the corresponding RDATA only on these - interfaces. - - NAK Anticipation - - If a network element hears an upstream NCF (i.e., on the - upstream interface for the distribution tree for the TSI), it - establishes repair state without outgoing interfaces in - anticipation of responding to and eliminating duplicates of the - NAK that may arrive from downstream. - -3. Terms and Concepts - - Before proceeding from the preceding overview to the detail in the - subsequent Procedures, this section presents some concepts and - definitions that make that detail more intelligible. - -3.1. Transport Session Identifiers - - Every PGM packet is identified by a: - - TSI transport session identifier - - TSIs MUST be globally unique, and only one source at a time may act - as the source for a transport session. (Note that repairers do not - change the TSI in any RDATA they transmit). TSIs are composed of the - concatenation of a globally unique source identifier (GSI) and a - source-assigned data-source port. - - Since all PGM packets originated by receivers are in response to PGM - packets originated by a source, receivers simply echo the TSI heard - from the source in any corresponding packets they originate. - - Since all PGM packets originated by network elements are in response - to PGM packets originated by a receiver, network elements simply echo - the TSI heard from the receiver in any corresponding packets they - originate. - -3.2. Sequence Numbers - - PGM uses a circular sequence number space from 0 through ((2**32) - - 1) to identify and order ODATA packets. Sources MUST number ODATA - packets in unit increments in the order in which the corresponding - application data is submitted for transmission. Within a transmit or - - - -Speakman, et. al. Experimental [Page 12] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - receive window (defined below), a sequence number x is "less" or - "older" than sequence number y if it numbers an ODATA packet - preceding ODATA packet y, and a sequence number y is "greater" or - "more recent" than sequence number x if it numbers an ODATA packet - subsequent to ODATA packet x. - -3.3. Transmit Window - - The description of the operation of PGM rests fundamentally on the - definition of the source-maintained transmit window. This definition - in turn is derived directly from the amount of transmitted data (in - seconds) a source retains for repair (TXW_SECS), and the maximum - transmit rate (in bytes/second) maintained by a source to regulate - its bandwidth utilization (TXW_MAX_RTE). - - In terms of sequence numbers, the transmit window is the range of - sequence numbers consumed by the source for sequentially numbering - and transmitting the most recent TXW_SECS of ODATA packets. The - trailing (or left) edge of the transmit window (TXW_TRAIL) is defined - as the sequence number of the oldest data packet available for repair - from a source. The leading (or right) edge of the transmit window - (TXW_LEAD) is defined as the sequence number of the most recent data - packet a source has transmitted. - - The size of the transmit window in sequence numbers (TXW_SQNS) (i.e., - the difference between the leading and trailing edges plus one) MUST - be no greater than half the PGM sequence number space less one. - - When TXW_TRAIL is equal to TXW_LEAD, the transmit window size is one. - When TXW_TRAIL is equal to TXW_LEAD plus one, the transmit window - size is empty. - -3.4. Receive Window - - The receive window at the receivers is determined entirely by PGM - packets from the source. That is, a receiver simply obeys what the - source tells it in terms of window state and advancement. - - For a given transport session identified by a TSI, a receiver - maintains: - - RXW_TRAIL the sequence number defining the trailing edge of the - receive window, the sequence number (known from data - packets and SPMs) of the oldest data packet available - for repair from the source - - - - - - -Speakman, et. al. Experimental [Page 13] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - RXW_LEAD the sequence number defining the leading edge of the - receive window, the greatest sequence number of any - received data packet within the transmit window - - The receive window is the range of sequence numbers a receiver is - expected to use to identify receivable ODATA. - - A data packet is described as being "in" the receive window if its - sequence number is in the receive window. - - The receive window is advanced by the receiver when it receives an - SPM or ODATA packet within the transmit window that increments - RXW_TRAIL. Receivers also advance their receive windows upon receipt - of any PGM data packet within the receive window that advances the - receive window. - -3.5. Source Path State - - To establish the repair state required to constrain RDATA, it's - essential that NAKs return from a receiver to a source on the reverse - of the distribution tree from the source. That is, they must return - through the same sequence of PGM network elements through which the - ODATA was forwarded, but in reverse. There are two reasons for this, - the less obvious one being by far the more important. - - The first and obvious reason is that RDATA is forwarded on the same - path as ODATA and so repair state must be established on this path if - it is to constrain the propagation of RDATA. - - The second and less obvious reason is that in the absence of repair - state, PGM network elements do NOT forward RDATA, so the default - behavior is to discard repairs. If repair state is not properly - established for interfaces on which ODATA went missing, then - receivers on those interfaces will continue to NAK for lost data and - ultimately experience unrecoverable data loss. - - The principle function of SPMs is to provide the source path state - required for PGM network elements to forward NAKs from one PGM - network element to the next on the reverse of the distribution tree - for the TSI, establishing repair state each step of the way. This - source path state is simply the address of the upstream PGM network - element on the reverse of the distribution tree for the TSI. That - upstream PGM network element may be more than one subnet hop away. - SPMs establish the identity of the upstream PGM network element on - the distribution tree for each TSI in each group in each PGM network - element, a sort of virtual PGM topology. So although NAKs are - unicast addressed, they are NOT unicast routed by PGM network - elements in the conventional sense. Instead PGM network elements use - - - -Speakman, et. al. Experimental [Page 14] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - the source path state established by SPMs to direct NAKs PGM-hop-by- - PGM-hop toward the source. The idea is to constrain NAKs to the pure - PGM topology spanning the more heterogeneous underlying topology of - both PGM and non-PGM network elements. - - The result is repair state in every PGM network element between the - receiver and the source so that the corresponding RDATA is never - discarded by a PGM network element for lack of repair state. - - SPMs also maintain transmit window state in receivers by advertising - the trailing and leading edges of the transmit window (SPM_TRAIL and - SPM_LEAD). In the absence of data, SPMs MAY be used to close the - transmit window in time by advancing the transmit window until - SPM_TRAIL is equal to SPM_LEAD plus one. - -3.6. Packet Contents - - This section just provides enough short-hand to make the Procedures - intelligible. For the full details of packet contents, please refer - to Packet Formats below. - -3.6.1. Source Path Messages - -3.6.1.1. SPMs - - SPMs are transmitted by sources to establish source-path state in PGM - network elements, and to provide transmit-window state in receivers. - - SPMs are multicast to the group and contain: - - SPM_TSI the source-assigned TSI for the session to which the - SPM corresponds - - SPM_SQN a sequence number assigned sequentially by the source - in unit increments and scoped by SPM_TSI - - Nota Bene: this is an entirely separate sequence than is used to - number ODATA and RDATA. - - SPM_TRAIL the sequence number defining the trailing edge of the - source's transmit window (TXW_TRAIL) - - SPM_LEAD the sequence number defining the leading edge of the - source's transmit window (TXW_LEAD) - - SPM_PATH the network-layer address (NLA) of the interface on - the PGM network element on which the SPM is forwarded - - - - -Speakman, et. al. Experimental [Page 15] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -3.6.2. Data Packets - -3.6.2.1. ODATA - Original Data - - ODATA packets are transmitted by sources to send application data to - receivers. - - ODATA packets are multicast to the group and contain: - - OD_TSI the globally unique source-assigned TSI - - OD_TRAIL the sequence number defining the trailing edge of the - source's transmit window (TXW_TRAIL) - - OD_TRAIL makes the protocol more robust in the face of - lost SPMs. By including the trailing edge of the - transmit window on every data packet, receivers that - have missed any SPMs that advanced the transmit window - can still detect the case, recover the application, - and potentially re-synchronize to the transport - session. - - OD_SQN a sequence number assigned sequentially by the source - in unit increments and scoped by OD_TSI - -3.6.2.2. RDATA - Repair Data - - RDATA packets are repair packets transmitted by sources or DLRs in - response to NAKs. - - RDATA packets are multicast to the group and contain: - - RD_TSI OD_TSI of the ODATA packet for which this is a repair - - RD_TRAIL the sequence number defining the trailing edge of the - source's transmit window (TXW_TRAIL). This is updated - to the most current value when the repair is sent, so - it is not necessarily the same as OD_TRAIL of the - ODATA packet for which this is a repair - - RD_SQN OD_SQN of the ODATA packet for which this is a repair - -3.6.3. Negative Acknowledgments - -3.6.3.1. NAKs - Negative Acknowledgments - - NAKs are transmitted by receivers to request repairs for missing data - packets. - - - -Speakman, et. al. Experimental [Page 16] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - NAKs are unicast (PGM-hop-by-PGM-hop) to the source and contain: - - NAK_TSI OD_TSI of the ODATA packet for which a repair is - requested - - NAK_SQN OD_SQN of the ODATA packet for which a repair is - requested - - NAK_SRC the unicast NLA of the original source of the missing - ODATA. - - NAK_GRP the multicast group NLA - -3.6.3.2. NNAKs - Null Negative Acknowledgments - - NNAKs are transmitted by a DLR that receives NAKs redirected to it by - either receivers or network elements to provide flow-control feed- - back to a source. - - NNAKs are unicast (PGM-hop-by-PGM-hop) to the source and contain: - - NNAK_TSI NAK_TSI of the corresponding re-directed NAK. - - NNAK_SQN NAK_SQN of the corresponding re-directed NAK. - - NNAK_SRC NAK_SRC of the corresponding re-directed NAK. - - NNAK_GRP NAK_GRP of the corresponding re-directed NAK. - -3.6.4. Negative Acknowledgment Confirmations - -3.6.4.1. NCFs - NAK confirmations - - NCFs are transmitted by network elements and sources in response to - NAKs. - - NCFs are multicast to the group and contain: - - NCF_TSI NAK_TSI of the NAK being confirmed - - NCF_SQN NAK_SQN of the NAK being confirmed - - NCF_SRC NAK_SRC of the NAK being confirmed - - NCF_GRP NAK_GRP of the NAK being confirmed - - - - - - -Speakman, et. al. Experimental [Page 17] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -3.6.5. Option Encodings - - OPT_LENGTH 0x00 - Option's Length - - OPT_FRAGMENT 0x01 - Fragmentation - - OPT_NAK_LIST 0x02 - List of NAK entries - - OPT_JOIN 0x03 - Late Joining - - OPT_REDIRECT 0x07 - Redirect - - OPT_SYN 0x0D - Synchronization - - OPT_FIN 0x0E - Session Fin receivers, conventional - feedbackish - - OPT_RST 0x0F - Session Reset - - OPT_PARITY_PRM 0x08 - Forward Error Correction Parameters - - OPT_PARITY_GRP 0x09 - Forward Error Correction Group Number - - OPT_CURR_TGSIZE 0x0A - Forward Error Correction Group Size - - OPT_CR 0x10 - Congestion Report - - OPT_CRQST 0x11 - Congestion Report Request - - OPT_NAK_BO_IVL 0x04 - NAK Back-Off Interval - - OPT_NAK_BO_RNG 0x05 - NAK Back-Off Range - - OPT_NBR_UNREACH 0x0B - Neighbor Unreachable - - OPT_PATH_NLA 0x0C - Path NLA - - OPT_INVALID 0x7F - Option invalidated - -4. Procedures - General - - Since SPMs, NCFs, and RDATA must be treated conditionally by PGM - network elements, they must be distinguished from other packets in - the chosen multicast network protocol if PGM network elements are to - extract them from the usual switching path. - - - - - - -Speakman, et. al. Experimental [Page 18] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - The most obvious way for network elements to achieve this is to - examine every packet in the network for the PGM transport protocol - and packet types. However, the overhead of this approach is costly - for high-performance, multi-protocol network elements. An - alternative, and a requirement for PGM over IP multicast, is that - SPMs, NCFs, and RDATA MUST be transmitted with the IP Router Alert - Option [6]. This option gives network elements a network-layer - indication that a packet should be extracted from IP switching for - more detailed processing. - -5. Procedures - Sources - -5.1. Data Transmission - - Since PGM relies on a purely rate-limited transmission strategy in - the source to bound the bandwidth consumed by PGM transport sessions, - an assortment of techniques is assembled here to make that strategy - as conservative and robust as possible. These techniques are the - minimum REQUIRED of a PGM source. - -5.1.1. Maximum Cumulative Transmit Rate - - A source MUST number ODATA packets in the order in which they are - submitted for transmission by the application. A source MUST - transmit ODATA packets in sequence and only within the transmit - window beginning with TXW_TRAIL at no greater a rate than - TXW_MAX_RTE. - - TXW_MAX_RTE is typically the maximum cumulative transmit rate of SPM, - ODATA, and RDATA. Different transmission strategies MAY define - TXW_MAX_RTE as appropriate for the implementation. - -5.1.2. Transmit Rate Regulation - - To regulate its transmit rate, a source MUST use a token bucket - scheme or any other traffic management scheme that yields equivalent - behavior. A token bucket [7] is characterized by a continually - sustainable data rate (the token rate) and the extent to which the - data rate may exceed the token rate for short periods of time (the - token bucket size). Over any arbitrarily chosen interval, the number - of bytes the source may transmit MUST NOT exceed the token bucket - size plus the product of the token rate and the chosen interval. - - In addition, a source MUST bound the maximum rate at which successive - packets may be transmitted using a leaky bucket scheme drained at a - maximum transmit rate, or equivalent mechanism. - - - - - -Speakman, et. al. Experimental [Page 19] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -5.1.3. Outgoing Packet Ordering - - To preserve the logic of PGM's transmit window, a source MUST - strictly prioritize sending of pending NCFs first, pending SPMs - second, and only send ODATA or RDATA when no NCFs or SPMs are - pending. The priority of RDATA versus ODATA is application - dependent. The sender MAY implement weighted bandwidth sharing - between RDATA and ODATA. Note that strict prioritization of RDATA - over ODATA may stall progress of ODATA if there are receivers that - keep generating NAKs so as to always have RDATA pending (e.g. a - steady stream of late joiners with OPT_JOIN). Strictly prioritizing - ODATA over RDATA may lead to a larger portion of receivers getting - unrecoverable losses. - -5.1.4. Ambient SPMs - - Interleaved with ODATA and RDATA, a source MUST transmit SPMs at a - rate at least sufficient to maintain current source path state in PGM - network elements. Note that source path state in network elements - does not track underlying changes in the distribution tree from a - source until an SPM traverses the altered distribution tree. The - consequence is that NAKs may go unconfirmed both at receivers and - amongst network elements while changes in the underlying distribution - tree take place. - -5.1.5. Heartbeat SPMs - - In the absence of data to transmit, a source SHOULD transmit SPMs at - a decaying rate in order to assist early detection of lost data, to - maintain current source path state in PGM network elements, and to - maintain current receive window state in the receivers. - - In this scheme [8], a source maintains an inter-heartbeat timer - IHB_TMR which times the interval between the most recent packet - (ODATA, RDATA, or SPM) transmission and the next heartbeat - transmission. IHB_TMR is initialized to a minimum interval IHB_MIN - after the transmission of any data packet. If IHB_TMR expires, the - source transmits a heartbeat SPM and initializes IHB_TMR to double - its previous value. The transmission of consecutive heartbeat SPMs - doubles IHB each time up to a maximum interval IHB_MAX. The - transmission of any data packet initializes IHB_TMR to IHB_MIN once - again. The effect is to provoke prompt detection of missing packets - in the absence of data to transmit, and to do so with minimal - bandwidth overhead. - - - - - - - -Speakman, et. al. Experimental [Page 20] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -5.1.6. Ambient and Heartbeat SPMs - - Ambient and heartbeat SPMs are described as driven by separate timers - in this specification to highlight their contrasting functions. - Ambient SPMs are driven by a count-down timer that expires regularly - while heartbeat SPMs are driven by a count-down timer that keeps - being reset by data, and the interval of which changes once it begins - to expire. The ambient SPM timer is just counting down in real-time - while the heartbeat timer is measuring the inter-data-packet - interval. - - In the presence of data, no heartbeat SPMs will be transmitted since - the transmission of data keeps setting the IHB_TMR back to its - initial value. At the same time however, ambient SPMs MUST be - interleaved into the data as a matter of course, not necessarily as a - heartbeat mechanism. This ambient transmission of SPMs is REQUIRED - to keep the distribution tree information in the network current and - to allow new receivers to synchronize with the session. - - An implementation SHOULD de-couple ambient and heartbeat SPM timers - sufficiently to permit them to be configured independently of each - other. - -5.2. Negative Acknowledgment Confirmation - - A source MUST immediately multicast an NCF in response to any NAK it - receives. The NCF is REQUIRED since the alternative of responding - immediately with RDATA would not allow other PGM network elements on - the same subnet to do NAK anticipation, nor would it allow DLRs on - the same subnet to provide repairs. A source SHOULD be able to - detect a NAK storm and adopt countermeasure to protect the network - against a denial of service. A possible countermeasure is to send - the first NCF immediately in response to a NAK and then delay the - generation of further NCFs (for identical NAKs) by a small interval, - so that identical NCFs are rate-limited, without affecting the - ability to suppress NAKs. - -5.3. Repairs - - After multicasting an NCF in response to a NAK, a source MUST then - multicast RDATA (while respecting TXW_MAX_RTE) in response to any NAK - it receives for data packets within the transmit window. - - In the interest of increasing the efficiency of a particular RDATA - packet, a source MAY delay RDATA transmission to accommodate the - arrival of NAKs from the whole loss neighborhood. This delay SHOULD - not exceed twice the greatest propagation delay in the loss - neighborhood. - - - -Speakman, et. al. Experimental [Page 21] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -6. Procedures - Receivers - -6.1. Data Reception - - Initial data reception - - A receiver SHOULD initiate data reception beginning with the first - data packet it receives within the advertised transmit window. This - packet's sequence number (ODATA_SQN) temporarily defines the trailing - edge of the transmit window from the receiver's perspective. That - is, it is assigned to RXW_TRAIL_INIT within the receiver, and until - the trailing edge sequence number advertised in subsequent packets - (SPMs or ODATA or RDATA) increments past RXW_TRAIL_INIT, the receiver - MUST only request repairs for sequence numbers subsequent to - RXW_TRAIL_INIT. Thereafter, it MAY request repairs anywhere in the - transmit window. This temporary restriction on repair requests - prevents receivers from requesting a potentially large amount of - history when they first begin to receive a given PGM transport - session. - - Note that the JOIN option, discussed later, MAY be used to provide a - different value for RXW_TRAIL_INIT. - - Receiving and discarding data packets - - Within a given transport session, a receiver MUST accept any ODATA or - RDATA packets within the receive window. A receiver MUST discard any - data packet that duplicates one already received in the transmit - window. A receiver MUST discard any data packet outside of the - receive window. - - Contiguous data - - Contiguous data is comprised of those data packets within the receive - window that have been received and are in the range from RXW_TRAIL up - to (but not including) the first missing sequence number in the - receive window. The most recently received data packet of contiguous - data defines the leading edge of contiguous data. - - As its default mode of operation, a receiver MUST deliver only - contiguous data packets to the application, and it MUST do so in the - order defined by those data packets' sequence numbers. This provides - applications with a reliable ordered data flow. - - - - - - - - -Speakman, et. al. Experimental [Page 22] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Non contiguous data - - PGM receiver implementations MAY optionally provide a mode of - operation in which data is delivered to an application in the order - received. However, the implementation MUST only deliver complete - application protocol data units (APDUs) to the application. That is, - APDUs that have been fragmented into different TPDUs MUST be - reassembled before delivery to the application. - -6.2. Source Path Messages - - Receivers MUST receive and sequence SPMs for any TSI they are - receiving. An SPM is in sequence if its sequence number is greater - than that of the most recent in-sequence SPM and within half the PGM - number space. Out-of-sequence SPMs MUST be discarded. - - For each TSI, receivers MUST use the most recent SPM to determine the - NLA of the upstream PGM network element for use in NAK addressing. A - receiver MUST NOT initiate repair requests until it has received at - least one SPM for the corresponding TSI. - - Since SPMs require per-hop processing, it is likely that they will be - forwarded at a slower rate than data, and that they will arrive out - of sync with the data stream. In this case, the window information - that the SPMs carry will be out of date. Receivers SHOULD expect - this to be the case and SHOULD detect it by comparing the packet lead - and trail values with the values the receivers have stored for lead - and trail. If the SPM packet values are less, they SHOULD be - ignored, but the rest of the packet SHOULD be processed as normal. - -6.3. Data Recovery by Negative Acknowledgment - - Detecting missing data packets - - Receivers MUST detect gaps in the expected data sequence in the - following manners: - - by comparing the sequence number on the most recently received - ODATA or RDATA packet with the leading edge of contiguous data - - by comparing SPM_LEAD of the most recently received SPM with the - leading edge of contiguous data - - In both cases, if the receiver has not received all intervening data - packets, it MAY initiate selective NAK generation for each missing - sequence number. - - - - - -Speakman, et. al. Experimental [Page 23] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - In addition, a receiver may detect a single missing data packet by - receiving an NCF or multicast NAK for a data packet within the - transmit window which it has not received. In this case it MAY - initiate selective NAK generation for the said sequence number. - - In all cases, receivers SHOULD temper the initiation of NAK - generation to account for simple mis-ordering introduced by the - network. A possible mechanism to achieve this is to assume loss only - after the reception of N packets with sequence numbers higher than - those of the (assumed) lost packets. A possible value for N is 2. - This method SHOULD be complemented with a timeout based mechanism - that handles the loss of the last packet before a pause in the - transmission of the data stream. The leading edge field in SPMs - SHOULD also be taken into account in the loss detection algorithm. - - Generating NAKs - - NAK generation follows the detection of a missing data packet and is - the cycle of: - - waiting for a random period of time (NAK_RB_IVL) while listening - for matching NCFs or NAKs - - transmitting a NAK if a matching NCF or NAK is not heard - - waiting a period (NAK_RPT_IVL) for a matching NCF and recommencing - NAK generation if the matching NCF is not received - - waiting a period (NAK_RDATA_IVL) for data and recommencing NAK - generation if the matching data is not received - - The entire generation process can be summarized by the following - state machine: - - - - - - - - - - - - - - - - - - -Speakman, et. al. Experimental [Page 24] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - | - | detect missing tpdu - | - clear data retry count - | - clear NCF retry count - V - matching NCF |--------------------------| - <---------------| BACK-OFF_STATE | <---------------------- - | | start timer(NAK_RB_IVL) | ^ ^ - | | | | | - | |--------------------------| | | - | matching | | timer expires | | - | NAK | | - send NAK | | - | | | | | - | V V | | - | |--------------------------| | | - | | WAIT_NCF_STATE | | | - | matching NCF | start timer(NAK_RPT_IVL) | | | - |<--------------| |------------> | - | |--------------------------| timer expires | - | | | ^ - increment NCF | - | NAK_NCF_RETRIES | | | retry count | - | exceeded | | | | - | V ----------- | - | Cancelation matching NAK | - | - restart timer(NAK_RPT_IVL) | - | | - | | - V |--------------------------| | - --------------->| WAIT_DATA_STATE |-----------------------> - |start timer(NAK_RDATA_IVL)| timer expires - | | - increment data - |--------------------------| retry count - | | ^ - NAK_DATA_RETRIES | | | - exceeded | | | - | ----------- - | matching NCF or NAK - V - restart timer(NAK_RDATA_IVL) - Cancellation - - In any state, receipt of matching RDATA or ODATA completes data - recovery and successful exit from the state machine. State - transition stops any running timers. - - In any state, if the trailing edge of the window moves beyond the - sequence number, data recovery for that sequence number terminates. - - - - - -Speakman, et. al. Experimental [Page 25] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - During NAK_RB_IVL a NAK is said to be pending. When awaiting data or - an NCF, a NAK is said to be outstanding. - - Backing off NAK transmission - - Before transmitting a NAK, a receiver MUST wait some interval - NAK_RB_IVL chosen randomly over some time period NAK_BO_IVL. During - this period, receipt of a matching NAK or a matching NCF will suspend - NAK generation. NAK_RB_IVL is counted down from the time a missing - data packet is detected. - - A value for NAK_BO_IVL learned from OPT_NAK_BO_IVL (see 16.4.1 below) - MUST NOT be used by a receiver (i.e., the receiver MUST NOT NAK) - unless either NAK_BO_IVL_SQN is zero, or the receiver has seen - POLL_RND == 0 for POLL_SQN =< NAK_BO_IVL_SQN within half the sequence - number space. - - When a parity NAK (Appendix A, FEC) is being generated, the back-off - interval SHOULD be inversely biased with respect to the number of - parity packets requested. This way NAKs requesting larger numbers of - parity packets are likely to be sent first and thus suppress other - NAKs. A NAK for a given transmission group suppresses another NAK - for the same transmission group only if it is requesting an equal or - larger number of parity packets. - - When a receiver has to transmit a sequence of NAKs, it SHOULD - transmit the NAKs in order from oldest to most recent. - - Suspending NAK generation - - Suspending NAK generation just means waiting for either NAK_RB_IVL, - NAK_RPT_IVL or NAK_RDATA_IVL to pass. A receiver MUST suspend NAK - generation if a duplicate of the NAK is already pending from this - receiver or the NAK is already outstanding from this or another - receiver. - - NAK suppression - - A receiver MUST suppress NAK generation and wait at least - NAK_RDATA_IVL before recommencing NAK generation if it hears a - matching NCF or NAK during NAK_RB_IVL. A matching NCF must match - NCF_TSI with NAK_TSI, and NCF_SQN with NAK_SQN. - - Transmitting a NAK - - Upon expiry of NAK_RB_IVL, a receiver MUST unicast a NAK to the - upstream PGM network element for the TSI specifying the transport - session identifier and missing sequence number. In addition, it MAY - - - -Speakman, et. al. Experimental [Page 26] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - multicast a NAK with TTL of 1 to the group, if the PGM parent is not - directly connected. It also records both the address of the source - of the corresponding ODATA and the address of the group in the NAK - header. - - It MUST repeat the NAK at a rate governed by NAK_RPT_IVL up to - NAK_NCF_RETRIES times while waiting for a matching NCF. It MUST then - wait NAK_RDATA_IVL before recommencing NAK generation. If it hears a - matching NCF or NAK during NAK_RDATA_IVL, it MUST wait anew for - NAK_RDATA_IVL before recommencing NAK generation (i.e. matching NCFs - and NAKs restart NAK_RDATA_IVL). - - Completion of NAK generation - - NAK generation is complete only upon the receipt of the matching - RDATA (or even ODATA) packet at any time during NAK generation. - - Cancellation of NAK generation - - NAK generation is cancelled upon the advancing of the receive window - so as to exclude the matching sequence number of a pending or - outstanding NAK, or NAK_DATA_RETRIES / NAK_NCF_RETRIES being - exceeded. Cancellation of NAK generation indicates unrecoverable - data loss. - - Receiving NCFs and multicast NAKs - - A receiver MUST discard any NCFs or NAKs it hears for data packets - outside the transmit window or for data packets it has received. - Otherwise they are treated as appropriate for the current repair - state. - -7. Procedures - Network Elements - -7.1. Source Path State - - Upon receipt of an in-sequence SPM, a network element records the - Source Path Address SPM_PATH with the multicast routing information - for the TSI. If the receiving network element is on the same subnet - as the forwarding network element, this address will be the same as - the address of the immediately upstream network element on the - distribution tree for the TSI. If, however, non-PGM network elements - intervene between the forwarding and the receiving network elements, - this address will be the address of the first PGM network element - across the intervening network elements. - - - - - - -Speakman, et. al. Experimental [Page 27] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - The network element then forwards the SPM on each outgoing interface - for that TSI. As it does so, it encodes the network address of the - outgoing interface in SPM_PATH in each copy of the SPM it forwards. - -7.2. NAK Confirmation - - Network elements MUST immediately transmit an NCF in response to any - unicast NAK they receive. The NCF MUST be multicast to the group on - the interface on which the NAK was received. - - Nota Bene: In order to avoid creating multicast routing state for - PGM network elements across non-PGM-capable clouds, the network- - header source address of NCFs transmitted by network elements MUST - be set to the ODATA source's NLA, not the network element's NLA as - might be expected. - - Network elements should be able to detect a NAK storm and adopt - counter-measure to protect the network against a denial of service. - A possible countermeasure is to send the first NCF immediately in - response to a NAK and then delay the generation of further NCFs (for - identical NAKs) by a small interval, so that identical NCFs are - rate-limited, without affecting the ability to suppress NAKs. - - Simultaneously, network elements MUST establish repair state for the - NAK if such state does not already exist, and add the interface on - which the NAK was received to the corresponding repair interface list - if the interface is not already listed. - -7.3. Constrained NAK Forwarding - - The NAK forwarding procedures for network elements are quite similar - to those for receivers, but three important differences should be - noted. - - First, network elements do NOT back off before forwarding a NAK - (i.e., there is no NAK_BO_IVL) since the resulting delay of the NAK - would compound with each hop. Note that NAK arrivals will be - randomized by the receivers from which they originate, and this - factor in conjunction with NAK anticipation and elimination will - combine to forestall NAK storms on subnets with a dense network - element population. - - Second, network elements do NOT retry confirmed NAKs if RDATA is not - seen; they simply discard the repair state and rely on receivers to - re-request the repair. This approach keeps the repair state in the - network elements relatively ephemeral and responsive to underlying - routing changes. - - - - -Speakman, et. al. Experimental [Page 28] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Third, note that ODATA does NOT cancel NAK forwarding in network - elements since it is switched by network elements without transport- - layer intervention. - - Nota Bene: Once confirmed by an NCF, network elements discard NAK - packets; they are NOT retained in network elements beyond this - forwarding operation. - - NAK forwarding requires that a network element listen to NCFs for the - same transport session. NAK forwarding also requires that a network - element observe two time out intervals for any given NAK (i.e., per - NAK_TSI and NAK_SQN): NAK_RPT_IVL and NAK_RDATA_IVL. - - The NAK repeat interval NAK_RPT_IVL, limits the length of time for - which a network element will repeat a NAK while waiting for a - corresponding NCF. NAK_RPT_IVL is counted down from the transmission - of a NAK. Expiry of NAK_RPT_IVL cancels NAK forwarding (due to - missing NCF). - - The NAK RDATA interval NAK_RDATA_IVL, limits the length of time for - which a network element will wait for the corresponding RDATA. - NAK_RDATA_IVL is counted down from the time a matching NCF is - received. Expiry of NAK_RDATA_IVL causes the network element to - discard the corresponding repair state (due to missing RDATA). - - During NAK_RPT_IVL, a NAK is said to be pending. During - NAK_RDATA_IVL, a NAK is said to be outstanding. - - A Network element MUST forward NAKs only to the upstream PGM network - element for the TSI. - - A network element MUST repeat a NAK at a rate of NAK_RPT_RTE for an - interval of NAK_RPT_IVL until it receives a matching NCF. A matching - NCF must match NCF_TSI with NAK_TSI, and NCF_SQN with NAK_SQN. - - Upon reception of the corresponding NCF, network elements MUST wait - at least NAK_RDATA_IVL for the corresponding RDATA. Receipt of the - corresponding RDATA at any time during NAK forwarding cancels NAK - forwarding and tears down the corresponding repair state in the - network element. - -7.4. NAK elimination - - Two NAKs duplicate each other if they bear the same NAK_TSI and - NAK_SQN. Network elements MUST discard all duplicates of a NAK that - is pending. - - - - - -Speakman, et. al. Experimental [Page 29] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Once a NAK is outstanding, network elements MUST discard all - duplicates of that NAK for NAK_ELIM_IVL. Upon expiry of - NAK_ELIM_IVL, network elements MUST suspend NAK elimination for that - TSI/SQN until the first duplicate of that NAK is seen after the - expiry of NAK_ELIM_IVL. This duplicate MUST be forwarded in the - usual manner. Once this duplicate NAK is outstanding, network - elements MUST once again discard all duplicates of that NAK for - NAK_ELIM_IVL, and so on. NAK_RDATA_IVL MUST be reset each time a NAK - for the corresponding TSI/SQN is confirmed (i.e., each time - NAK_ELIM_IVL is reset). NAK_ELIM_IVL MUST be some small fraction of - NAK_RDATA_IVL. - - NAK_ELIM_IVL acts to balance implosion prevention against repair - state liveness. That is, it results in the elimination of all but at - most one NAK per NAK_ELIM_IVL thereby allowing repeated NAKs to keep - the repair state alive in the PGM network elements. - -7.5. NAK Anticipation - - An unsolicited NCF is one that is received by a network element when - the network element has no corresponding pending or outstanding NAK. - Network elements MUST process unsolicited NCFs differently depending - on the interface on which they are received. - - If the interface on which an NCF is received is the same interface - the network element would use to reach the upstream PGM network - element, the network element simply establishes repair state for - NCF_TSI and NCF_SQN without adding the interface to the repair - interface list, and discards the NCF. If the repair state already - exists, the network element restarts the NAK_RDATA_IVL and - NAK_ELIM_IVL timers and discards the NCF. - - If the interface on which an NCF is received is not the same - interface the network element would use to reach the upstream PGM - network element, the network element does not establish repair state - and just discards the NCF. - - Anticipated NAKs permit the elimination of any subsequent matching - NAKs from downstream. Upon establishing anticipated repair state, - network elements MUST eliminate subsequent NAKs only for a period of - NAK_ELIM_IVL. Upon expiry of NAK_ELIM_IVL, network elements MUST - suspend NAK elimination for that TSI/SQN until the first duplicate of - that NAK is seen after the expiry of NAK_ELIM_IVL. This duplicate - MUST be forwarded in the usual manner. Once this duplicate NAK is - outstanding, network elements MUST once again discard all duplicates - of that NAK for NAK_ELIM_IVL, and so on. NAK_RDATA_IVL MUST be reset - - - - - -Speakman, et. al. Experimental [Page 30] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - each time a NAK for the corresponding TSI/SQN is confirmed (i.e., - each time NAK_ELIM_IVL is reset). NAK_ELIM_IVL must be some small - fraction of NAK_RDATA_IVL. - -7.6. NAK Shedding - - Network elements MAY implement local procedures for withholding NAK - confirmations for receivers detected to be reporting excessive loss. - The result of these procedures would ultimately be unrecoverable data - loss in the receiver. - -7.7. Addressing NAKs - - A PGM network element uses the source and group addresses (NLAs) - contained in the transport header to find the state for the - corresponding TSI, looks up the corresponding upstream PGM network - element's address, uses it to re-address the (unicast) NAK, and - unicasts it on the upstream interface for the distribution tree for - the TSI. - -7.8. Constrained RDATA Forwarding - - Network elements MUST maintain repair state for each interface on - which a given NAK is received at least once. Network elements MUST - then use this list of interfaces to constrain the forwarding of the - corresponding RDATA packet only to those interfaces in the list. An - RDATA packet corresponds to a NAK if it matches NAK_TSI and NAK_SQN. - - Network elements MUST maintain this repair state only until either - the corresponding RDATA is received and forwarded, or NAK_RDATA_IVL - passes after forwarding the most recent instance of a given NAK. - Thereafter, the corresponding repair state MUST be discarded. - - Network elements SHOULD discard and not forward RDATA packets for - which they have no repair state. Note that the consequence of this - procedure is that, while it constrains repairs to the interested - subset of the network, loss of repair state precipitates further NAKs - from neglected receivers. - -8. Packet Formats - - All of the packet formats described in this section are transport- - layer headers that MUST immediately follow the network-layer header - in the packet. Only data packet headers (ODATA and RDATA) may be - followed in the packet by application data. For each packet type, - the network-header source and destination addresses are specified in - - - - - -Speakman, et. al. Experimental [Page 31] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - addition to the format and contents of the transport layer header. - Recall from General Procedures that, for PGM over IP multicast, SPMs, - NCFs, and RDATA MUST also bear the IP Router Alert Option. - - For PGM over IP, the IP protocol number is 113. - - In all packets the descriptions of Data-Source Port, Data-Destination - Port, Type, Options, Checksum, Global Source ID (GSI), and Transport - Service Data Unit (TSDU) Length are: - - Data-Source Port: - - A random port number generated by the source. This port number - MUST be unique within the source. Source Port together with - Global Source ID forms the TSI. - - Data-Destination Port: - - A globally well-known port number assigned to the given PGM - application. - - Type: - - The high-order two bits of the Type field encode a version - number, 0x0 in this instance. The low-order nibble of the type - field encodes the specific packet type. The intervening two - bits (the low-order two bits of the high-order nibble) are - reserved and MUST be zero. - - Within the low-order nibble of the Type field: - - values in the range 0x0 through 0x3 represent SPM-like - packets (i.e., session-specific, sourced by a source, - periodic), - - values in the range 0x4 through 0x7 represent DATA-like - packets (i.e., data and repairs), - - values in the range 0x8 through 0xB represent NAK-like - packets (i.e., hop-by-hop reliable NAK forwarding - procedures), - - and values in the range 0xC through 0xF represent SPMR-like - packets (i.e., session-specific, sourced by a receiver, - asynchronous). - - - - - - -Speakman, et. al. Experimental [Page 32] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Options: - - This field encodes binary indications of the presence and - significance of any options. It also directly encodes some - options. - - bit 0 set => One or more Option Extensions are present - - bit 1 set => One or more Options are network-significant - - Note that this bit is clear when OPT_FRAGMENT and/or - OPT_JOIN are the only options present. - - bit 6 set => Packet is a parity packet for a transmission group - of variable sized packets (OPT_VAR_PKTLEN). Only present when - OPT_PARITY is also present. - - bit 7 set => Packet is a parity packet (OPT_PARITY) - - Bits are numbered here from left (0 = MSB) to right (7 = LSB). - - All the other options (option extensions) are encoded in - extensions to the PGM header. - - Checksum: - - This field is the usual 1's complement of the 1's complement - sum of the entire PGM packet including header. - - The checksum does not include a network-layer pseudo header for - compatibility with network address translation. If the - computed checksum is zero, it is transmitted as all ones. A - value of zero in this field means the transmitter generated no - checksum. - - Note that if any entity between a source and a receiver - modifies the PGM header for any reason, it MUST either - recompute the checksum or clear it. The checksum is mandatory - on data packets (ODATA and RDATA). - - Global Source ID: - - A globally unique source identifier. This ID MUST NOT change - throughout the duration of the transport session. A - RECOMMENDED identifier is the low-order 48 bits of the MD5 [9] - signature of the DNS name of the source. Global Source ID - together with Data-Source Port forms the TSI. - - - - -Speakman, et. al. Experimental [Page 33] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - TSDU Length: - - The length in octets of the transport data unit exclusive of - the transport header. - - Note that those who require the TPDU length must obtain it from - sum of the transport header length (TH) and the TSDU length. - TH length is the sum of the size of the particular PGM packet - header (type_specific_size) plus the length of any options that - might be present. - - Address Family Indicators (AFIs) are as specified in [10]. - -8.1. Source Path Messages - - SPMs are sent by a source to establish source path state in network - elements and to provide transmit window state to receivers. - - The network-header source address of an SPM is the unicast NLA of the - entity that originates the SPM. - - The network-header destination address of an SPM is a multicast group - NLA. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source Port | Destination Port | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Options | Checksum | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Global Source ID ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ... Global Source ID | TSDU Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | SPM's Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Trailing Edge Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Leading Edge Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | NLA AFI | Reserved | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Path NLA ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - | Option Extensions when present ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - - - -Speakman, et. al. Experimental [Page 34] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Source Port: - - SPM_SPORT - - Data-Source Port, together with SPM_GSI forms SPM_TSI - - Destination Port: - - SPM_DPORT - - Data-Destination Port - - Type: - - SPM_TYPE = 0x00 - - Global Source ID: - - SPM_GSI - - Together with SPM_SPORT forms SPM_TSI - - SPM's Sequence Number - - SPM_SQN - - The sequence number assigned to the SPM by the source. - - Trailing Edge Sequence Number: - - SPM_TRAIL - - The sequence number defining the current trailing edge of the - source's transmit window (TXW_TRAIL). - - Leading Edge Sequence Number: - - SPM_LEAD - - The sequence number defining the current leading edge of the - source's transmit window (TXW_LEAD). - - If SPM_TRAIL == 0 and SPM_LEAD == 0x80000000, this indicates that - no window information is present in the packet. - - - - - - - -Speakman, et. al. Experimental [Page 35] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Path NLA: - - SPM_PATH - - The NLA of the interface on the network element on which this SPM - was forwarded. Initialized by a source to the source's NLA, - rewritten by each PGM network element upon forwarding. - -8.2. Data Packets - - Data packets carry application data from a source or a repairer to - receivers. - - ODATA: - - Original data packets transmitted by a source. - - RDATA: - - Repairs transmitted by a source or by a designated local - repairer (DLR) in response to a NAK. - - The network-header source address of a data packet is the unicast NLA - of the entity that originates the data packet. - - The network-header destination address of a data packet is a - multicast group NLA. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source Port | Destination Port | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Options | Checksum | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Global Source ID ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ... Global Source ID | TSDU Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Data Packet Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Trailing Edge Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Option Extensions when present ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Data ... - +-+-+- ... - - - - -Speakman, et. al. Experimental [Page 36] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Source Port: - - OD_SPORT, RD_SPORT - - Data-Source Port, together with Global Source ID forms: - - OD_TSI, RD_TSI - - Destination Port: - - OD_DPORT, RD_DPORT - - Data-Destination Port - - Type: - - OD_TYPE = 0x04 RD_TYPE = 0x05 - - Global Source ID: - - OD_GSI, RD_GSI - - Together with Source Port forms: - - OD_TSI, RD_TSI - - Data Packet Sequence Number: - - OD_SQN, RD_SQN - - The sequence number originally assigned to the ODATA packet by the - source. - - Trailing Edge Sequence Number: - - OD_TRAIL, RD_TRAIL - - The sequence number defining the current trailing edge of the - source's transmit window (TXW_TRAIL). In RDATA, this MAY not be - the same as OD_TRAIL of the ODATA packet for which it is a repair. - - Data: - - Application data. - - - - - - - -Speakman, et. al. Experimental [Page 37] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -8.3. Negative Acknowledgments and Confirmations - - NAK: - - Negative Acknowledgments are sent by receivers to request the - repair of an ODATA packet detected to be missing from the - expected sequence. - - N-NAK: - - Null Negative Acknowledgments are sent by DLRs to provide flow - control feedback to the source of ODATA for which the DLR has - provided the corresponding RDATA. - - The network-header source address of a NAK is the unicast NLA of the - entity that originates the NAK. The network-header source address of - NAK is rewritten by each PGM network element with its own. - - The network-header destination address of a NAK is initialized by the - originator of the NAK (a receiver) to the unicast NLA of the upstream - PGM network element known from SPMs. The network-header destination - address of a NAK is rewritten by each PGM network element with the - unicast NLA of the upstream PGM network element to which this NAK is - forwarded. On the final hop, the network-header destination address - of a NAK is rewritten by the PGM network element with the unicast NLA - of the original source or the unicast NLA of a DLR. - - NCF: - - NAK Confirmations are sent by network elements and sources to - confirm the receipt of a NAK. - - The network-header source address of an NCF is the ODATA source's - NLA, not the network element's NLA as might be expected. - - The network-header destination address of an NCF is a multicast group - NLA. - - Note that in NAKs and N-NAKs, unlike the other packets, the field - SPORT contains the Data-Destination port and the field DPORT contains - the Data-Source port. As a general rule, the content of SPORT/DPORT - is determined by the direction of the flow: in packets which travel - down-stream SPORT is the port number chosen in the data source - (Data-Source Port) and DPORT is the data destination port number - (Data-Destination Port). The opposite holds for packets which travel - upstream. This makes DPORT the protocol endpoint in the recipient - host, regardless of the direction of the packet. - - - - -Speakman, et. al. Experimental [Page 38] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source Port | Destination Port | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Options | Checksum | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Global Source ID ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ... Global Source ID | TSDU Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Requested Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | NLA AFI | Reserved | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source NLA ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - | NLA AFI | Reserved | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Multicast Group NLA ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - | Option Extensions when present ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... - - Source Port: - - NAK_SPORT, NNAK_SPORT - - Data-Destination Port - - NCF_SPORT - - Data-Source Port, together with Global Source ID forms NCF_TSI - - Destination Port: - - NAK_DPORT, NNAK_DPORT - - Data-Source Port, together with Global Source ID forms: - - NAK_TSI, NNAK_TSI - - NCF_DPORT - - Data-Destination Port - - - - - - -Speakman, et. al. Experimental [Page 39] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Type: - - NAK_TYPE = 0x08 NNAK_TYPE = 0x09 - - NCF_TYPE = 0x0A - - Global Source ID: - - NAK_GSI, NNAK_GSI, NCF_GSI - - Together with Data-Source Port forms - - NAK_TSI, NNAK_TSI, NCF_TSI - - Requested Sequence Number: - - NAK_SQN, NNAK_SQN - - NAK_SQN is the sequence number of the ODATA packet for which a - repair is requested. - - NNAK_SQN is the sequence number of the RDATA packet for which a - repair has been provided by a DLR. - - NCF_SQN - - NCF_SQN is NAK_SQN from the NAK being confirmed. - - Source NLA: - - NAK_SRC, NNAK_SRC, NCF_SRC - - The unicast NLA of the original source of the missing ODATA. - - Multicast Group NLA: - - NAK_GRP, NNAK_GRP, NCF_GRP - - The multicast group NLA. NCFs MAY bear OPT_REDIRECT and/or - OPT_NAK_LIST - -9. Options - - PGM specifies several end-to-end options to address specific - application requirements. PGM specifies options to support - fragmentation, late joining, and redirection. - - - - - -Speakman, et. al. Experimental [Page 40] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Options MAY be appended to PGM data packet headers only by their - original transmitters. While they MAY be interpreted by network - elements, options are neither added nor removed by network elements. - - Options are all in the TLV style, or Type, Length, Value. The Type - field is contained in the first byte, where bit 0 is the OPT_END bit, - followed by 7 bits of type. The OPT_END bit MUST be set in the last - option in the option list, whichever that might be. The Length field - is the total length of the option in bytes, and directly follows the - Type field. Following the Length field are 5 reserved bits, the - OP_ENCODED flag, the 2 Option Extensibility bits OPX and the - OP_ENCODED_NULL flag. Last are 7 bits designated for option specific - information which may be defined on a per-option basis. If not - defined for a particular option, they MUST be set to 0. - - The Option Extensibility bits dictate the desired treatment of an - option if it is unknown to the network element processing it. - - Nota Bene: Only network elements pay any attention to these bits. - - The OPX bits are defined as follows: - - 00 - Ignore the option - - 01 - Invalidate the option by changing the type to OPT_INVALID - = 0x7F - - 10 - Discard the packet - - 11 - Unsupported, and reserved for future use - - Some options present in data packet (ODATA and RDATA) are strictly - associated with the packet content (PGM payload), OPT_FRAGMENT being - an example. These options must be preserved even when the data - packet that would normally contain them is not received, but its the - payload is recovered though the use of FEC. PGM specifies a - mechanism to accomplish this that uses the F (OP_ENCODED) and U - (OP_ENCODED_NULL) bits in the option common header. OP_ENCODED and - OP_ENCODED_NULL MUST be normally set to zero except when the option - is used in FEC packets to preserve original options. See Appendix A - for details. - - There is a limit of 16 options per packet. - - - - - - - - -Speakman, et. al. Experimental [Page 41] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - General Option Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U|Opt. Specific| - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Option Value ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...+-+-+ - -9.1. Option extension length - OPT_LENGTH - - When option extensions are appended to the standard PGM header, the - extensions MUST be preceded by an option extension length field - specifying the total length of all option extensions. - - In addition, the presence of the options MUST be encoded in the - Options field of the standard PGM header before the Checksum is - computed. - - All network-significant options MUST be appended before any - exclusively receiver-significant options. - - To provide an indication of the end of option extensions, OPT_END - (0x80) MUST be set in the Option Type field of the trailing option - extension. - -9.1.1. OPT_LENGTH - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Option Type | Option Length | Total length of all options | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x00 - - Option Length = 4 octets - - Total length of all options - - The total length in octets of all option extensions including - OPT_LENGTH. - - OPT_LENGTH is NOT network-significant. - - - - - - -Speakman, et. al. Experimental [Page 42] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.2. Fragmentation Option - OPT_FRAGMENT - - Fragmentation allows transport-layer entities at a source to break up - application protocol data units (APDUs) into multiple PGM data - packets (TPDUs) to conform with the MTU supported by the network - layer. The fragmentation option MAY be applied to ODATA and RDATA - packets only. - - Architecturally, the accumulation of TSDUs into APDUs is applied to - TPDUs that have already been received, duplicate eliminated, and - contiguously sequenced by the receiver. Thus APDUs MAY be - reassembled across increments of the transmit window. - -9.2.1. OPT_FRAGMENT - Packet Extension Contents - - OPT_FRAG_OFF the offset of the fragment from the beginning of the - APDU - - OPT_FRAG_LEN the total length of the original APDU - -9.2.2. OPT_FRAGMENT - Procedures - Sources - - A source fragments APDUs into a contiguous series of fragments no - larger than the MTU supported by the network layer. A source - sequentially and uniquely assigns OD_SQNs to these fragments in the - order in which they occur in the APDU. A source then sets - OPT_FRAG_OFF to the value of the offset of the fragment in the - original APDU (where the first byte of the APDU is at offset 0, and - OPT_FRAG_OFF numbers the first byte in the fragment), and set - OPT_FRAG_LEN to the value of the total length of the original APDU. - -9.2.3. OPT_FRAGMENT - Procedures - Receivers - - Receivers detect and accumulate fragmented packets until they have - received an entire contiguous sequence of packets comprising an APDU. - This sequence begins with the fragment bearing OPT_FRAG_OFF of 0, and - terminates with the fragment whose length added to its OPT_FRAG_OFF - is OPT_FRAG_LEN. - - - - - - - - - - - - - -Speakman, et. al. Experimental [Page 43] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.2.4. OPT_FRAGMENT - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | First Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Offset | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x01 - - Option Length = 12 octets - - First Sequence Number - - Sequence Number of the PGM DATA/RDATA packet containing the first - fragment of the APDU. - - Offset - - The byte offset of the fragment from the beginning of the APDU - (OPT_FRAG_OFF). - - Length - - The total length of the original APDU (OPT_FRAG_LEN). - - OPT_FRAGMENT is NOT network-significant. - -9.3. NAK List Option - OPT_NAK_LIST - - The NAK List option MAY be used in conjunction with NAKs to allow - receivers to request transmission for more than one sequence number - with a single NAK packet. The option is limited to 62 listed NAK - entries. The NAK list MUST be unique and duplicate free. It MUST be - ordered, and MUST consist of either a list of selective or a list of - parity NAKs. In general, network elements, sources and receivers - must process a NAK list as if they had received individual NAKs for - each sequence number in the list. The procedures for each are - outlined in detail earlier in this document. Clarifications and - differences are detailed here. - - - - - -Speakman, et. al. Experimental [Page 44] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.3.1. OPT_NAK_LIST - Packet Extensions Contents - - A list of sequence numbers for which retransmission is requested. - -9.3.2. OPT_NAK_LIST - Procedures - Receivers - - Receivers MAY append the NAK List option to a NAK to indicate that - they wish retransmission of a number of RDATA. - - Receivers SHOULD proceed to back off NAK transmission in a manner - consistent with the procedures outlined for single sequence number - NAKs. Note that the repair of each separate sequence number will be - completed upon receipt of a separate RDATA packet. - - Reception of an NCF or multicast NAK containing the NAK List option - suspends generation of NAKs for all sequence numbers within the NAK - list, as well as the sequence number within the NAK header. - -9.3.3. OPT_NAK_LIST - Procedures - Network Elements - - Network elements MUST immediately respond to a NAK with an identical - NCF containing the same NAK list as the NAK itself. - - Network elements MUST forward a NAK containing a NAK List option if - any one sequence number specified by the NAK (including that in the - main NAK header) is not currently outstanding. That is, it MUST - forward the NAK, if any one sequence number does not have an - elimination timer running for it. The NAK must be forwarded intact. - - Network elements MUST eliminate a NAK containing the NAK list option - only if all sequence numbers specified by the NAK (including that in - the main NAK header) are outstanding. That is, they are all running - an elimination timer. - - Upon receipt of an unsolicited NCF containing the NAK list option, a - network element MUST anticipate data for every sequence number - specified by the NAK as if it had received an NCF for every sequence - number specified by the NAK. - -9.3.4. OPT_NAK_LIST - Procedures - Sources - - A source MUST immediately respond to a NAK with an identical NCF - containing the same NAK list as the NAK itself. - - It MUST then multicast RDATA (while respecting TXW_MAX_RTE) for every - requested sequence number. - - - - - -Speakman, et. al. Experimental [Page 45] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.3.5. OPT_NAK_LIST - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Requested Sequence Number 1 | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ..... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Requested Sequence Number N | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x02 - - Option Length = 4 + (4 * number of SQNs) octets - - Requested Sequence Number - - A list of up to 62 additional sequence numbers to which the NAK - applies. - - OPT_NAK_LIST is network-significant. - -9.4. Late Joining Option - OPT_JOIN - - Late joining allows a source to bound the amount of repair history - receivers may request when they initially join a particular transport - session. - - This option indicates that receivers that join a transport session in - progress MAY request repair of all data as far back as the given - minimum sequence number from the time they join the transport - session. The default is for receivers to receive data only from the - first packet they receive and onward. - -9.4.1. OPT_JOIN - Packet Extensions Contents - - OPT_JOIN_MIN the minimum sequence number for repair - -9.4.2. OPT_JOIN - Procedures - Receivers - - If a PGM packet (ODATA, RDATA, or SPM) bears OPT_JOIN, a receiver MAY - initialize the trailing edge of the receive window (RXW_TRAIL_INIT) - to the given Minimum Sequence Number and proceeds with normal data - reception. - - - - -Speakman, et. al. Experimental [Page 46] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.4.3. OPT_JOIN - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Minimum Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - - Option Type = 0x03 - - Option Length = 8 octets - - Minimum Sequence Number - - The minimum sequence number defining the initial trailing edge of - the receive window for a late joining receiver. - - OPT_JOIN is NOT network-significant. - -9.5. Redirect Option - OPT_REDIRECT - - Redirection MAY be used by a designated local repairer (DLR) to - advertise its own address as an alternative to the original source, - for requesting repairs. - - These procedures allow a PGM Network Element to use a DLR that is one - PGM hop from it either upstream or downstream in the multicast - distribution tree. The former are referred to as upstream DLRs. The - latter are referred to as off-tree DLRs. Off-Tree because even - though they are downstream of the point of loss, they might not lie - on the subtree affected by the loss. - - A DLR MUST receive any PGM sessions for which it wishes to provide - retransmissions. A DLR SHOULD respond to NCFs or POLLs sourced by - its PGM parent with a redirecting POLR response packet containing an - OPT_REDIRECT which provides its own network layer address. - Recipients of redirecting POLRs MAY then direct NAKs for subsequent - ODATA sequence numbers to the DLR rather than to the original source. - In addition, DLRs that receive redirected NAKs for which they have - RDATA MUST send a NULL NAK to provide flow control to the original - source without also provoking a repair from that source. - - - - - - - -Speakman, et. al. Experimental [Page 47] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.5.1. OPT_REDIRECT - Packet Extensions Contents - - OPT_REDIR_NLA the DLR's own unicast network-layer address to which - recipients of the redirecting POLR MAY direct - subsequent NAKs for the corresponding TSI. - -9.5.2. OPT_REDIRECT - Procedures - DLRs - - A DLR MUST receive any PGM sessions for which it wishes to provide a - source of repairs. In addition to acting as an ordinary PGM - receiver, a DLR MAY then respond to NCFs or relevant POLLs sourced by - parent network elements (or even by the source itself) by sending a - POLR containing an OPT_REDIRECT providing its own network-layer - address. - - If a DLR can provide FEC repairs it MUST denote this by setting - OPT_PARITY in the PGM header of its POLR response. - -9.5.2.1. Upstream DLRs - - If the NCF completes NAK transmission initiated by the DLR itself, - the DLR MUST NOT send a redirecting POLR. - - When a DLR receives an NCF from its upstream PGM parent, it SHOULD - send a redirecting POLR, multicast to the group. The DLR SHOULD - record that it is acting as an upstream DLR for the said session. - Note that this POLR MUST have both the data source's source address - and the router alert option in its network header. - - An upstream DLR MUST act as an ordinary PGM source in responding to - any NAK it receives (i.e., directed to it). That is, it SHOULD - respond first with a normal NCF and then RDATA as usual. In - addition, an upstream DLR that receives redirected NAKs for which it - has RDATA MUST send a NULL NAK to provide flow control to the - original source. If it cannot provide the RDATA it forwards the NAK - to the upstream PGM neighbor as usual. - - Nota Bene: In order to propagate on exactly the same distribution - tree as ODATA, RDATA and POLR packets transmitted by DLRs MUST - bear the ODATA source's NLA as the network-header source address, - not the DLR's NLA as might be expected. - - - - - - - - - - -Speakman, et. al. Experimental [Page 48] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.5.2.2. Off-Tree DLRs - - A DLR that receives a POLL with sub-type PGM_POLL_DLR MUST respond - with a unicast redirecting POLR if it provides the appropriate - service. The DLR SHOULD respond using the rules outlined for polling - in Appendix D of this text. If the DLR responds, it SHOULD record - that it is acting as an off-tree DLR for the said session. - - An off-tree DLR acts in a special way in responding to any NAK it - receives (i.e., directed to it). It MUST respond to a NAK directed - to it from its parent by unicasting an NCF and RDATA to its parent. - The parent will then forward the RDATA down the distribution tree. - The DLR uses its own and the parent's NLA addresses in the network - header for the source and destination respectively. The unicast NCF - and RDATA packets SHOULD not have the router alert option. In all - other ways the RDATA header should be "as if" the packet had come - from the source. - - Again, an off-tree DLR that receives redirected NAKs for which it has - RDATA MUST originate a NULL NAK to provide flow control to the - original source. It MUST originate the NULL NAK before originating - the RDATA. This must be done to reduce the state held in the network - element. - - If it cannot provide the RDATA for a given NAK, an off-tree DLR - SHOULD confirm the NAK with a unicast NCF as normal, then immediately - send a NAK for the said data packet back to its parent. - -9.5.2.3. Simultaneous Upstream and Off-Tree DLR operation - - Note that it is possible for a DLR to provide service to its parent - and to downstream network elements simultaneously. A downstream loss - coupled with a loss for the same data on some other part of the - distribution tree served by its parent could cause this. In this - case it may provide both upstream and off-tree functionality - simultaneously. - - Note that a DLR differentiates between NAKs from an NE downstream or - from its parent by comparing the network-header source address of the - NAK with it's upstream PGM parent's NLA. The DLR knows the parent's - NLA from the session's SPM messages. - - - - - - - - - - -Speakman, et. al. Experimental [Page 49] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.5.3. OPT_REDIRECT - Procedures - Network Elements - -9.5.3.1. Discovering DLRs - - When a PGM router receives notification of a loss via a NAK, it - SHOULD first try to use a known DLR to recover the loss. If such a - DLR is not known it SHOULD initiate DLR discovery. DLR discovery may - occur in two ways. If there are upstream DLRs, the NAK transmitted - by this router to its PGM parent will trigger their discovery, via a - redirecting POLR. Also, a network element SHOULD initiate a search - for off-tree DLRs using the PGM polling mechanism, and the sub-type - PGM_POLL_DLR. - - If a DLR can provide FEC repairs it will denote this by setting - OPT_PARITY in the PGM header of its POLR response. A network element - SHOULD only direct parity NAKs to a DLR that can provide FEC repairs. - -9.5.3.2. Redirected Repair - - When it can, a network element SHOULD use upstream DLRs. - - Upon receiving a redirecting POLR, network elements SHOULD record the - redirecting information for the TSI, and SHOULD redirect subsequent - NAKs for the same TSI to the network address provided in the - redirecting POLR rather than to the PGM neighbor known via the SPMs. - Note, however, that a redirecting POLR is NOT regarded as matching - the NAK that provoked it, so it does not complete the transmission of - that NAK. Only a normal matching NCF can complete the transmission - of a NAK. - - For subsequent NAKs, if the network element has recorded redirection - information for the corresponding TSI, it MAY change the destination - network address of those NAKs and attempt to transmit them to the - DLR. No NAK for a specific SQN SHOULD be sent to an off-tree DLR if - a NAK for the SQN has been seen on the interface associated with the - DLR. Instead the NAK SHOULD be forwarded upstream. Subsequent NAKs - for different SQNs MAY be forwarded to the said DLR (again assuming - no NAK for them has been seen on the interface to the DLR). - - If a corresponding NCF is not received from the DLR within - NAK_RPT_IVL, the network element MUST discard the redirecting - information for the TSI and re-attempt to forward the NAK towards the - PGM upstream neighbor. - - - - - - - - -Speakman, et. al. Experimental [Page 50] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - If a NAK is received from the DLR for a requested SQN, the network - element MUST discard the redirecting information for the SQN and re- - attempt to forward the NAK towards the PGM upstream neighbor. The - network element MAY still direct NAKs for different SQNs to the DLR. - - RDATA and NCFs from upstream DLRs will flow down the distribution - tree. However, RDATA and NCFs from off-tree DLRs will be unicast to - the network element. The network element will terminate the NCF, but - MUST put the source's NLA and the group address into the network - header and MUST add router alert before forwarding the RDATA packet - to the distribution subtree. - - NULL NAKs from an off-tree DLR for an RDATA packet requested from - that off-tree DLR MUST always be forwarded upstream. The network - element can assume that these will arrive before the matching RDATA. - Other NULL NAKs are forwarded only if matching repair state has not - already been created. Network elements MUST NOT confirm or retry - NULL NAKs and they MUST NOT add the receiving interface to the repair - state. If a NULL NAK is used to initially create repair state, this - fact must be recorded so that any subsequent non-NULL NAK will not be - eliminated, but rather will be forwarded to provoke an actual repair. - State created by a NULL NAK exists only for NAK_ELIM_IVL. - -9.5.4. OPT_REDIRECT - Procedures - Receivers - - These procedures are intended to be applied in instances where a - receiver's first hop router on the reverse path to the source is not - a PGM Network Element. So, receivers MUST ignore a redirecting POLR - from a DLR on the same IP subnet that the receiver resides on, since - this is likely to suffer identical loss to the receiver and so be - useless. Therefore, these procedures are entirely OPTIONAL. A - receiver MAY choose to ignore all redirecting POLRs since in cases - where its first hop router on the reverse path is PGM capable, it - would ignore them anyway. Also, note that receivers will never learn - of off-tree DLRs. - - Upon receiving a redirecting POLR, receivers SHOULD record the - redirecting information for the TSI, and MAY redirect subsequent NAKs - for the same TSI to the network address provided in the redirecting - POLR rather than to the PGM neighbor for the corresponding ODATA for - which the receiver is requesting repair. Note, however, that a - redirecting POLR is NOT regarded as matching the NAK that provoked - it, so it does not complete the transmission of that NAK. Only a - normal matching NCF can complete the transmission of a NAK. - - For subsequent NAKs, if the receiver has recorded redirection - information for the corresponding TSI, it MAY change the destination - network address of those NAKs and attempt to transmit them to the - - - -Speakman, et. al. Experimental [Page 51] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - DLR. If a corresponding NCF is not received within NAK_RPT_IVL, the - receiver MUST discard the redirecting information for the TSI and - re-attempt to forward the NAK to the PGM neighbor for the original - source of the missing ODATA. - -9.5.5. OPT_REDIRECT - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | NLA AFI | Reserved | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | DLR's NLA ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - - Option Type = 0x07 - - Option Length = 4 + NLA length - - DLR's NLA - - The DLR's own unicast network address to which recipients of the - redirecting POLR may direct subsequent NAKs. - - OPT_REDIRECT is network-significant. - -9.6. OPT_SYN - Synchronization Option - - The SYN option indicates the starting data packet for a session. It - must only appear in ODATA or RDATA packets. - - The SYN option MAY be used to provide a useful abstraction to - applications that can simplify application design by providing stream - start notification. It MAY also be used to let a late joiner to a - session know that it is indeed late (i.e. it would not see the SYN - option). - -9.6.1. OPT_SYN - Procedures - Receivers - - Procedures for receivers are implementation dependent. A receiver - MAY use the SYN to provide its applications with abstractions of the - data stream. - - - - - - - -Speakman, et. al. Experimental [Page 52] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.6.2. OPT_SYN - Procedures - Sources - - Sources MAY include OPT_SYN in the first data for a session. That - is, they MAY include the option in: - - the first ODATA sent on a session by a PGM source - - any RDATA sent as a result of loss of this ODATA packet - - all FEC packets for the first transmission group; in this case it - is interpreted as the first packet having the SYN - -9.6.3. OPT_SYN - Procedures - DLRs - - In an identical manner to sources, DLRs MUST provide OPT_SYN in - any retransmitted data that is at the start of a session. - -9.6.4. OPT_SYN - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x0D - - Option Length = 4 - - OPT_SYN is NOT network-significant. - -9.7. OPT_FIN - Session Finish Option - - This FIN option indicates the last data packet for a session and - an orderly close down. - - The FIN option MAY be used to provide an abstraction to - applications that can simplify application design by providing - stream end notification. - - This option MAY be present in the last data packet or transmission - group for a session. The FIN PGM option MUST appear in every SPM - sent after the last ODATA for a session. The SPM_LEAD sequence - number in an SPM with the FIN option indicates the last known data - successfully transmitted for the session. - - - - - - -Speakman, et. al. Experimental [Page 53] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.7.1. OPT_FIN - Procedures - Receivers - - A receiver SHOULD use receipt of a FIN to let it know that it can - tear down its data structures for the said session once a suitable - time period has expired (TXW_SECS). It MAY still try to solicit - retransmissions within the existing transmit window. - - Other than this, procedures for receivers are implementation - dependent. A receiver MAY use the FIN to provide its applications - with abstractions of the data stream and to inform its - applications that the session is ending. - - 9.7.2. OPT_FIN - Procedures - Sources - - Sources MUST include OPT_FIN in every SPM sent after it has been - determined that the application has closed gracefully. If a - source is aware at the time of transmission that it is ending a - session the source MAY include OPT_FIN in, - - the last ODATA - - any associated RDATAs for the last data - - FEC packets for the last transmission group; in this case it is - interpreted as the last packet having the FIN - - When a source detects that it needs to send an OPT_FIN it SHOULD - immediately send it. This is done either by appending it to the last - data packet or transmission group or by immediately sending an SPM - and resetting the SPM heartbeat timer (i.e. it does not wait for a - timer to expire before sending the SPM). After sending an OPT_FIN, - the session SHOULD not close and stop sending SPMs until after a time - period equal to TXW_SECS. - -9.7.3. OPT_FIN - Procedures - DLRs - - In an identical manner to sources, DLRs MUST provide OPT_FIN in any - retransmitted data that is at the end of a session. - - - - - - - - - - - - - -Speakman, et. al. Experimental [Page 54] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.7.4. OPT_FIN - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x0E - - Option Length = 4 - - OPT_FIN is NOT network-significant. - -9.8. OPT_RST - Session Reset Option - - The RST option MAY appear in every SPM sent after an unrecoverable - error is identified by the source. This acts to notify the receivers - that the session is being aborted. This option MAY appear only in - SPMs. The SPM_LEAD sequence number in an SPM with the RST option - indicates the last known data successfully transmitted for the - session. - -9.8.1. OPT_RST - Procedures - Receivers - - Receivers SHOULD treat the reception of OPT_RST in an SPM as an abort - of the session. - - A receiver that receives an SPM with an OPT_RST with the N bit set - SHOULD not send any more NAKs for the said session towards the - source. If the N bit (see 9.8.5) is not set, the receiver MAY - continue to try to solicit retransmit data within the current - transmit window. - -9.8.2. OPT_RST - Procedures - Sources - - Sources SHOULD include OPT_RST in every SPM sent after it has been - determined that an unrecoverable error condition has occurred. The N - bit of the OPT_RST SHOULD only be sent if the source has determined - that it cannot process NAKs for the session. The cause of the - OPT_RST is set to an implementation specific value. If the error - code is unknown, then the value of 0x00 is used. When a source - detects that it needs to send an OPT_RST it SHOULD immediately send - it. This is done by immediately sending an SPM and resetting the SPM - heartbeat timer (i.e. it does not wait for a timer to expire before - sending the SPM). After sending an OPT_RST, the session SHOULD not - close and stop sending SPMs until after a time period equal to - TXW_SECS. - - - -Speakman, et. al. Experimental [Page 55] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -9.8.3. OPT_RST - Procedures - DLRs - - None. - -9.8.4. OPT_RST - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U|N|Error Code | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x0F - - Option Length = 4 - - N bit - - The N bit is set to 1 to indicate that NAKs for previous ODATA - will go unanswered from the source. The application will tell the - source to turn this bit on or off. - - Error Code - - The 6 bit error code field is used to forward an error code down - to the receivers from the source. - - The value of 0x00 indicates an unknown reset reason. Any other - value indicates the application purposely aborted and gave a - reason (the error code value) that may have meaning to the end - receiver application. These values are entirely application - dependent. - - OPT_RST is NOT network-significant. - -10. Security Considerations - - In addition to the usual problems of end-to-end authentication, PGM - is vulnerable to a number of security risks that are specific to the - mechanisms it uses to establish source path state, to establish - repair state, to forward NAKs, to identify DLRs, and to distribute - repairs. These mechanisms expose PGM network elements themselves to - security risks since network elements not only switch but also - interpret SPMs, NAKs, NCFs, and RDATA, all of which may legitimately - be transmitted by PGM sources, receivers, and DLRs. Short of full - authentication of all neighboring sources, receivers, DLRs, and - network elements, the protocol is not impervious to abuse. - - - - -Speakman, et. al. Experimental [Page 56] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - So putting aside the problems of rogue PGM network elements for the - moment, there are enough potential security risks to network elements - associated with sources, receivers, and DLRs alone. These risks - include denial of service through the exhausting of both CPU - bandwidth and memory, as well as loss of (repair) data connectivity - through the muddling of repair state. - - False SPMs may cause PGM network elements to mis-direct NAKs intended - for the legitimate source with the result that the requested RDATA - would not be forthcoming. - - False NAKs may cause PGM network elements to establish spurious - repair state that will expire only upon time-out and could lead to - memory exhaustion in the meantime. - - False NCFs may cause PGM network elements to suspend NAK forwarding - prematurely (or to mis-direct NAKs in the case of redirecting POLRs) - resulting eventually in loss of RDATA. - - False RDATA may cause PGM network elements to tear down legitimate - repair state resulting eventually in loss of legitimate RDATA. - - The development of precautions for network elements to protect - themselves against incidental or unsophisticated versions of these - attacks is work outside of this spec and includes: - - Damping of jitter in the value of either the network-header source - address of SPMs or the path NLA in SPMs. While the network-header - source address is expected to change seldom, the path NLA is - expected to change occasionally as a consequence of changes in - underlying multicast routing information. - - The extension of NAK shedding procedures to control the volume, not - just the rate, of confirmed NAKs. In either case, these procedures - assist network elements in surviving NAK attacks at the expense of - maintaining service. More efficiently, network elements may use the - knowledge of TSIs and their associated transmit windows gleaned from - SPMs to control the proliferation of repair state. - - A three-way handshake between network elements and DLRs that would - permit a network element to ascertain with greater confidence that an - alleged DLR is identified by the alleged network-header source - address, and is PGM conversant. - - - - - - - - -Speakman, et. al. Experimental [Page 57] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -11. Appendix A - Forward Error Correction - -11.1. Introduction - - The following procedures incorporate packet-level Reed Solomon - Erasure correcting techniques as described in [11] and [12] into PGM. - This approach to Forward Error Correction (FEC) is based upon the - computation of h parity packets from k data packets for a total of n - packets such that a receiver can reconstruct the k data packets out - of any k of the n packets. The original k data packets are referred - to as the Transmission Group, and the total n packets as the FEC - Block. - - These procedures permit any combination of pro-active FEC or on- - demand FEC with conventional ARQ (selective retransmission) within a - given TSI to provide any flavor of layered or integrated FEC. The - two approaches can be used by the same or different receivers in a - single transport session without conflict. Once provided by a - source, the actual use of FEC or selective retransmission for loss - recovery in the session is entirely at the discretion of the - receivers. Note however that receivers SHOULD NOT ask for selective - retransmissions when FEC is available, nevertheless sources MUST - provide selective retransmissions in response to selective NAKs from - the leading partial transmission group (i.e. the most recent - transmission group, which is not yet full). For any group that is - full, the source SHOULD provide FEC on demand in response to a - selective NAK. - - Pro-active FEC refers to the technique of computing parity packets at - transmission time and transmitting them as a matter of course - following the data packets. Pro-active FEC is RECOMMENDED for - providing loss recovery over simplex or asymmetric multicast channels - over which returning repair requests is either impossible or costly. - It provides increased reliability at the expense of bandwidth. - - On-demand FEC refers to the technique of computing parity packets at - repair time and transmitting them only upon demand (i.e., receiver- - based loss detection and repair request). On-demand FEC is - RECOMMENDED for providing loss recovery of uncorrelated loss in very - large receiver populations in which the probability of any single - packet being lost is substantial. It provides equivalent reliability - to selective NAKs (ARQ) at no more and typically less expense of - bandwidth. - - Selective NAKs are NAKs that request the retransmission of specific - packets by sequence number corresponding to the sequence number of - any data packets detected to be missing from the expected sequence - (conventional ARQ). Selective NAKs can be used for recovering losses - - - -Speakman, et. al. Experimental [Page 58] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - occurring in leading partial transmission groups, i.e. in the most - recent transmission group, which is not yet full. The RECOMMENDED - way of handling partial transmission groups, however, is for the data - source to use variable-size transmission groups (see below). - - Parity NAKs are NAKs that request the transmission of a specific - number of parity packets by count corresponding to the count of the - number of data packets detected to be missing from a group of k data - packets (on-demand FEC). - - The objective of these procedures is to incorporate these FEC - techniques into PGM so that: - - sources MAY provide parity packets either pro-actively or on- - demand, interchangeably within the same TSI, - - receivers MAY use either selective or parity NAKs interchangeably - within the same TSI (however, in a session where on-demand parity - is available receivers SHOULD only use parity NAKs). - - network elements maintain repair state based on either selective - or parity NAKs in the same data structure, altering only search, - RDATA constraint, and deletion algorithms in either case, - - and only OPTION additions to the basic packet formats are - REQUIRED. - -11.2. Overview - - Advertising FEC parameters in the transport session - - Sources add OPT_PARITY_PRM to SPMs to provide session-specific - parameters such as the number of packets (TGSIZE == k) in a - transmission group. This option lets receivers know how many packets - there are in a transmission group, and it lets network elements sort - repair state by transmission group number. This option includes an - indication of whether pro-active and/or on-demand parity is available - from the source. - - Distinguishing parity packets from data packets - - Sources send pro-active parity packets as ODATA (NEs do not forward - RDATA unless a repair state is present) and on-demand parity packets - as RDATA. A source MUST add OPT_PARITY to the ODATA/RDATA packet - header of parity packets to permit network elements and receivers to - distinguish them from data packets. - - - - - -Speakman, et. al. Experimental [Page 59] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Data and parity packet numbering - - Parity packets MUST be calculated over a fixed number k of data - packets known as the Transmission Group. Grouping of packets into - transmission groups effectively partitions a packet sequence number - into a high-order portion (TG_SQN) specifying the transmission group - (TG), and a low-order portion (PKT_SQN) specifying the packet number - (PKT-NUM in the range 0 through k-1) within that group. From an - implementation point of view, it's handy if k, the TG size, is a - power of 2. If so, then TG_SQN and PKT_SQN can be mapped side-by- - side into the 32 bit SQN. log2(TGSIZE) is then the size in bits of - PKT_SQN. - - This mapping does not reduce the effective sequence number space - since parity packets marked with OPT_PARITY allow the sequence space - (PKT_SQN) to be completely reused in order to number the h parity - packets, as long as h is not greater than k. - - In the case where h is greater than k, a source MUST add - OPT_PARITY_GRP to any parity packet numbered j greater than k-1, - specifying the number m of the group of k parity packets to which the - packet belongs, where m is just the quotient from the integer - division of j by k. Correspondingly, PKT-NUM for such parity packets - is just j modulo k. In other words, when a source needs to generate - more parity packets than there were original data packets (perhaps - because of a particularly lossy line such that a receiver lost not - only the original data but some of the parity RDATA as well), use the - OPT_PARITY_GRP option in order to number and identify the - transmission group of the extra packets that would exceed the normal - sequential number space. - - Note that parity NAKs (and consequently their corresponding parity - NCFs) MUST also contain the OPT_PARITY flag in the options field of - the fixed header, and that in these packets, PKT_SQN MUST contain - PKT_CNT, the number of missing packets, rather than PKT_NUM, the SQN - of a specific missing packet. More on all this later. - - Variable Transmission Group Size - - The transmission group size advertised in the OPT_PARITY_PRM option - on SPMs MUST be a power of 2 and constant for the duration of the - session. However, the actual transmission group size used MAY not be - constant for the duration of the session, and MAY not be a power of - 2. When a TG size different from the one advertised in - OPT_PARITY_PRM is used, the TG size advertised in OPT_PARITY_PRM MUST - be interpreted as specifying the maximum effective size of the TG. - - - - - -Speakman, et. al. Experimental [Page 60] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - When the actual TG size is not a power of 2 or is smaller than the - max TG size, there will be sparse utilization of the sequence number - space since some of the sequence numbers that would have been - consumed in numbering a maximum sized TG will not be assigned to - packets in the smaller TG. The start of the next transmission group - will always begin on the boundary of the maximum TG size as though - each of the sequence numbers had been utilized. - - When the source decides to use a smaller group size than that - advertised in OPT_PARITY_PRM, it appends OPT_CURR_TGSIZE to the last - data packet (ODATA) in the truncated transmission group. This lets - the receiver know that it should not expect any more packets in this - transmission group, and that it may start requesting repairs for any - missing packets. If the last data packet itself went missing, the - receiver will detect the end of the group when it receives a parity - packet for the group, an SPM with SPM_LEAD equal to OD_SQN of the - last data packet, or the first packet of the next group, whichever - comes first. In addition, any parity packet from this TG will also - carry the OPT_CURR_TGSIZE option as will any SPM sent with SPM_LEAD - equal to OD_SQN of the last data packet. - - Variable TSDU length - - If a non constant TSDU length is used within a given transmission - group, the size of parity packets in the corresponding FEC block MUST - be equal to the size of the largest original data packet in the - block. Parity packets MUST be computed by padding the original - packets with zeros up to the size of the largest data packet. Note - that original data packets are transmitted without padding. - - Receivers using a combination of original packets and FEC packets to - rebuild missing packets MUST pad the original packets in the same way - as the source does. The receiver MUST then feed the padded original - packets plus the parity packets to the FEC decoder. The decoder - produces the original packets padded with zeros up to the size of the - largest original packet in the group. In order for the receiver to - eliminate the padding on the reconstructed data packets, the original - size of the packet MUST be known, and this is accomplished as - follows: - - The source, along with the packet payloads, encodes the TSDU - length and appends the 2-byte encoded length to the padded FEC - packets. - - Receivers pad the original packets that they received to the - largest original packet size and then append the TSDU length to - the padded packets. They then pass them and the FEC packets to - the FEC decoder. - - - -Speakman, et. al. Experimental [Page 61] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - The decoder produces padded original packets with their original - TSDU length appended. Receivers MUST now use this length to get - rid of the padding. - - A source that transmits variable size packets MUST take into account - the fact that FEC packets will have a size equal to the maximum size - of the original packets plus the size of the length field (2 bytes). - - If a fixed packet size is used within a transmission group, the - encoded length is not appended to the parity packets. The presence - of the fixed header option flag OPT_VAR_PKTLEN in parity packets - allows receivers to distinguish between transmission groups with - variable sized packets and fixed-size ones, and behave accordingly. - - Payload-specific options - - Some options present in data packet (ODATA and RDATA) are strictly - associated with the packet content (PGM payload), OPT_FRAGMENT being - an example. These options must be preserved even when the data - packet that would normally contain them is not received, but its the - payload is recovered though the use of FEC. - - To achieve this, PGM encodes the content of these options in special - options that are inserted in parity packets. Two flags present in - the the option common-header are used for this process: bit F - (OP_ENCODED) and bit U (OP_ENCODED_NULL). - - Whenever at least one of the original packets of a TG contains a - payload-specific option of a given type, the source MUST include an - encoded version of that option type in all the parity packets it - transmits. The encoded option is computed by applying FEC encoding - to the whole option with the exception of the first three bytes of - the option common-header (E, Option Type, Option Length, OP_ENCODED - and OPX fields). The type, length and OPX of the encoded option are - the same as the type, length and OPX in the original options. - OP_ENCODED is set to 1 (all original option have OP_ENCODED = 0). - - The encoding is performed using the same process that is used to - compute the payload of the parity packet. i.e. the FEC encoder is fed - with one copy of that option type for each original packet in the TG. - If one (or more) original packet of the TG does not contain that - option type, an all zeroes option is used for the encoding process. - To be able to distinguish this "dummy" option from valid options with - all-zeroes payload, OP_ENCODED_NULL is used. OP_ENCODED_NULL is set - to 0 in all the original options, but the value of 1 is used in the - encoding process if the option did not exist in the original packet. - On the receiver side, all option with OP_ENCODED_NULL equal to 1 are - discarded after decoding. - - - -Speakman, et. al. Experimental [Page 62] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - When a receiver recovers a missing packet using FEC repair packets, - it MUST also recover payload-specific options, if any. The presence - of these can be unequivocally detected through the presence of - encoded options in parity packets (encoded options have OP_ENCODED - set to 1). Receivers apply FEC-recovery to encoded options and - possibly original options, as they do to recover packet payloads. - The FEC decoding is applied to the whole option with the exception of - the first three bytes of the option common-header (E, Option Type, - Option Length, OP_ENCODED and OPX fields). Each decoded option is - associated with the relative payload, unless OP_ENCODED_NULL turns - out to be 1, in which case the decoded option is discarded. - - The decoding MUST be performed using the 1st occurrence of a given - option type in original/parity packets. If one or more original - packets do not contain that option type, an option of the same type - with zero value must be used. This option MUST have OP_ENCODED_NULL - equal to 1. - -11.3. Packet Contents - - This section just provides enough short-hand to make the Procedures - intelligible. For the full details of packet contents, please refer - to Packet Formats below. - - OPT_PARITY indicated in pro-active (ODATA) and on-demand - (RDATA) parity packets to distinguish them from - data packets. This option is directly encoded in - the "Option" field of the fixed PGM header - - OPT_VAR_PKTLEN MAY be present in pro-active (ODATA) and on-demand - (RDATA) parity packets to indicate that the - corresponding transmission group is composed of - variable size data packets. This option is - directly encoded in the "Option" field of the fixed - PGM header - - OPT_PARITY_PRM appended by sources to SPMs to specify session- - specific parameters such as the transmission group - size and the availability of pro-active and/or on- - demand parity from the source - - OPT_PARITY_GRP the number of the group (greater than 0) of h - parity packets to which the parity packet belongs - when more than k parity packets are provided by the - source - - - - - - -Speakman, et. al. Experimental [Page 63] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - OPT_CURR_TGSIZE appended by sources to the last data packet and any - parity packets in a variable sized transmission - group to indicate to the receiver the actual size - of a transmission group. May also be appended to - certain SPMs - -11.3.1. Parity NAKs - - NAK_TG_SQN the high-order portion of NAK_SQN specifying the - transmission group for which parity packets are - requested - - NAK_PKT_CNT the low-order portion of NAK_SQN specifying the - number of missing data packets for which parity - packets are requested - - Nota Bene: NAK_PKT_CNT (and NCF_PKT_CNT) are 0-based counters, - meaning that NAK_PKT_CNT = 0 means that 1 FEC RDATA is being - requested, and in general NAK_PKT_CNT = k - 1 means that k FEC - RDATA are being requested. - -11.3.2. Parity NCFs - - NCF_TG_SQN the high-order portion of NCF_SQN specifying the - transmission group for which parity packets were - requested - - NCF_PKT_CNT the low-order portion of NCF_SQN specifying the - number of missing data packets for which parity - packets were requested - - Nota Bene: NCF_PKT_CNT (and NAK_PKT_CNT) are 0-based counters, - meaning that NAK_PKT_CNT = 0 means that 1 FEC RDATA is being - requested, and in general NAK_PKT_CNT = k - 1 means that k FEC - RDATA are being requested. - -11.3.3. On-demand Parity - - RDATA_TG_SQN the high-order portion of RDATA_SQN specifying the - transmission group to which the parity packet - belongs - - RDATA_PKT_SQN the low-order portion of RDATA_SQN specifying the - parity packet sequence number within the - transmission group - - - - - - -Speakman, et. al. Experimental [Page 64] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -11.3.4. Pro-active Parity - - ODATA_TG_SQN the high-order portion of ODATA_SQN specifying the - transmission group to which the parity packet - belongs - - ODATA_PKT_SQN the low-order portion of ODATA_SQN specifying the - parity packet sequence number within the - transmission group - -11.4. Procedures - Sources - - If a source elects to provide parity for a given transport session, - it MUST first provide the transmission group size PARITY_PRM_TGS in - the OPT_PARITY_PRM option of its SPMs. This becomes the maximum - effective transmission group size in the event that the source elects - to send smaller size transmission groups. If a source elects to - provide proactive parity for a given transport session, it MUST set - PARITY_PRM_PRO in the OPT_PARITY_PRM option of its SPMs. If a source - elects to provide on-demand parity for a given transport session, it - MUST set PARITY_PRM_OND in the OPT_PARITY_PRM option of its SPMs. - - A source MUST send any pro-active parity packets for a given - transmission group only after it has first sent all of the - corresponding k data packets in that group. Pro-active parity - packets MUST be sent as ODATA with OPT_PARITY in the fixed header. - - If a source elects to provide on-demand parity, it MUST respond to a - parity NAK for a transmission group with a parity NCF. The source - MUST complete the transmission of the k original data packets and the - proactive parity packets, possibly scheduled, before starting the - transmission of on-demand parity packets. Subsequently, the source - MUST send the number of parity packets requested by that parity NAK. - On-demand parity packets MUST be sent as RDATA with OPT_PARITY in the - fixed header. Previously transmitted pro-active parity packets - cannot be reused as on-demand parity packets, these MUST be computed - with new, previously unused, indexes. - - In either case, the source MUST provide selective retransmissions - only in response to selective NAKs from the leading partial - transmission group. For any group that is full, the source SHOULD - provide FEC on demand in response to a selective retransmission - request. - - In the absence of data to transmit, a source SHOULD prematurely - terminate the current transmission group by including OPT_CURR_TGSIZE - to the last data packet or to any proactive parity packets provided. - - - - -Speakman, et. al. Experimental [Page 65] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - If the last data packet has already been transmitted and there is no - provision for sending proactive parity packets, an SPM with - OPT_CURR_TGSIZE SHOULD be sent. - - A source consolidates requests for on-demand parity in the same - transmission group according to the following procedures. If the - number of pending (i.e., unsent) parity packets from a previous - request for on-demand parity packets is equal to or greater than - NAK_PKT_CNT in a subsequent NAK, that subsequent NAK MUST be - confirmed but MAY otherwise be ignored. If the number of pending - (i.e., unsent) parity packets from a previous request for on-demand - parity packets is less than NAK_PKT_CNT in a subsequent NAK, that - subsequent NAK MUST be confirmed but the source need only increase - the number of pending parity packets to NAK_PKT_CNT. - - When a source provides parity packets relative to a transmission - group with variable sized packets, it MUST compute parity packets by - padding the smaller original packets with zeroes out to the size of - the largest of the original packets. The source MUST also append the - encoded TSDU lengths at the end of any padding or directly to the end - of the largest packet, and add the OPT_VAR_PKTLEN option as specified - in the overview description. - - When a source provides variable sized transmission groups, it SHOULD - append the OPT_CURR_TGSIZE option to the last data packet in the - shortened group, and it MUST append the OPT_CURR_TGSIZE option to any - parity packets it sends within that group. In case the the last data - packet is sent before a determination has been made to shorten the - group and there is no provision for sending proactive parity packets, - an SPM with OPT_CURR_TGSIZE SHOULD be sent. The source MUST also add - OPT_CURR_TGSIZE to any SPM that it sends with SPM_LEAD equal to - OD_SQN of the last data packet. - - A receiver MUST NAK for the entire number of packets missing based on - the maximum TG size, even if it already knows that the actual TG size - is smaller. The source MUST take this into account and compute the - number of packets effectively needed as the difference between - NAK_PKT_CNT and an offset computed as the difference between the max - TG size and the effective TG size. - -11.5. Procedures - Receivers - - If a receiver elects to make use of parity packets for loss recovery, - it MUST first learn the transmission group size PARITY_PRM_TGS from - OPT_PARITY_PRM in the SPMs for the TSI. The transmission group size - is used by a receiver to determine the sequence number boundaries - between transmission groups. - - - - -Speakman, et. al. Experimental [Page 66] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Thereafter, if PARITY_PRM_PRO is also set in the SPMs for the TSI, a - receiver SHOULD use any pro-active parity packets it receives for - loss recovery, and if PARITY_PRM_OND is also set in the SPMs for the - TSI, it MAY solicit on-demand parity packets upon loss detection. If - PARITY_PRM_OND is set, a receiver MUST NOT send selective NAKs, - except in partial transmission groups if the source does not use the - variable transmission-group size option. Parity packets are ODATA - (pro-active) or RDATA (on-demand) packets distinguished by OPT_PARITY - which lets receivers know that ODATA/RDATA_TG_SQN identifies the - group of PARITY_PRM_TGS packets to which the parity may be applied - for loss recovery in the corresponding transmission group, and that - ODATA/RDATA_PKT_SQN is being reused to number the parity packets - within that group. Receivers order parity packets and eliminate - duplicates within a transmission group based on ODATA/RDATA_PKT_SQN - and on OPT_PARITY_GRP if present. - - To solicit on-demand parity packets, a receiver MUST send parity NAKs - upon loss detection. For the purposes of soliciting on-demand - parity, loss detection occurs at transmission group boundaries, i.e. - upon receipt of the last data packet in a transmission group, upon - receipt of any data packet in any subsequent transmission group, or - upon receipt of any parity packet in the current or a subsequent - transmission group. - - A parity NAK is simply a NAK with OPT_PARITY and NAK_PKT_CNT set to - the count of the number of packets detected to be missing from the - transmission group specified by NAK_TG_SQN. Note that this - constrains the receiver to request no more parity packets than there - are data packets in the transmission group. - - A receiver SHOULD bias the value of NAK_BO_IVL for parity NAKs - inversely proportional to NAK_PKT_CNT so that NAKs for larger losses - are likely to be scheduled ahead of NAKs for smaller losses in the - same receiver population. - - A confirming NCF for a parity NAK is a parity NCF with NCF_PKT_CNT - equal to or greater than that specified by the parity NAK. - - A receiver's NAK_RDATA_IVL timer is not cancelled until all requested - parity packets have been received. - - In the absence of data (detected from SPMs bearing SPM_LEAD equal to - RXW_LEAD) on non-transmission-group boundaries, receivers MAY resort - to selective NAKs for any missing packets in that partial - transmission group. - - - - - - -Speakman, et. al. Experimental [Page 67] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - When a receiver handles parity packets belonging to a transmission - group with variable sized packets, (detected from the presence of the - OPT_VAR_PKTLEN option in the parity packets), it MUST decode them as - specified in the overview description and use the decoded TSDU length - to get rid of the padding in the decoded packet. - - If the source was using a variable sized transmission group via the - OPT_CURR_TGSIZE, the receiver might learn this before having - requested (and received) any retransmission. The above happens if it - sees OPT_CURR_TGSIZE in the last data packet of the TG, in any - proactive parity packet or in a SPM. If the receivers learns this - and determines that it has missed one or more packets in the - shortened transmission group, it MAY then NAK for them without - waiting for the start of the next transmission group. Otherwise it - will start NAKing at the start of the next transmission group. - - In both cases, the receiver MUST NAK for the number of packets - missing assuming that the size of the transmission group is the - maximum effective transmission group. In other words, the receivers - cannot exploit the fact that it might already know that the - transmission group was smaller but MUST always NAK for the number of - packets it believes are missing, plus the number of packets required - to bring the total packets up to the maximum effective transmission - group size. - - After the first parity packet has been delivered to the receiver, the - actual TG size is known to him, either because already known or - because discovered via OPT_CURR_TGSIZE contained in the parity - packet. Hence the receiver can decode the whole group as soon as the - minimum number of parity packets needed is received. - -11.6. Procedures - Network Elements - - Pro-active parity packets (ODATA with OPT_PARITY) are switched by - network elements without transport-layer intervention. - - On-demand parity packets (RDATA with OPT_PARITY) necessitate modified - request, confirmation and repair constraint procedures for network - elements. In the context of these procedures, repair state is - maintained per NAK_TSI and NAK_TG_SQN, and in addition to recording - the interfaces on which corresponding NAKs have been received, - records the largest value of NAK_PKT_CNT seen in corresponding NAKs - on each interface. This value is referred to as the known packet - count. The largest of the known packet counts recorded for any - interface in the repair state for the transmit group or carried by an - NCF is referred to as the largest known packet count. - - - - - -Speakman, et. al. Experimental [Page 68] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Upon receipt of a parity NAK, a network element responds with the - corresponding parity NCF. The corresponding parity NCF is just an - NCF formed in the usual way (i.e., a multicast copy of the NAK with - the packet type changed), but with the addition of OPT_PARITY and - with NCF_PKT_CNT set to the larger of NAK_PKT_CNT and the known - packet count for the receiving interface. The network element then - creates repair state in the usual way with the following - modifications. - - If repair state for the receiving interface does not exist, the - network element MUST create it and additionally record NAK_PKT_CNT - from the parity NAK as the known packet count for the receiving - interface. - - If repair state for the receiving interface already exists, the - network element MUST eliminate the NAK only if NAK_ELIM_IVL has not - expired and NAK_PKT_CNT is equal to or less than the largest known - packet count. If NAK_PKT_CNT is greater than the known packet count - for the receiving interface, the network element MUST update the - latter with the larger NAK_PKT_CNT. - - Upon either adding a new interface or updating the known packet count - for an existing interface, the network element MUST determine if - NAK_PKT_CNT is greater than the largest known packet count. If so or - if NAK_ELIM_IVL has expired, the network element MUST forward the - parity NAK in the usual way with a value of NAK_PKT_CNT equal to the - largest known packet count. - - Upon receipt of an on-demand parity packet, a network element MUST - locate existing repair state for the corresponding RDATA_TSI and - RDATA_TG_SQN. If no such repair state exists, the network element - MUST discard the RDATA as usual. - - If corresponding repair state exists, the largest known packet count - MUST be decremented by one, then the network element MUST forward the - RDATA on all interfaces in the existing repair state, and decrement - the known packet count by one for each. Any interfaces whose known - packet count is thereby reduced to zero MUST be deleted from the - repair state. If the number of interfaces is thereby reduced to - zero, the repair state itself MUST be deleted. - - Upon reception of a parity NCF, network elements MUST cancel pending - NAK retransmission only if NCF_PKT_CNT is greater or equal to the - largest known packet count. Network elements MUST use parity NCFs to - anticipate NAKs in the usual way with the addition of recording - NCF_PKT_CNT from the parity NCF as the largest known packet count - with the anticipated state so that any subsequent NAKs received with - NAK_PKT_CNT equal to or less than NCF_PKT_CNT will be eliminated, and - - - -Speakman, et. al. Experimental [Page 69] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - any with NAK_PKT_CNT greater than NCF_PKT_CNT will be forwarded. - Network elements which receive a parity NCF with NCF_PKT_CNT larger - than the largest known packet count MUST also use it to anticipate - NAKs, increasing the largest known packet count to reflect - NCF_PKT_CNT (partial anticipation). - - Parity NNAKs follow the usual elimination procedures with the - exception that NNAKs are eliminated only if existing NAK state has a - NAK_PKT_CNT greater than NNAK_PKT_CNT. - - Network elements must take extra precaution when the source is using - a variable sized transmission group. Network elements learn that the - source is using a TG size smaller than the maximum from - OPT_CURR_TGSIZE in parity RDATAs or in SPMs. When this happens, they - compute a TG size offset as the difference between the maximum TG - size and the actual TG size advertised by OPT_CURR_TGSIZE. Upon - reception of parity RDATA, the TG size offset is used to update the - repair state as follows: - - Any interface whose known packet count is reduced to the TG size - offset is deleted from the repair state. - - This replaces the normal rule for deleting interfaces that applies - when the TG size is equal to the maximum TG size. - -11.7. Procedures - DLRs - - A DLR with the ability to provide FEC repairs MUST indicate this by - setting the OPT_PARITY bit in the redirecting POLR. It MUST then - process any redirected FEC NAKs in the usual way. - -11.8. Packet Formats - -11.8.1. OPT_PARITY_PRM - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| |P O| - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Transmission Group Size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x08 - - Option Length = 8 octets - - P-bit (PARITY_PRM_PRO) - - - -Speakman, et. al. Experimental [Page 70] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Indicates when set that the source is providing pro-active parity - packets. - - O-bit (PARITY_PRM_OND) - - Indicates when set that the source is providing on-demand parity - packets. - - At least one of PARITY_PRM_PRO and PARITY_PRM_OND MUST be set. - - Transmission Group Size (PARITY_PRM_TGS) - - The number of data packets in the transmission group over which - the parity packets are calculated. If a variable transmission - group size is being used, then this becomes the maximum effective - transmission group size across the session. - - OPT_PARITY_PRM MAY be appended only to SPMs. - - OPT_PARITY_PRM is network-significant. - -11.8.2. OPT_PARITY_GRP - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Parity Group Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x09 - - Option Length = 8 octets - - Parity Group Number (PRM_GROUP) - - The number of the group of k parity packets amongst the h parity - packets within the transmission group to which the parity packet - belongs, where the first k parity packets are in group zero. - PRM_GROUP MUST NOT be zero. - - OPT_PARITY_GRP MAY be appended only to parity packets. - - OPT_PARITY_GRP is NOT network-significant. - - - - - - -Speakman, et. al. Experimental [Page 71] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -11.8.3. OPT_CURR_TGSIZE - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Actual Transmission Group Size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x0A - - Option Length = 8 octets - - Actual Transmission Group Size (PRM_ATGSIZE) - - The actual number of data packets in this transmission group. - This MUST be less than or equal to the maximum transmission group - size PARITY_PRM_TGS in OPT_PARITY_PRM. - - OPT_CURR_TGSIZE MAY be appended to data and parity packets (ODATA or - RDATA) and to SPMs. - - OPT_CURR_TGSIZE is network-significant except when appended to ODATA. - -12. Appendix B - Support for Congestion Control - -12.1. Introduction - - A source MUST implement strategies for congestion avoidance, aimed at - providing overall network stability, fairness among competing PGM - flows, and some degree of fairness towards coexisting TCP flows [13]. - In order to do this, the source must be provided with feedback on the - status of the network in terms of traffic load. This appendix - specifies NE procedures that provide such feedback to the source in a - scalable way. (An alternative TCP-friendly scheme for congestion - control that does not require NE support can be found in [16]). - - The procedures specified in this section enable the collection and - selective forwarding of three types of feedback to the source: - - o Worst link load as measured in network elements. - - o Worst end-to-end path load as measured in network elements. - - o Worst end-to-end path load as reported by receivers. - - - - - -Speakman, et. al. Experimental [Page 72] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - This specification defines in detail NE procedures, receivers - procedures and packet formats. It also defines basic procedures in - receivers for generating congestion reports. This specification does - not define the procedures used by PGM sources to adapt their - transmission rates in response of congestion reports. Those - procedures depend upon the specific congestion control scheme. - - PGM defines a header option that PGM receivers may append to NAKs - (OPT_CR). OPT_CR carries congestion reports in NAKs that propagate - upstream towards the source. - - During the process of hop-by-hop reverse NAK forwarding, NEs examine - OPT_CR and possibly modify its contents prior to forwarding the NAK - upstream. Forwarding CRs also has the side effect of creating - congestion report state in the NE. The presence of OPT_CR and its - contents also influences the normal NAK suppression rules. Both the - modification performed on the congestion report and the additional - suppression rules depend on the content of the congestion report and - on the congestion report state recorded in the NE as detailed below. - - OPT_CR contains the following fields: - - OPT_CR_NE_WL Reports the load in the worst link as detected though - NE internal measurements - - OPT_CR_NE_WP Reports the load in the worst end-to-end path as - detected though NE internal measurements - - OPT_CR_RX_WP Reports the load in the worst end-to-end path as - detected by receivers - - A load report is either a packet drop rate (as measured at an NE's - interfaces) or a packet loss rate (as measured in receivers). Its - value is linearly encoded in the range 0-0xFFFF, where 0xFFFF - represents a 100% loss/drop rate. Receivers that send a NAK bearing - OPT_CR determine which of the three report fields are being reported. - - OPT_CR also contains the following fields: - - OPT_CR_NEL A bit indicating that OPT_CR_NE_WL is being reported. - - OPT_CR_NEP A bit indicating that OPT_CR_NE_WP is being reported. - - OPT_CR_RXP A bit indicating that OPT_CR_RX_WP is being reported. - - - - - - - -Speakman, et. al. Experimental [Page 73] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - OPT_CR_LEAD A SQN in the ODATA space that serves as a temporal - reference for the load report values. This is - initialized by receivers with the leading edge of the - transmit window as known at the moment of transmitting - the NAK. This value MAY be advanced in NEs that - modify the content of OPT_CR. - - OPT_CR_RCVR The identity of the receiver that generated the worst - OPT_CR_RX_WP. - - The complete format of the option is specified later. - -12.2. NE-Based Worst Link Report - - To permit network elements to report worst link, receivers append - OPT_CR to a NAK with bit OPT_CR_NEL set and OPT_CR_NE_WL set to zero. - NEs receiving NAKs that contain OPT_CR_NE_WL process the option and - update per-TSI state related to it as described below. The ultimate - result of the NEs' actions ensures that when a NAK leaves a sub-tree, - OPT_CR_NE_WL contains a congestion report that reflects the load of - the worst link in that sub-tree. To achieve this, NEs rewrite - OPT_CR_NE_WL with the worst value among the loads measured on the - local (outgoing) links for the session and the congestion reports - received from those links. - - Note that the mechanism described in this sub-section does not permit - the monitoring of the load on (outgoing) links at non-PGM-capable - multicast routers. For this reason, NE-Based Worst Link Reports - SHOULD be used in pure PGM topologies only. Otherwise, this - mechanism might fail in detecting congestion. To overcome this - limitation PGM sources MAY use a heuristic that combines NE-Based - Worst Link Reports and Receiver-Based Reports. - -12.3. NE-Based Worst Path Report - - To permit network elements to report a worst path, receivers append - OPT_CR to a NAK with bit OPT_CR_NEP set and OPT_CR_NE_WP set to zero. - The processing of this field is similar to that of OPT_CR_NE_WL with - the difference that, on the reception of a NAK, the value of - OPT_CR_NE_WP is adjusted with the load measured on the interface on - which the NAK was received according to the following formula: - - OPT_CR_NE_WP = if_load + OPT_CR_NE_WP * (100% - if_loss_rate) - - The worst among the adjusted OPT_CR_NE_WP is then written in the - outgoing NAK. This results in a hop-by-hop accumulation of link loss - rates into a path loss rate. - - - - -Speakman, et. al. Experimental [Page 74] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - As with OPT_CR_NE_WL, the congestion report in OPT_CR_NE_WP may be - invalid if the multicast distribution tree includes non-PGM-capable - routers. - -12.4. Receiver-Based Worst Report - - To report a packet loss rate, receivers append OPT_CR to a NAK with - bit OPT_CR_RXP set and OPT_CR_RX_WP set to the packet loss rate. NEs - receiving NAKs that contain OPT_CR_RX_WP process the option and - update per-TSI state related to it as described below. The ultimate - result of the NEs' actions ensures that when a NAK leaves a sub-tree, - OPT_CR_RX_WP contains a congestion report that reflects the load of - the worst receiver in that sub-tree. To achieve this, NEs rewrite - OTP_CR_RE_WP with the worst value among the congestion reports - received on its outgoing links for the session. In addition to this, - OPT_CR_RCVR MUST contain the NLA of the receiver that originally - measured the value of OTP_CR_RE_WP being forwarded. - -12.5. Procedures - Receivers - - To enable the generation of any type of congestion report, receivers - MUST insert OPT_CR in each NAK they generate and provide the - corresponding field (OPT_CR_NE_WL, OPT_CR_NE_WP, OPT_CR_RX_WP). The - specific fields to be reported will be advertised to receivers in - OPT_CRQST on the session's SPMs. Receivers MUST provide only those - options requested in OPT_CRQST. - - Receivers MUST initialize OPT_CR_NE_WL and OPT_CR_NE_WP to 0 and they - MUST initialize OPT_CR_RCVR to their NLA. At the moment of sending - the NAK, they MUST also initialize OPT_CR_LEAD to the leading edge of - the transmission window. - - Additionally, if a receiver generates a NAK with OPT_CR with - OPT_CR_RX_WP, it MUST initialize OPT_CR_RX_WP to the proper value, - internally computed. - -12.6. Procedures - Network Elements - - Network elements start processing each OPT_CR by selecting a - reference SQN in the ODATA space. The reference SQN selected is the - highest SQN known to the NE. Usually this is OPT_CR_LEAD contained - in the NAK received. - - They use the selected SQN to age the value of load measurement as - follows: - - o locally measured load values (e.g. interface loads) are - considered up-to-date - - - -Speakman, et. al. Experimental [Page 75] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - o load values carried in OPT_CR are considered up-to-date and are - not aged so as to be independent of variance in round-trip - times from the network element to the receivers - - o old load values recorded in the NE are exponentially aged - according to the difference between the selected reference SQN - and the reference SQN associated with the old load value. - - The exponential aging is computed so that a recorded value gets - scaled down by a factor exp(-1/2) each time the expected inter-NAK - time elapses. Hence the aging formula must include the current loss - rate as follows: - - aged_loss_rate = loss_rate * exp( - SQN_difference * loss_rate / - 2) - - Note that the quantity 1/loss_rate is the expected SQN_lag between - two NAKs, hence the formula above can also be read as: - - aged_loss_rate = loss_rate * exp( - 1/2 * SQN_difference / - SQN_lag) - - which equates to (loss_rate * exp(-1/2)) when the SQN_difference is - equal to expected SQN_lag between two NAKs. - - All the subsequent computations refer to the aged load values. - - Network elements process OPT_CR by handling the three possible types - of congestion reports independently. - - For each congestion report in an incoming NAK, a new value is - computed to be used in the outgoing NAK: - - o The new value for OPT_CR_NE_WL is the maximum of the load - measured on the outgoing interfaces for the session, the value - of OPT_CR_NE_WL of the incoming NAK, and the value previously - sent upstream (recorded in the NE). All these values are as - obtained after the aging process. - - o The new value for OPT_CR_NE_WP is the maximum of the value - previously sent upstream (after aging) and the value of - OPT_CR_NE_WP in the incoming NAK adjusted with the load on the - interface upon which the NAK was received (as described above). - - o The new value for OPT_CR_RX_WP is the maximum of the value - previously sent upstream (after aging) and the value of - OPT_CR_RX_WP in the incoming NAK. - - - - -Speakman, et. al. Experimental [Page 76] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - o If OPT_CR_RX_WP was selected from the incoming NAK, the new - value for OPT_CR_RCVR is the one in the incoming NAK. - Otherwise it is the value previously sent upstream. - - o The new value for OPT_CR_LEAD is the reference SQN selected for - the aging procedure. - -12.6.1. Overriding Normal Suppression Rules - - Normal suppression rules hold to determine if a NAK should be - forwarded upstream or not. However if any of the outgoing congestion - reports has changed by more than 5% relative to the one previously - sent upstream, this new NAK is not suppressed. - -12.6.2. Link Load Measurement - - PGM routers monitor the load on all their outgoing links and record - it in the form of per-interface loss rate statistics. "load" MUST be - interpreted as the percentage of the packets meant to be forwarded on - the interface that were dropped. Load statistics refer to the - aggregate traffic on the links and not to PGM traffic only. - - This document does not specify the algorithm to be used to collect - such statistics, but requires that such algorithm provide both - accuracy and responsiveness in the measurement process. As far as - accuracy is concerned, the expected measurement error SHOULD be - upper-limited (e.g. less than than 10%). As far as responsiveness is - concerned, the measured load SHOULD converge to the actual value in a - limited time (e.g. converge to 90% of the actual value in less than - 200 milliseconds), when the instantaneous offered load changes. - Whenever both requirements cannot be met at the same time, accuracy - SHOULD be traded for responsiveness. - - - - - - - - - - - - - - - - - - - -Speakman, et. al. Experimental [Page 77] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -12.7. Packet Formats - -12.7.1. OPT_CR - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| L P R| - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Congestion Report Reference SQN | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | NE Worst Link | NE Worst Path | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Rcvr Worst Path | Reserved | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | NLA AFI | Reserved | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Worst Receiver's NLA ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - - Option Type = 0x10 - - Option Length = 20 octets + NLA length - - L OPT_CR_NEL bit : set indicates OPT_CR_NE_WL is being reported - - P OPT_CR_NEP bit : set indicates OPT_CR_NE_WP is being reported - - R OPT_CR_RXP bit : set indicates OPT_CR_RX_WP is being reported - - Congestion Report Reference SQN (OPT_CR_LEAD). - - A SQN in the ODATA space that serves as a temporal reference point - for the load report values. - - NE Worst Link (OPT_CR_NE_WL). - - Reports the load in the worst link as detected though NE internal - measurements - - NE Worst Path (OPT_CR_NE_WP). - - Reports the load in the worst end-to-end path as detected though - NE internal measurements - - - - - - - -Speakman, et. al. Experimental [Page 78] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Rcvr Worst Path (OPT_CR_RX_WP). - - Reports the load in the worst end-to-end path as detected by - receivers - - Worst Receiver's NLA (OPT_CR_RCVR). - - The unicast address of the receiver that generated the worst - OPT_CR_RX_WP. - - OPT_CR MAY be appended only to NAKs. - - OPT-CR is network-significant. - -12.7.2. OPT_CRQST - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| L P R| - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x11 - - Option Length = 4 octets - - L OPT_CRQST_NEL bit : set indicates OPT_CR_NE_WL is being - requested - - P OPT_CRQST_NEP bit : set indicates OPT_CR_NE_WP is being - requested - - R OPT_CRQST_RXP bit : set indicates OPT_CR_RX_WP is being - requested - - OPT_CRQST MAY be appended only to SPMs. - - OPT-CRQST is network-significant. - -13. Appendix C - SPM Requests - -13.1. Introduction - - SPM Requests (SPMRs) MAY be used to solicit an SPM from a source in a - non-implosive way. The typical application is for late-joining - receivers to solicit SPMs directly from a source in order to be able - to NAK for missing packets without having to wait for a regularly - scheduled SPM from that source. - - - -Speakman, et. al. Experimental [Page 79] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -13.2. Overview - - Allowing for SPMR implosion protection procedures, a receiver MAY - unicast an SPMR to a source to solicit the most current session, - window, and path state from that source any time after the receiver - has joined the group. A receiver may learn the TSI and source to - which to direct the SPMR from any other PGM packet it receives in the - group, or by any other means such as from local configuration or - directory services. The receiver MUST use the usual SPM procedures - to glean the unicast address to which it should direct its NAKs from - the solicited SPM. - -13.3. Packet Contents - - This section just provides enough short-hand to make the Procedures - intelligible. For the full details of packet contents, please refer - to Packet Formats below. - -13.3.1. SPM Requests - - SPMRs are transmitted by receivers to solicit SPMs from a source. - - SPMs are unicast to a source and contain: - - SPMR_TSI the source-assigned TSI for the session to which the - SPMR corresponds - -13.4. Procedures - Sources - - A source MUST respond immediately to an SPMR with the corresponding - SPM rate limited to once per IHB_MIN per TSI. The corresponding SPM - matches SPM_TSI to SPMR_TSI and SPM_DPORT to SPMR_DPORT. - -13.5. Procedures - Receivers - - To moderate the potentially implosive behavior of SPMRs at least on a - densely populated subnet, receivers MUST use the following back-off - and suppression procedure based on multicasting the SPMR with a TTL - of 1 ahead of and in addition to unicasting the SPMR to the source. - The role of the multicast SPMR is to suppress the transmission of - identical SPMRs from the subnet. - - More specifically, before unicasting a given SPMR, receivers MUST - choose a random delay on SPMR_BO_IVL (~250 msecs) during which they - listen for a multicast of an identical SPMR. If a receiver does not - see a matching multicast SPMR within its chosen random interval, it - MUST first multicast its own SPMR to the group with a TTL of 1 before - then unicasting its own SPMR to the source. If a receiver does see a - - - -Speakman, et. al. Experimental [Page 80] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - matching multicast SPMR within its chosen random interval, it MUST - refrain from unicasting its SPMR and wait instead for the - corresponding SPM. - - In addition, receipt of the corresponding SPM within this random - interval SHOULD cancel transmission of an SPMR. - - In either case, the receiver MUST wait at least SPMR_SPM_IVL before - attempting to repeat the SPMR by choosing another delay on - SPMR_BO_IVL and repeating the procedure above. - - The corresponding SPMR matches SPMR_TSI to SPMR_TSI and SPMR_DPORT to - SPMR_DPORT. The corresponding SPM matches SPM_TSI to SPMR_TSI and - SPM_DPORT to SPMR_DPORT. - -13.6. SPM Requests - - SPMR: - - SPM Requests are sent by receivers to request the immediate - transmission of an SPM for the given TSI from a source. - - The network-header source address of an SPMR is the unicast NLA of - the entity that originates the SPMR. - - The network-header destination address of an SPMR is the unicast NLA - of the source from which the corresponding SPM is requested. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source Port | Destination Port | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Options | Checksum | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Global Source ID ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ... Global Source ID | TSDU Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Option Extensions when present ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... - - Source Port: - - SPMR_SPORT - - Data-Destination Port - - - - -Speakman, et. al. Experimental [Page 81] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Destination Port: - - SPMR_DPORT - - Data-Source Port, together with Global Source ID forms SPMR_TSI - - Type: - - SPMR_TYPE = 0x0C - - Global Source ID: - - SPMR_GSI - - Together with Source Port forms - - SPMR_TSI - -14. Appendix D - Poll Mechanism - -14.1. Introduction - - These procedures provide PGM network elements and sources with the - ability to poll their downstream PGM neighbors to solicit replies - in an implosion-controlled way. - - Both general polls and specific polls are possible. The former - provide a PGM (parent) node with a way to check if there are any - PGM (children) nodes connected to it, both network elements and - receivers, and to estimate their number. The latter may be used - by PGM parent nodes to search for nodes with specific properties - among its PGM children. An example of application for this is DLR - discovery. - - Polling is implemented using two additional PGM packets: - - POLL a Poll Request that PGM parent nodes multicast to the group to - perform the poll. Similarly to NCFs, POLL packets stop at the - first PGM node they reach, as they are not forwarded by PGM - network elements. - - POLR a Poll Response that PGM children nodes (either network elements - or receivers) use to reply to a Poll Request by addressing it - to the NLA of the interface from which the triggering POLL was - sent. - - - - - - -Speakman, et. al. Experimental [Page 82] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - The polling mechanism dictates that PGM children nodes that receive a - POLL packet reply to it only if certain conditions are satisfied and - ignore the POLL otherwise. Two types of condition are possible: a - random condition that defines a probability of replying for the - polled child, and a deterministic condition. Both the random - condition and the deterministic condition are controlled by the - polling PGM parent node by specifying the probability of replying and - defining the deterministic condition(s) respectively. Random-only - poll, deterministic-only poll or a combination of the two are - possible. - - The random condition in polls allows the prevention of implosion of - replies by controlling their number. Given a probability of replying - P and assuming that each receiver makes an independent decision, the - number of expected replies to a poll is P*N where N is the number of - PGM children relative to the polling PGM parent. The polling node - can control the number of expected replies by specifying P in the - POLL packet. - -14.2. Packet Contents - - This section just provides enough short-hand to make the Procedures - intelligible. For the full details of packet contents, please refer - to Packet Formats below. - -14.2.1. POLL (Poll Request) - - POLL_SQN a sequence number assigned sequentially by the polling - parent in unit increments and scoped by POLL_PATH and - the TSI of the session. - - POLL_ROUND a poll round sequence number. Multiple poll rounds - are possible within a POLL_SQN. - - POLL_S_TYPE the sub-type of the poll request - - POLL_PATH the network-layer address (NLA) of the interface on - the PGM network element or source on which the POLL is - transmitted - - POLL_BO_IVL the back-off interval that MUST be used to compute the - random back-off time to wait before sending the - response to a poll. POLL_BO_IVL is expressed in - microseconds. - - POLL_RAND a random string used to implement the randomness in - replying - - - - -Speakman, et. al. Experimental [Page 83] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - POLL_MASK a bit-mask used to determine the probability of random - replies - - Poll request MAY also contain options which specify deterministic - conditions for the reply. No options are currently defined. - -14.2.2. POLR (Poll Response) - - POLR_SQN POLL_SQN of the poll request for which this is a reply - - POLR_ROUND POLL_ROUND of the poll request for which this is a - reply - - Poll response MAY also contain options. No options are currently - defined. - -14.3. Procedures - General - -14.3.1. General Polls - - General Polls may be used to check for and count PGM children that - are 1 PGM hop downstream of an interface of a given node. They have - POLL_S_TYPE equal to PGM_POLL_GENERAL. PGM children that receive a - general poll decide whether to reply to it only based on the random - condition present in the POLL. - - To prevent response implosion, PGM parents that initiate a general - poll SHOULD establish the probability of replying to the poll, P, so - that the expected number of replies is contained. The expected - number of replies is N * P, where N is the number of children. To be - able to compute this number, PGM parents SHOULD already have a rough - estimate of the number of children. If they do not have a recent - estimate of this number, they SHOULD send the first poll with a very - low probability of replying and increase it in subsequent polls in - order to get the desired number of replies. - - To prevent poll-response implosion caused by a sudden increase in the - children population occurring between two consecutive polls with - increasing probability of replying, PGM parents SHOULD use poll - rounds. Poll rounds allow PGM parents to "freeze" the size of the - children population when they start a poll and to maintain it - constant across multiple polls (with the same POLL_SQN but different - POLL_ROUND). This works by allowing PGM children to respond to a - poll only if its POLL_ROUND is zero or if they have previously - received a poll with the same POLL_SQN and POLL_ROUND equal to zero. - - - - - - -Speakman, et. al. Experimental [Page 84] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - In addition to this PGM children MUST observe a random back-off in - replying to a poll. This spreads out the replies in time and allows - a PGM parent to abort the poll if too many replies are being - received. To abort an ongoing poll a PGM parent MUST initiate - another poll with different POLL_SQN. PGM children that receive a - POLL MUST cancel any pending reply for POLLs with POLL_SQN different - from the one of the last POLL received. - - For a given poll with probability of replying P, a PGM parent - estimates the number of children as M / P, where M is the number of - responses received. PGM parents SHOULD keep polling periodically and - use some average of the result of recent polls as their estimate for - the number of children. - -14.3.2. Specific Polls - - Specific polls provide a way to search for PGM children that comply - to specific requisites. As an example specific poll could be used to - search for down-stream DLRs. A specific poll is characterized by a - POLL_S_TYPE different from PGM_POLL_GENERAL. PGM children decide - whether to reply to a specific poll or not based on the POLL_S_TYPE, - on the random condition and on options possibly present in the POLL. - The way options should be interpreted is defined by POLL_S_TYPE. The - random condition MUST be interpreted as an additional condition to be - satisfied. To disable the random condition PGM parents MUST specify - a probability of replying P equal to 1. - - PGM children MUST ignore a POLL packet if they do not understand - POLL_S_TYPE. Some specific POLL_S_TYPE may also require that the - children ignore a POLL if they do not fully understand all the PGM - options present in the packet. - -14.4. Procedures - PGM Parents (Sources or Network Elements) - - A PGM parent (source or network element), that wants to poll the - first PGM-hop children connected to one of its outgoing interfaces - MUST send a POLL packet on that interface with: - - POLL_SQN equal to POLL_SQN of the last POLL sent incremented by - one. If poll rounds are used, this must be equal to - POLL_SQN of the last group of rounds incremented by - one. - - POLL_ROUND The round of the poll. If the poll has a single - round, this must be zero. If the poll has multiple - rounds, this must be one plus the last POLL_ROUND for - the same POLL_SQN, or zero if this is the first round - within this POLL_SQN. - - - -Speakman, et. al. Experimental [Page 85] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - POLL_S_TYPE the type of the poll. For general poll use - PGM_POLL_GENERAL - - POLL_PATH set to the NLA of the outgoing interface - - POLL_BO_IVL set to the wanted reply back-off interval. As far as - the choice of this is concerned, using NAK_BO_IVL is - usually a conservative option, however a smaller value - MAY be used, if the number of expected replies can be - determined with a good confidence or if a - conservatively low probability of reply (P) is being - used (see POLL_MASK next). When the number of - expected replies is unknown, a large POLL_BO_IVL - SHOULD be used, so that the poll can be effectively - aborted if the number of replies being received is too - large. - - POLL_RAND MUST be a random string re-computed each time a new - poll is sent on a given interface - - POLL_MASK determines the probability of replying, P, according - to the relationship P = 1 / ( 2 ^ B ), where B is the - number of bits set in POLL_MASK [15]. If this is a - deterministic poll, B MUST be 0, i.e. POLL_MASK MUST - be a all-zeroes bit-mask. - - Nota Bene: POLLs transmitted by network elements MUST bear the - ODATA source's network-header source address, not the network - element's NLA. POLLs MUST also be transmitted with the IP - - Router Alert Option [6], to be allow PGM network element to - intercept them. - - A PGM parent that has started a poll by sending a POLL packet SHOULD - wait at least POLL_BO_IVL before starting another poll. During this - interval it SHOULD collect all the valid response (the one with - POLR_SQN and POLR_ROUND matching with the outstanding poll) and - process them at the end of the collection interval. - - A PGM parent SHOULD observe the rules mentioned in the description of - general procedures, to prevent implosion of response. These rules - should in general be observed both for generic polls and specific - polls. The latter however can be performed using deterministic poll - (with no implosion prevention) if the expected number of replies is - known to be small. A PGM parent that issue a generic poll with the - intent of estimating the children population size SHOULD use poll - rounds to "freeze" the children that are involved in the measure - process. This allows the sender to "open the door wider" across - - - -Speakman, et. al. Experimental [Page 86] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - subsequent rounds (by increasing the probability of response), - without fear of being flooded by late joiners. Note the use of - rounds has the drawback of introducing additional delay in the - estimate of the population size, as the estimate obtained at the end - of a round-group refers to the condition present at the time of the - first round. - - A PGM parent that has started a poll SHOULD monitor the number of - replies during the collection phase. If this become too large, the - PGM parent SHOULD abort the poll by immediately starting a new poll - (different POLL_SQN) and specifying a very low probability of - replying. - - - When polling is being used to estimate the receiver population for - the purpose of calculating NAK_BO_IVL, OPT_NAK_BO_IVL (see 16.4.1 - below) MUST be appended to SPMs, MAY be appended to NCFs and POLLs, - and in all cases MUST have NAK_BO_IVL_SQN set to POLL_SQN of the most - recent complete round of polls, and MUST bear that round's - corresponding derived value of NAK_BAK_IVL. In this way, - OPT_NAK_BO_IVL provides a current value for NAK_BO_IVL at the same - time as information is being gathered for the calculation of a future - value of NAK_BO_IVL. - -14.5. Procedures - PGM Children (Receivers or Network Elements) - - PGM receivers and network elements MUST compute a 32-bit random node - identifier (RAND_NODE_ID) at startup time. When a PGM child - (receiver or network element) receives a POLL it MUST use its - RAND_NODE_ID to match POLL_RAND of incoming POLLs. The match is - limited to the bits specified by POLL_MASK. If the incoming POLL - contain a POLL_MASK made of all zeroes, the match is successful - despite the content of POLL_RAND (deterministic reply). If the match - fails, then the receiver or network element MUST discard the POLL - without any further action, otherwise it MUST check the fields - POLL_ROUND, POLL_S_TYPE and any PGM option included in the POLL to - determine whether it SHOULD reply to the poll. - - If POLL_ROUND is non-zero and the PGM receiver has not received a - previous poll with the same POLL_SQN and a zero POLL_ROUND, it MUST - discard the poll without further action. - - If POLL_S_TYPE is equal to PGM_POLL_GENERAL, the PGM child MUST - schedule a reply to the POLL despite the presence of PGM options on - the POLL packet. - - - - - - -Speakman, et. al. Experimental [Page 87] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - If POLL_S_TYPE is different from PGM_POLL_GENERAL, the decision on - whether a reply should be scheduled depends on the actual type and on - the options possibly present in the POLL. - - If POLL_S_TYPE is unknown to the recipient of the POLL, it MUST NOT - reply and ignore the poll. Currently the only POLL_S_TYPE defined - are PGM_POLL_GENERAL and PGM_POLL_DLR. - - If a PGM receiver or network element has decided to reply to a POLL, - it MUST schedule the transmission of a single POLR at a random time - in the future. The random delay is chosen in the interval [0, - POLL_BO_IVL]. POLL_BO_IVL is the one contained in the POLL received. - When this timer expires, it MUST send a POLR using POLL_PATH of the - received POLL as destination address. POLR_SQN MUST be equal to - POLL_SQN and POLR_ROUND must be equal to POLL_ROUND. The POLR MAY - contain PGM options according to the semantic of POLL_S_TYPE or the - semantic of PGM options possibly present in the POLL. If POLL_S_TYPE - is PGM_POLL_GENERAL no option is REQUIRED. - - A PGM receiver or network element MUST cancel any pending - transmission of POLRs if a new POLL is received with POLL_SQN - different from POLR_SQN of the poll that scheduled POLRs. - -14.6. Constant Definition - - The POLL_S_TYPE values currently defined are: - - PGM_POLL_GENERAL 0 - - PGM_POLL_DLR 1 - -14.7. Packet Formats - - The packet formats described in this section are transport-layer - headers that MUST immediately follow the network-layer header in the - packet. - - The descriptions of Data-Source Port, Data-Destination Port, Options, - Checksum, Global Source ID (GSI), and TSDU Length are those provided - in Section 8. - -14.7.1. Poll Request - - POLL are sent by PGM parents (sources or network elements) to - initiate a poll among their first PGM-hop children. - - - - - - -Speakman, et. al. Experimental [Page 88] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - POLLs are sent to the ODATA multicast group. The network-header - source address of a POLL is the ODATA source's NLA. POLL MUST be - transmitted with the IP Router Alert Option. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source Port | Destination Port | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Options | Checksum | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Global Source ID ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ... Global Source ID | TSDU Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | POLL's Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | POLL's Round | POLL's Sub-type | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | NLA AFI | Reserved | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Path NLA ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - | POLL's Back-off Interval | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Random String | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Matching Bit-Mask | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Option Extensions when present ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Source Port: - - POLL_SPORT - - Data-Source Port, together with POLL_GSI forms POLL_TSI - - Destination Port: - - POLL_DPORT - - Data-Destination Port - - Type: - - POLL_TYPE = 0x01 - - - - -Speakman, et. al. Experimental [Page 89] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Global Source ID: - - POLL_GSI - - Together with POLL_SPORT forms POLL_TSI - - POLL's Sequence Number - - POLL_SQN - - The sequence number assigned to the POLL by the originator. - - POLL's Round - - POLL_ROUND - - The round number within the poll sequence number. - - POLL's Sub-type - - POLL_S_TYPE - - The sub-type of the poll request. - - Path NLA: - - POLL_PATH - - The NLA of the interface on the source or network element on which - this POLL was forwarded. - - POLL's Back-off Interval - - POLL_BO_IVL - - The back-off interval used to compute a random back-off for the - reply, expressed in microseconds. - - Random String - - POLL_RAND - - A random string used to implement the random condition in - replying. - - - - - - - -Speakman, et. al. Experimental [Page 90] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Matching Bit-Mask - - POLL_MASK - - A bit-mask used to determine the probability of random replies. - -14.7.2. Poll Response - - POLR are sent by PGM children (receivers or network elements) to - reply to a POLL. - - The network-header source address of a POLR is the unicast NLA of the - entity that originates the POLR. The network-header destination - address of a POLR is initialized by the originator of the POLL to the - unicast NLA of the upstream PGM element (source or network element) - known from the POLL that triggered the POLR. - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source Port | Destination Port | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Options | Checksum | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Global Source ID ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | ... Global Source ID | TSDU Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | POLR's Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | POLR's Round | reserved | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Option Extensions when present ... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Source Port: - - POLR_SPORT - - Data-Destination Port - - Destination Port: - - POLR_DPORT - - Data-Source Port, together with Global Source ID forms POLR_TSI - - - - - -Speakman, et. al. Experimental [Page 91] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Type: - - POLR_TYPE = 0x02 - - Global Source ID: - - POLR_GSI - - Together with POLR_DPORT forms POLR_TSI - - POLR's Sequence Number - - POLR_SQN - - The sequence number (POLL_SQN) of the POLL packet for which this - is a reply. - - POLR's Round - - POLR_ROUND - - The round number (POLL_ROUND) of the POLL packet for which this is - a reply. - -15. Appendix E - Implosion Prevention - -15.1. Introduction - - These procedures are intended to prevent NAK implosion and to limit - its extent in case of the loss of all or part of the suppressing - multicast distribution tree. They also provide a means to adaptively - tune the NAK back-off interval, NAK_BO_IVL. - - The PGM virtual topology is established and refreshed by SPMs. - Between one SPM and the next, PGM nodes may have an out-of-date view - of the PGM topology due to multicast routing changes, flapping, or a - link/router failure. If any of the above happens relative to a PGM - parent node, a potential NAK implosion problem arises because the - parent node is unable to suppress the generation of duplicate NAKs as - it cannot reach its children using NCFs. The procedures described - below introduce an alternative way of performing suppression in this - case. They also attempt to prevent implosion by adaptively tuning - NAK_BO_IVL. - - - - - - - - -Speakman, et. al. Experimental [Page 92] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -15.2. Tuning NAK_BO_IVL - - Sources and network elements continuously monitor the number of - duplicated NAKs received and use this observation to tune the NAK - back-off interval (NAK_BO_IVL) for the first PGM-hop receivers - connected to them. Receivers learn the current value of NAK_BO_IVL - through OPT_NAK_BO_IVL appended to NCFs or SPMs. - -15.2.1. Procedures - Sources and Network Elements - - For each TSI, sources and network elements advertise the value of - NAK_BO_IVL that their first PGM-hop receivers should use. They - advertise a separate value on all the outgoing interfaces for the TSI - and keep track of the last values advertised. - - For each interface and TSI, sources and network elements count the - number of NAKs received for a specific repair state (i.e., per - sequence number per TSI) from the time the interface was first added - to the repair state list until the time the repair state is - discarded. Then they use this number to tune the current value of - NAK_BO_IVL as follows: - - Increase the current value NAK_BO_IVL when the first duplicate NAK - is received for a given SQN on a particular interface. - - Decrease the value of NAK_BO_IVL if no duplicate NAKs are received on - a particular interface for the last NAK_PROBE_NUM measurements where - each measurement corresponds to the creation of a new repair state. - - An upper and lower limit are defined for the possible value of - NAK_BO_IVL at any time. These are NAK_BO_IVL_MAX and NAK_BO_IVL_MIN - respectively. The initial value that should be used as a starting - point to tune NAK_BO_IVL is NAK_BO_IVL_DEFAULT. The policies - RECOMMENDED for increasing and decreasing NAK_BO_IVL are multiplying - by two and dividing by two respectively. - - Sources and network elements advertise the current value of - NAK_BO_IVL through the OPT_NAK_BO_IVL that they append to NCFs. They - MAY also append OPT_NAK_BO_IVL to outgoing SPMs. - - In order to avoid forwarding the NAK_BO_IVL advertised by the parent, - network elements must be able to recognize OPT_NAK_BO_IVL. Network - elements that receive SPMs containing OPT_NAK_BO_IVL MUST either - remove the option or over-write its content (NAK_BO_IVL) with the - current value of NAK_BO_IVL for the outgoing interface(s), before - forwarding the SPMs. - - - - - -Speakman, et. al. Experimental [Page 93] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Sources MAY advertise the value of NAK_BO_IVL_MAX and NAK_BO_IVL_MIN - to the session by appending a OPT_NAK_BO_RNG to SPMs. - -15.2.2. Procedures - Receivers - - Receivers learn the value of NAK_BO_IVL to use through the option - OPT_NAK_BO_IVL, when this is present in NCFs or SPMs. A value for - NAK_BO_IVL learned from OPT_NAK_BO_IVL MUST NOT be used by a receiver - unless either NAK_BO_IVL_SQN is zero, or the receiver has seen - POLL_RND == 0 for POLL_SQN =< NAK_BO_IVL_SQN within half the sequence - number space. The initial value of NAK_BO_IVL is set to - NAK_BO_IVL_DEFAULT. - - Receivers that receive an SPM containing OPT_NAK_BO_RNG MUST use its - content to set the local values of NAK_BO_IVL_MAX and NAK_BO_IVL_MIN. - -15.2.3. Adjusting NAK_BO_IVL in the absence of NAKs - - Monitoring the number of duplicate NAKs provides a means to track - indirectly the change in the size of first PGM-hop receiver - population and adjust NAK_BO_IVL accordingly. Note that the number - of duplicate NAKs for a given SQN is related to the number of first - PGM-hop children that scheduled (or forwarded) a NAK and not to the - absolute number of first PGM-hop children. This mechanism, however, - does not work in the absence of packet loss, hence a large number of - duplicate NAKs is possible after a period without NAKs, if many new - receivers have joined the session in the meanwhile. To address this - issue, PGM Sources and network elements SHOULD periodically poll the - number of first PGM-hop children using the "general poll" procedures - described in Appendix D. If the result of the polls shows that the - population size has increased significantly during a period without - NAKs, they SHOULD increase NAK_BO_IVL as a safety measure. - -15.3. Containing Implosion in the Presence of Network Failures - -15.3.1. Detecting Network Failures - - In some cases PGM (parent) network elements can promptly detect the - loss of all or part of the suppressing multicast distribution tree - (due to network failures or route changes) by checking their - multicast connectivity, when they receive NAKs. In some other cases - this is not possible as the connectivity problem might occur at some - other non-PGM node downstream or might take time to reflect in the - multicast routing table. To address these latter cases, PGM uses a - simple heuristic: a failure is assumed for a TSI when the count of - duplicated NAKs received for a repair state reaches the value - DUP_NAK_MAX in one of the interfaces. - - - - -Speakman, et. al. Experimental [Page 94] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -15.3.2. Containing Implosion - - When a PGM source or network element detects or assumes a failure for - which it looses multicast connectivity to down-stream PGM agents - (either receivers or other network elements), it sends unicast NCFs - to them in response to NAKs. Downstream PGM network elements which - receive unicast NCFs and have multicast connectivity to the multicast - session send special SPMs to prevent further NAKs until a regular SPM - sent by the source refreshes the PGM tree. - - Procedures - Sources and Network Elements - - PGM sources or network elements which detect or assume a failure that - prevents them from reaching down-stream PGM agents through multicast - NCFs revert to confirming NAKs through unicast NCFs for a given TSI - on a given interface. If the PGM agent is the source itself, than it - MUST generate an SPM for the TSI, in addition to sending the unicast - NCF. - - Network elements MUST keep using unicast NCFs until they receive a - regular SPM from the source. - - When a unicast NCF is sent for the reasons described above, it MUST - contain the OPT_NBR_UNREACH option and the OPT_PATH_NLA option. - OPT_NBR_UNREACH indicates that the sender is unable to use multicast - to reach downstream PGM agents. OPT_PATH_NLA carries the network - layer address of the NCF sender, namely the NLA of the interface - leading to the unreachable subtree. - - When a PGM network element receives an NCF containing the - OPT_NBR_UNREACH option, it MUST ignore it if OPT_PATH_NLA specifies - an upstream neighbour different from the one currently known to be - the upstream neighbor for the TSI. Assuming the network element - matches the OPT_PATH_NLA of the upstream neighbour address, it MUST - stop forwarding NAKs for the TSI until it receives a regular SPM for - the TSI. In addition, it MUST also generate a special SPM to prevent - downstream receivers from sending more NAKs. This special SPM MUST - contain the OPT_NBR_UNREACH option and SHOULD have a SPM_SQN equal to - SPM_SQN of the last regular SPM forwarded. The OPT_NBR_UNREACH - option invalidates the windowing information in SPMs (SPM_TRAIL and - SPM_LEAD). The PGM network element that adds the OPT_NBR_UNREACH - option SHOULD invalidate the windowing information by setting - SPM_TRAIL to 0 and SPM_LEAD to 0x80000000. - - PGM network elements which receive an SPM containing the - OPT_NBR_UNREACH option and whose SPM_PATH matches the currently known - PGM parent, MUST forward them in the normal way and MUST stop - - - - -Speakman, et. al. Experimental [Page 95] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - forwarding NAKs for the TSI until they receive a regular SPM for the - TSI. If the SPM_PATH does not match the currently known PGM parent, - the SPM containing the OPT_NBR_UNREACH option MUST be ignored. - - Procedures - Receivers - - PGM receivers which receive either an NCF or an SPM containing the - OPT_NBR_UNREACH option MUST stop sending NAKs until a regular SPM is - received for the TSI. - - On reception of a unicast NCF containing the OPT_NBR_UNREACH option - receivers MUST generate a multicast copy of the packet with TTL set - to one on the RPF interface for the data source. This will prevent - other receivers in the same subnet from generating NAKs. - - Receivers MUST ignore windowing information in SPMs which contain the - OPT_NBR_UNREACH option. - - Receivers MUST ignore NCFs containing the OPT_NBR_UNREACH option if - the OPT_PATH_NLA specifies a neighbour different than the one - currently know to be the PGM parent neighbour. Similarly receivers - MUST ignore SPMs containing the OPT_NBR_UNREACH option if SPM_PATH - does not match the current PGM parent. - -15.4. Packet Formats - -15.4.1. OPT_NAK_BO_IVL - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | NAK Back-Off Interval | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | NAK Back-Off Interval SQN | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x04 - - NAK Back-Off Interval - - The value of NAK-generation Back-Off Interval in microseconds. - - - - - - - - -Speakman, et. al. Experimental [Page 96] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - NAK Back-Off Interval Sequence Number - - The POLL_SQN to which this value of NAK_BO_IVL corresponds. Zero - is reserved and means NAK_BO_IVL is NOT being determined through - polling (see Appendix D) and may be used immediately. Otherwise, - NAK_BO_IVL MUST NOT be used unless the receiver has also seen - POLL_ROUND = 0 for POLL_SQN =< NAK_BO_IVL_SQN within half the - sequence number space. - - OPT_NAK_BO_IVL MAY be appended to NCFs, SPMs, or POLLs. - - OPT_NAK_BO_IVL is network-significant. - -15.4.2. OPT_NAK_BO_RNG - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Maximum NAK Back-Off Interval | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Minimum NAK Back-Off Interval | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x05 - - Maximum NAK Back-Off Interval - - The maximum value of NAK-generation Back-Off Interval in - microseconds. - - Minimum NAK Back-Off Interval - - The minimum value of NAK-generation Back-Off Interval in - microseconds. - - OPT_NAK_BO_RNG MAY be appended to SPMs. - - OPT_NAK_BO_RNG is network-significant. - -15.4.3. OPT_NBR_UNREACH - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - - -Speakman, et. al. Experimental [Page 97] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Option Type = 0x0B - - When present in SPMs, it invalidates the windowing information. - - OPT_NBR_UNREACH MAY be appended to SPMs and NCFs. - - OPT_NBR_UNREACH is network-significant. - -15.4.4. OPT_PATH_NLA - Packet Extension Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |E| Option Type | Option Length |Reserved |F|OPX|U| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Path NLA | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Option Type = 0x0C - - Path NLA - - The NLA of the interface on the originating PGM network element - that it uses to send multicast SPMs to the recipient of the packet - containing this option. - - OPT_PATH_NLA MAY be appended to NCFs. - - OPT_PATH_NLA is network-significant. - -16. Appendix F - Transmit Window Example - - Nota Bene: The concept of and all references to the increment - window (TXW_INC) and the window increment (TXW_ADV_SECS) - throughout this document are for illustrative purposes only. They - provide the shorthand with which to describe the concept of - advancing the transmit window without also implying any particular - implementation or policy of advancement. - - The size of the transmit window in seconds is simply TXW_SECS. The - size of the transmit window in bytes (TXW_BYTES) is (TXW_MAX_RTE * - TXW_SECS). The size of the transmit window in sequence numbers - (TXW_SQNS) is (TXW_BYTES / bytes-per-packet). - - The fraction of the transmit window size (in seconds of data) by - which the transmit window is advanced (TXW_ADV_SECS) is called the - window increment. The trailing (oldest) such fraction of the - transmit window itself is called the increment window. - - - -Speakman, et. al. Experimental [Page 98] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - In terms of sequence numbers, the increment window is the range of - sequence numbers that will be the first to be expired from the - transmit window. The trailing (or left) edge of the increment window - is just TXW_TRAIL, the trailing (or left) edge of the transmit - window. The leading (or right) edge of the increment window - (TXW_INC) is defined as one less than the sequence number of the - first data packet transmitted by the source TXW_ADV_SECS after - transmitting TXW_TRAIL. - - A data packet is described as being "in" the transmit or increment - window, respectively, if its sequence number is in the range defined - by the transmit or increment window, respectively. - - The transmit window is advanced across the increment window by the - source when it increments TXW_TRAIL to TXW_INC. When the transmit - window is advanced across the increment window, the increment window - is emptied (i.e., TXW_TRAIL is momentarily equal to TXW_INC), begins - to refill immediately as transmission proceeds, is full again - TXW_ADV_SECS later (i.e., TXW_TRAIL is separated from TXW_INC by - TXW_ADV_SECS of data), at which point the transmit window is advanced - again, and so on. - -16.1. Advancing across the Increment Window - - In anticipation of advancing the transmit window, the source starts a - timer TXW_ADV_IVL_TMR which runs for time period TXW_ADV_IVL. - TXW_ADV_IVL has a value in the range (0, TXW_ADV_SECS). The value - MAY be configurable or MAY be determined statically by the strategy - used for advancing the transmit window. - - When TXW_ADV_IVL_TMR is running, a source MAY reset TXW_ADV_IVL_TMR - if NAKs are received for packets in the increment window. In - addition, a source MAY transmit RDATA in the increment window with - priority over other data within the transmit window. - - When TXW_ADV_IVL_TMR expires, a source SHOULD advance the trailing - edge of the transmit window from TXW_TRAIL to TXW_INC. - - Once the transmit window is advanced across the increment window, - SPM_TRAIL, OD_TRAIL and RD_TRAIL are set to the new value of - TXW_TRAIL in all subsequent transmitted packets, until the next - window advancement. - - PGM does not constrain the strategies that a source may use for - advancing the transmit window. The source MAY implement any scheme - or number of schemes. Three suggested strategies are outlined here. - - - - - -Speakman, et. al. Experimental [Page 99] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Consider the following example: - - Assuming a constant transmit rate of 128kbps and a constant data - packet size of 1500 bytes, if a source maintains the past 30 - seconds of data for repair and increments its transmit window in 5 - second increments, then - - TXW_MAX_RTE = 16kBps - TXW_ADV_SECS = 5 seconds, - TXW_SECS = 35 seconds, - TXW_BYTES = 560kB, - TXW_SQNS = 383 (rounded up), - - and the size of the increment window in sequence numbers - (TXW_MAX_RTE * TXW_ADV_SECS / 1500) = 54 (rounded down). - - Continuing this example, the following is a diagram of the transmit - window and the increment window therein in terms of sequence numbers. - - - TXW_TRAIL TXW_LEAD - | | - | | - |--|--------------- Transmit Window -------------|----| - v | | v - v v - n-1 | n | n+1 | ... | n+53 | n+54 | ... | n+381 | n+382 | n+383 - ^ - ^ | ^ - |--- Increment Window|---| - | - | - TXW_INC - - So the values of the sequence numbers defining these windows are: - - TXW_TRAIL = n - TXW_INC = n+53 - TXW_LEAD = n+382 - - Nota Bene: In this example the window sizes in terms of sequence - numbers can be determined only because of the assumption of a - constant data packet size of 1500 bytes. When the data packet - sizes are variable, more or fewer sequence numbers MAY be consumed - transmitting the same amount (TXW_BYTES) of data. - - So, for a given transport session identified by a TSI, a source - maintains: - - - -Speakman, et. al. Experimental [Page 100] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - TXW_MAX_RTE a maximum transmit rate in kBytes per second, the - cumulative transmit rate of some combination of SPMs, - ODATA, and RDATA depending on the transmit window - advancement strategy - - TXW_TRAIL the sequence number defining the trailing edge of the - transmit window, the sequence number of the oldest - data packet available for repair - - TXW_LEAD the sequence number defining the leading edge of the - transmit window, the sequence number of the most - recently transmitted ODATA packet - - TXW_INC the sequence number defining the leading edge of the - increment window, the sequence number of the most - recently transmitted data packet amongst those that - will expire upon the next increment of the transmit - window - - PGM does not constrain the strategies that a source may use for - advancing the transmit window. A source MAY implement any scheme or - number of schemes. This is possible because a PGM receiver must obey - the window provided by the source in its packets. Three strategies - are suggested within this document. - - In the first, called "Advance with Time", the transmit window - maintains the last TXW_SECS of data in real-time, regardless of - whether any data was sent in that real time period or not. The - actual number of bytes maintained at any instant in time will vary - between 0 and TXW_BYTES, depending on traffic during the last - TXW_SECS. In this case, TXW_MAX_RTE is the cumulative transmit rate - of SPMs and ODATA. - - In the second, called "Advance with Data", the transmit window - maintains the last TXW_BYTES bytes of data for repair. That is, it - maintains the theoretical maximum amount of data that could be - transmitted in the time period TXW_SECS, regardless of when they were - transmitted. In this case, TXW_MAX_RTE is the cumulative transmit - rate of SPMs, ODATA, and RDATA. - - The third strategy leaves control of the window in the hands of the - application. The API provided by a source implementation for this, - could allow the application to control the window in terms of APDUs - and to manually step the window. This gives a form of Application - Level Framing (ALF). In this case, TXW_MAX_RTE is the cumulative - transmit rate of SPMs, ODATA, and RDATA. - - - - - -Speakman, et. al. Experimental [Page 101] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -16.2. Advancing with Data - - In the first strategy, TXW_MAX_RTE is calculated from SPMs and both - ODATA and RDATA, and NAKs reset TXW_ADV_IVL_TMR. In this mode of - operation the transmit window maintains the last TXW_BYTES bytes of - data for repair. That is, it maintains the theoretical maximum - amount of data that could be transmitted in the time period TXW_SECS. - This means that the following timers are not treated as real-time - timers, instead they are "data driven". That is, they expire when - the amount of data that could be sent in the time period they define - is sent. They are the SPM ambient time interval, TXW_ADV_SECS, - TXW_SECS, TXW_ADV_IVL, TXW_ADV_IVL_TMR and the join interval. Note - that the SPM heartbeat timers still run in real-time. - - While TXW_ADV_IVL_TMR is running, a source uses the receipt of a NAK - for ODATA within the increment window to reset timer TXW_ADV_IVL_TMR - to TXW_ADV_IVL so that transmit window advancement is delayed until - no NAKs for data in the increment window are seen for TXW_ADV_IVL - seconds. If the transmit window should fill in the meantime, further - transmissions would be suspended until the transmit window can be - advanced. - - A source MUST advance the transmit window across the increment window - only upon expiry of TXW_ADV_IVL_TMR. - - This mode of operation is intended for non-real-time, messaging - applications based on the receipt of complete data at the expense of - delay. - -16.3. Advancing with Time - - This strategy advances the transmit window in real-time. In this - mode of operation, TXW_MAX_RTE is calculated from SPMs and ODATA only - to maintain a constant data throughput rate by consuming extra - bandwidth for repairs. TXW_ADV_IVL has the value 0 which advances - the transmit window without regard for whether NAKs for data in the - increment window are still being received. - - In this mode of operation, all timers are treated as real-time - timers. - - This mode of operation is intended for real-time, streaming - applications based on the receipt of timely data at the expense of - completeness. - - - - - - - -Speakman, et. al. Experimental [Page 102] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -16.4. Advancing under explicit application control - - Some applications may wish more explicit control of the transmit - window than that provided by the advance with data / time strategies - above. An implementation MAY provide this mode of operation and - allow an application to explicitly control the window in terms of - APDUs. - -17. Appendix G - Applicability Statement - - As stated in the introduction, PGM has been designed with a specific - class of applications in mind in recognition of the fact that a - general solution for reliable multicast has proven elusive. The - applicability of PGM is narrowed further, and perhaps more - significantly, by the prototypical nature of at least four of the - transport elements the protocol incorporates. These are congestion - control, router assist, local retransmission, and a programmatic API - for reliable multicast protocols of this class. At the same time as - standardization efforts address each of these elements individually, - this publication is intended to foster experimentation with these - elements in general, and to inform that standardization process with - results from practise. - - This section briefly describes some of the experimental aspects of - PGM and makes non-normative references to some examples of current - practise based upon them. - - At least 3 different approaches to congestion control can be explored - with PGM: a receiver-feedback based approach, a router-assist based - approach, and layer-coding based approach. The first is supported by - the negative acknowledgement mechanism in PGM augmented by an - application-layer acknowledgement mechanism. The second is supported - by the router exception processing mechanism in PGM. The third is - supported by the FEC mechanisms in PGM. An example of a receiver- - feedback based approach is provided in [16], and a proposal for a - router-assist based approach was proposed in [17]. Open issues for - the researchers include how do each of these approaches behave in the - presence of multiple competing sessions of the same discipline or of - different disciplines, TCP most notably; how do each of them behave - over a particular range of topologies, and over a particular range of - loads; and how do each of them scale as a function of the size of the - receiver population. - - Router assist has applications not just to implosion control and - retransmit constraint as described in this specification, but also to - congestion control as described above, and more generally to any - feature which may be enhanced by access to per-network-element state - and processing. The full range of these features is as yet - - - -Speakman, et. al. Experimental [Page 103] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - unexplored, but a general mechanism for providing router assist in a - transport-protocol independent way (GRA) is a topic of active - research [18]. That effort has been primarily informed by the router - assist component of PGM, and implementation and deployment experience - with PGM will continue to be fed back into the specification and - eventual standardization of GRA. Open questions facing the - researchers ([19], [20], [21]) include how router-based state scales - relative to the feature benefit obtained, how system-wide factors - (such as throughput and retransmit latency) vary relative to the - scale and topology of deployed router assistance, and how incremental - deployment considerations affect the tractability of router-assist - based features. Router assist may have additional implications in - the area of congestion control to the extent that it may be applied - in multi-group layered coding schemes to increase the granularity and - reduce the latency of receiver based congestion control. - - GRA itself explicitly incorporates elements of active networking, and - to the extent that the router assist component of PGM is reflected in - GRA, experimentation with the narrowly defined network-element - functionality of PGM will provide some of the first real world - experience with this promising if controversial technology. - - Local retransmission is not a new idea in general in reliable - multicast, but the specific approach taken in PGM of locating re- - transmitters on the distribution tree for the session, diverting - repair requests from network elements to the re-transmitters, and - then propagating repairs downward from the repair point on the - distribution tree raises interesting questions concerning where to - locate re-transmitters in a given topology, and how network elements - locate those re-transmitters and evaluate their efficiency relative - to other available sources of retransmissions, most notably the - source itself. This particular aspect of PGM, while fully specified, - has only been implemented on the network element side, and awaits a - host-side implementation before questions like these can be - addressed. - - PGM presents the opportunity to develop a programming API for - reliable multicast applications that reflects both those - applications' service requirements as well as the services provided - by PGM in support of those applications that may usefully be made - visible above the transport interface. At least a couple of host- - side implementations of PGM and a concomitant API have been developed - for research purposes ([22], [23]), and are available as open source - explicitly for the kind of experimentation described in this section. - - Perhaps the broadest experiment that PGM can enable in a community of - researchers using a reasonable scale experimental transport protocol - is simply in the definition, implementation, and deployment of IP - - - -Speakman, et. al. Experimental [Page 104] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - multicast applications for which the reliability provided by PGM is a - significant enabler. Experience with such applications will not just - illuminate the value of reliable multicast, but will also provoke - practical examination of and responses to the attendant policy issues - (such as peering, billing, access control, firewalls, NATs, etc.), - and, if successful, will ultimately encourage more wide spread - deployment of IP multicast itself. - -18. Abbreviations - - ACK Acknowledgment - AFI Address Family Indicator - ALF Application Level Framing - APDU Application Protocol Data Unit - ARQ Automatic Repeat reQuest - DLR Designated Local Repairer - GSI Globally Unique Source Identifier - FEC Forward Error Correction - MD5 Message-Digest Algorithm - MTU Maximum Transmission Unit - NAK Negative Acknowledgment - NCF NAK Confirmation - NLA Network Layer Address - NNAK Null Negative Acknowledgment - ODATA Original Data - POLL Poll Request - POLR Poll Response - RDATA Repair Data - RSN Receive State Notification - SPM Source Path Message - SPMR SPM Request - TG Transmission Group - TGSIZE Transmission Group Size - TPDU Transport Protocol Data Unit - TSDU Transport Service Data Unit - TSI Transport Session Identifier - TSN Transmit State Notification - - - - - - - - - - - - - - -Speakman, et. al. Experimental [Page 105] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -19. Acknowledgements - - The design and specification of PGM has been substantially influenced - by reviews and revisions provided by several people who took the time - to read and critique this document. These include, in alphabetical - order: - - Bob Albrightson - Joel Bion - Mark Bowles - Steve Deering - Tugrul Firatli - Dan Harkins - Dima Khoury - Gerard Newman - Dave Oran - Denny Page - Ken Pillay - Chetan Rai - Yakov Rekhter - Dave Rossetti - Paul Stirpe - Brian Whetten - Kyle York - -20. References - - [1] B. Whetten, T. Montgomery, S. Kaplan, "A High Performance - Totally Ordered Multicast Protocol", in "Theory and Practice in - Distributed Systems", Springer Verlag LCNS938, 1994. - - [2] S. Floyd, V. Jacobson, C. Liu, S. McCanne, L. Zhang, "A - Reliable Multicast Framework for Light-weight Sessions and - Application Level Framing", ACM Transactions on Networking, - November 1996. - - [3] J. C. Lin, S. Paul, "RMTP: A Reliable Multicast Transport - Protocol", ACM SIGCOMM August 1996. - - [4] Miller, K., Robertson, K., Tweedly, A. and M. White, "Multicast - File Transfer Protocol (MFTP) Specification", Work In Progress. - - [5] Deering, S., "Host Extensions for IP Multicasting", STD 5, RFC - 1112, August 1989. - - [6] Katz, D., "IP Router Alert Option", RFC 2113, February 1997. - - [7] C. Partridge, "Gigabit Networking", Addison Wesley 1994. - - - -Speakman, et. al. Experimental [Page 106] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - [8] H. W. Holbrook, S. K. Singhal, D. R. Cheriton, "Log-Based - Receiver-Reliable Multicast for Distributed Interactive - Simulation", ACM SIGCOMM 1995. - - [9] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April - 1992. - - [10] Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, RFC - 1700, October 1994. - - [11] J. Nonnenmacher, E. Biersack, D. Towsley, "Parity-Based Loss - Recovery for Reliable Multicast Transmission", ACM SIGCOMM - September 1997. - - [12] L. Rizzo, "Effective Erasure Codes for Reliable Computer - Communication Protocols", Computer Communication Review, April - 1997. - - [13] V. Jacobson, "Congestion Avoidance and Control", ACM SIGCOMM - August 1988. - - [14] Bradner, S., "Key words for use in RFCs to Indicate Requirement - Levels", BCP, 14, RFC 2119, March 1997. - - [15] J. Bolot, T. Turletti, I. Wakeman, "Scalable Feedback Control - for Multicast Video Distribution in the Internet", Proc. - ACM/Sigcomm 94, pp. 58-67. - - [16] L. Rizzo, "pgmcc: A TCP-friendly Single-Rate Multicast - Congestion Control Scheme", Proc. of ACM SIGCOMM August 2000. - - [17] M. Luby, L. Vicisano, T. Speakman. "Heterogeneous multicast - congestion control based on router packet filtering", RMT - working group, June 1999, Pisa, Italy. - - [18] Cain, B., Speakman, T. and D. Towsley, "Generic Router Assist - (GRA) Building Block, Motivation and Architecture", Work In - Progress. - - [19] C. Papadopoulos, and E. Laliotis,"Incremental Deployment of a - Router-assisted Reliable Multicast Scheme,", Proc. of Networked - Group Communications (NGC2000), Stanford University, Palo Alto, - CA. November 2000. - - - - - - - - -Speakman, et. al. Experimental [Page 107] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - [20] C. Papadopoulos, "RAIMS: an Architecture for Router-Assisted - Internet Multicast Services." Presented at ETH, Zurich, - Switzerland, October 23 2000. - - [21] J. Chesterfield, A. Diana, A. Greenhalgh, M. Lad, and M. Lim, - "A BSD Router Implementation of PGM", - http://www.cs.ucl.ac.uk/external/m.lad/rpgm/ - - [22] L. Rizzo, "A PGM Host Implementation for FreeBSD", - http://www.iet.unipi.it/~luigi/pgm.html - - [23] M. Psaltaki, R. Araujo, G. Aldabbagh, P. Kouniakis, and A. - Giannopoulos, "Pragmatic General Multicast (PGM) host - implementation for FreeBSD.", - http://www.cs.ucl.ac.uk/research/darpa/pgm/PGM_FINAL.html - -21. Authors' Addresses - - Tony Speakman - EMail: speakman@cisco.com - - Dino Farinacci - Procket Networks - 3850 North First Street - San Jose, CA 95134 - USA - EMail: dino@procket.com - - Steven Lin - Juniper Networks - 1194 N. Mathilda Ave. - Sunnyvale, CA 94086 - USA - EMail: steven@juniper.net - - Alex Tweedly - EMail: agt@cisco.com - - Nidhi Bhaskar - EMail: nbhaskar@cisco.com - - Richard Edmonstone - EMail: redmonst@cisco.com - - Rajitha Sumanasekera - EMail: rajitha@cisco.com - - - - - -Speakman, et. al. Experimental [Page 108] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Lorenzo Vicisano - Cisco Systems, Inc. - 170 West Tasman Drive, - San Jose, CA 95134 - USA - EMail: lorenzo@cisco.com - - Jon Crowcroft - Department of Computer Science - University College London - Gower Street - London WC1E 6BT - UK - EMail: j.crowcroft@cs.ucl.ac.uk - - Jim Gemmell - Microsoft Bay Area Research Center - 301 Howard Street, #830 - San Francisco, CA 94105 - USA - EMail: jgemmell@microsoft.com - - Dan Leshchiner - Tibco Software - 3165 Porter Dr. - Palo Alto, CA 94304 - USA - EMail: dleshc@tibco.com - - Michael Luby - Digital Fountain, Inc. - 39141 Civic Center Drive - Fremont CA 94538 - USA - EMail: luby@digitalfountain.com - - Todd L. Montgomery - Talarian Corporation - 124 Sherman Ave. - Morgantown, WV 26501 - USA - EMail: todd@talarian.com - - - - - - - - - -Speakman, et. al. Experimental [Page 109] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - - Luigi Rizzo - Dip. di Ing. dell'Informazione - Universita` di Pisa - via Diotisalvi 2 - 56126 Pisa - Italy - EMail: luigi@iet.unipi.it - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Speakman, et. al. Experimental [Page 110] - -RFC 3208 PGM Reliable Transport Protocol December 2001 - - -22. Full Copyright Statement - - Copyright (C) The Internet Society (2001). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Speakman, et. al. Experimental [Page 111] - diff --git a/3rdparty/openpgm-svn-r1085/pgm/COPYING b/3rdparty/openpgm-svn-r1085/pgm/COPYING deleted file mode 100644 index 5ab7695..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/COPYING +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/3rdparty/openpgm-svn-r1085/pgm/INSTALL b/3rdparty/openpgm-svn-r1085/pgm/INSTALL deleted file mode 100644 index 3ba60e5..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/INSTALL +++ /dev/null @@ -1,4 +0,0 @@ -For building instructions, see: - - http://code.google.com/p/openpgm/wiki/OpenPgm3CReferenceBuildLibrary - diff --git a/3rdparty/openpgm-svn-r1085/pgm/LICENSE b/3rdparty/openpgm-svn-r1085/pgm/LICENSE deleted file mode 100644 index fabbeef..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Most of OpenPGM is licensed under the terms of the GNU Lesser Public License, -the LGPL, with a special exception: - - As a special exception, the copyright holders of this library give - you permission to link this library with independent modules to - produce an executable, regardless of the license terms of these - independent modules, and to copy and distribute the resulting - executable under terms of your choice, provided that you also meet, - for each linked independent module, the terms and conditions of the - license of that module. An independent module is a module which is - not derived from or based on this library. If you modify this - library, you must extend this exception to your version of the - library. - -See the file COPYING for details of the LGPL. - -Hence you should treat the libraries libpgm, libpgmsnmp, and libpgmhttp of -OpenPGM as being LGPL licensed, with the special exception. - diff --git a/3rdparty/openpgm-svn-r1085/pgm/README b/3rdparty/openpgm-svn-r1085/pgm/README deleted file mode 100644 index ece7aa1..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/README +++ /dev/null @@ -1,7 +0,0 @@ -OpenPGM is a library implementing the PGM reliable multicast network protocol. - -For more information about OpenPGM, see: - - http://openpgm.googlecode.com/ - - diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgm b/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgm deleted file mode 100644 index 8dd509d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgm +++ /dev/null @@ -1,170 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script -# $Id$ - -import os; -Import('env') - -src = Split(""" - thread.c - mem.c - string.c - list.c - slist.c - queue.c - hashtable.c - messages.c - error.c - math.c - packet_parse.c - packet_test.c - sockaddr.c - time.c - if.c - getifaddrs.c - getnodeaddr.c - indextoaddr.c - indextoname.c - nametoindex.c - inet_network.c - md5.c - rand.c - gsi.c - tsi.c - txw.c - rxw.c - skbuff.c - socket.c - source.c - receiver.c - recv.c - engine.c - timer.c - net.c - rate_control.c - checksum.c - reed_solomon.c - galois_tables.c - wsastrerror.c - histogram.c -""") - -e = env.Clone(); -e.Append(CCFLAGS = '-DGETTEXT_PACKAGE=\'"pgm"\''); - -# Galois tables -e.Command ('galois_tables.c', 'galois_generator.pl', "perl $SOURCE > $TARGET"); - -# Version stamping -e.Command ('version.c', 'version_generator.py', "python $SOURCE > $TARGET"); -e.Depends ('version.c', src); -src += ['version.c']; - -e.StaticLibrary('libpgm', src); -e.StaticSharedLibrary('libpgm-pic', src); - -#----------------------------------------------------------------------------- -# unit testing - -if env['WITH_CHECK'] == 'true': - te = e.Clone(); - te.MergeFlags(env['GLIB_FLAGS']); - newCCFLAGS = []; - for flag in te['CCFLAGS']: - if ("-W" != flag[:2]) and ("-pedantic" != flag[:9]): - newCCFLAGS.append(flag); - te['CCFLAGS'] = newCCFLAGS; - te.ParseConfig ('pkg-config --cflags --libs check'); -# log dependencies - tlog = [ e.Object('messages.c'), - e.Object('thread.c'), - e.Object('galois_tables.c'), - e.Object('mem.c'), - e.Object('histogram.c'), - e.Object('string.c'), - e.Object('slist.c') - ]; -# framework - te.Program (['atomic_unittest.c']); - te.Program (['checksum_unittest.c'] + tlog); - te.Program (['error_unittest.c'] + tlog); - te.Program (['md5_unittest.c'] + tlog); - te.Program (['getifaddrs_unittest.c', - e.Object('error.c'), - e.Object('sockaddr.c'), - e.Object('list.c')] + tlog); - te.Program (['getnodeaddr_unittest.c', - e.Object('error.c'), - e.Object('sockaddr.c')] + tlog); - te.Program (['indextoaddr_unittest.c', - e.Object('error.c'), - e.Object('sockaddr.c')] + tlog); - te.Program (['inet_network_unittest.c', - e.Object('sockaddr.c')] + tlog); - te.Program (['rate_control_unittest.c'] + tlog); - te.Program (['reed_solomon_unittest.c'] + tlog); - te.Program (['time_unittest.c', - e.Object('error.c')] + tlog); -# collate - tframework = [ e.Object('checksum.c'), - e.Object('error.c'), - e.Object('galois_tables.c'), - e.Object('getifaddrs.c'), - e.Object('getnodeaddr.c'), - e.Object('hashtable.c'), - e.Object('histogram.c'), - e.Object('indextoaddr.c'), - e.Object('indextoname.c'), - e.Object('inet_network.c'), - e.Object('list.c'), - e.Object('math.c'), - e.Object('md5.c'), - e.Object('mem.c'), - e.Object('messages.c'), - e.Object('nametoindex.c'), - e.Object('queue.c'), - e.Object('rand.c'), - e.Object('rate_control.c'), - e.Object('reed_solomon.c'), - e.Object('slist.c'), - e.Object('sockaddr.c'), - e.Object('string.c'), - e.Object('thread.c'), - e.Object('time.c'), - e.Object('wsastrerror.c') - ]; -# library - te.Program (['txw_unittest.c', - e.Object('tsi.c'), - e.Object('skbuff.c')] + tframework); - te.Program (['rxw_unittest.c', - e.Object('tsi.c'), - e.Object('skbuff.c')] + tframework); - te.Program (['engine_unittest.c', - e.Object('version.c')] + tframework); - te.Program (['gsi_unittest.c', - e.Object('if.c')] + tframework); - te.Program (['tsi_unittest.c'] + tframework); - te.Program (['if_unittest.c'] + tframework); - te.Program (['socket_unittest.c', - e.Object('if.c'), - e.Object('tsi.c')] + tframework); -# te.Program (['source_unittest.c'] + tframework); -# te.Program (['receiver_unittest.c', -# e.Object('tsi.c')] + tframework); - te.Program (['recv_unittest.c', - e.Object('tsi.c'), - e.Object('gsi.c'), - e.Object('skbuff.c')] + tframework); - te.Program (['net_unittest.c'] + tframework); - te.Program (['timer_unittest.c'] + tframework); - te.Program (['packet_parse_unittest.c'] + tframework); - te.Program (['packet_test_unittest.c'] + tframework); - te.Program (['ip_unittest.c', - e.Object('if.c')] + tframework); -# performance tests - te.Program (['checksum_perftest.c', - e.Object('time.c'), - e.Object('error.c')] + tlog); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgm89 b/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgm89 deleted file mode 100644 index dae46b9..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgm89 +++ /dev/null @@ -1,80 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script -# $Id$ - -import os; -import string; -Import('env') - -src = Split(""" - thread.c - mem.c - string.c - list.c - slist.c - queue.c - hashtable.c - messages.c - error.c - math.c - packet_parse.c - packet_test.c - sockaddr.c - time.c - if.c - getifaddrs.c - getnodeaddr.c - indextoaddr.c - indextoname.c - nametoindex.c - inet_network.c - md5.c - rand.c - gsi.c - tsi.c - txw.c - rxw.c - skbuff.c - socket.c - source.c - receiver.c - recv.c - engine.c - timer.c - net.c - rate_control.c - checksum.c - reed_solomon.c - galois_tables.c - wsastrerror.c - histogram.c -""") - -e = env.Clone(); -e.Append(CCFLAGS = '-DGETTEXT_PACKAGE=\'"pgm"\''); - -# Galois tables -e.Command ('galois_tables.c', 'galois_generator.pl', "perl $SOURCE > $TARGET"); - -# Version stamping -e.Command ('version.c', 'version_generator.py', "python $SOURCE > $TARGET"); -e.Depends ('version.c', src); -src += ['version.c']; - -# C89 degrading -c89source = Builder(action = 'perl -p -e "s/%z(u|d)/%l\\1/g" $SOURCE > $TARGET', - suffix = '.c89.c', - src_suffix = '.c', - single_source = 1); -e.Append(BUILDERS = {'C89Source' : c89source}) - -c89src = [] -for c99file in src: - c89file = c99file.replace('.c', '.c89.c'); - c89src += [ c89file ]; - e.C89Source(c99file); - -e.StaticLibrary('libpgm89', c89src); -e.StaticSharedLibrary('libpgm89-pic', c89src); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmex b/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmex deleted file mode 100644 index b508a04..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmex +++ /dev/null @@ -1,18 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script -# $Id$ - -Import('env') - -e = env.Clone(); -e.MergeFlags(env['GLIB_FLAGS']); - -src = Split(""" - log.c - backtrace.c - signal.c -""") - -e.StaticLibrary('libpgmex', src); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmhttp b/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmhttp deleted file mode 100644 index 9824b3c..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmhttp +++ /dev/null @@ -1,53 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script -# $Id$ - -Import('env') - -e = env.Clone() -e.Append(CCFLAGS = '-DGETTEXT_PACKAGE=\'"pgm-http"\''); - -# add binary tree to include path to find embedded htdocs -e.Append(CPPPATH = ['.']); - -src = Split(""" - http.c -""") - -htdocs = Split(""" - htdocs/404.html - htdocs/base.css - htdocs/robots.txt - htdocs/xhtml10_strict.doctype -""") - -pgmhttp = e.StaticLibrary('libpgmhttp', src); -pgmhttppic = e.StaticSharedLibrary('libpgmhttp-pic', src); - -# embed htdocs into C headers -embed_htdoc = Builder(action = './htdocs/convert_to_macro.pl $SOURCE > $TARGET') -e.Append(BUILDERS = {'EmbedHtdoc' : embed_htdoc}) - -for htdoc in htdocs: - embedded = htdoc + '.h' - e.EmbedHtdoc(embedded, htdoc) - -#----------------------------------------------------------------------------- -# unit testing - -if env['WITH_CHECK'] == 'true': - te = e.Clone(); -# add new suffix so we can re-use libpgm objects - te['SHOBJSUFFIX'] = '.http' + te['SHOBJSUFFIX']; - te['OBJSUFFIX'] = '.http' + te['OBJSUFFIX']; - - newCCFLAGS = []; - for flag in te['CCFLAGS']: - if ("-W" != flag[:2]) and ("-pedantic" != flag[:9]): - newCCFLAGS.append(flag); - te['CCFLAGS'] = newCCFLAGS; - te.ParseConfig ('pkg-config --cflags --libs check'); - te.Program (['http_unittest.c', te.Object('sockaddr.c'), te.Object('getifaddrs.c')]); - - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmsnmp b/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmsnmp deleted file mode 100644 index 8e35aab..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConscript.libpgmsnmp +++ /dev/null @@ -1,35 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script -# $Id$ - -Import('env') - -e = env.Clone() -e.Append(CCFLAGS = '-DGETTEXT_PACKAGE=\'"pgm-snmp"\''); - -e.MergeFlags(e['SNMP_FLAGS']); - -src = Split(""" - snmp.c - pgmMIB.c -""") - -e.StaticLibrary('libpgmsnmp', src); -e.StaticSharedLibrary('libpgmsnmp-pic', src); - -#----------------------------------------------------------------------------- -# unit testing - -if env['WITH_CHECK'] == 'true': - te = e.Clone(); - newCCFLAGS = []; - for flag in te['CCFLAGS']: - if ("-W" != flag[:2]) and ("-pedantic" != flag[:9]): - newCCFLAGS.append(flag); - te['CCFLAGS'] = newCCFLAGS; - te.ParseConfig ('pkg-config --cflags --libs check'); - te.Program ('snmp_unittest.c'); - te.Program (['pgmMIB_unittest.c', e.Object('snmp.c')]); - - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct b/3rdparty/openpgm-svn-r1085/pgm/SConstruct deleted file mode 100644 index 5754901..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct +++ /dev/null @@ -1,326 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 1, 0 ) -SConsignFile('scons.signatures' + '-' + platform.system() + '-' + platform.machine()); - -vars = Variables() -vars.AddVariables ( - EnumVariable ('BUILD', 'build environment', 'debug', - allowed_values=('release', 'debug', 'profile')), - EnumVariable ('BRANCH', 'branch prediction', 'none', - allowed_values=('none', 'profile', 'seed')), - EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', - allowed_values=('true', 'false')), - EnumVariable ('COVERAGE', 'test coverage', 'none', - allowed_values=('none', 'full')), - EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CHECK', 'Check test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_TEST', 'Network test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CC', 'C++ examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', - allowed_values=('true', 'false')), -) - -#----------------------------------------------------------------------------- -# Dependencies - -env = Environment(); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment( - variables = vars, - ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', - '-Wunsafe-loop-optimizations', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', - '-pedantic', -# C99 - '-std=gnu99', - '-D_XOPEN_SOURCE=600', - '-D_BSD_SOURCE', -# re-entrant libc - '-D_REENTRANT', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R', - '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header - '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system - '-DCONFIG_HAVE_PROC', -# example: crash handling - '-DCONFIG_HAVE_BACKTRACE', -# timing - '-DCONFIG_HAVE_PSELECT', - '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', - '-DCONFIG_HAVE_HPET', -# event handling - '-DCONFIG_HAVE_POLL', - '-DCONFIG_HAVE_EPOLL', -# interface enumeration - '-DCONFIG_HAVE_GETIFADDRS', - '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg -# '-DCONFIG_HAVE_WSACMSGHDR', -# multicast - '-DCONFIG_HAVE_MCAST_JOIN', - '-DCONFIG_HAVE_IP_MREQN', -# sprintf - '-DCONFIG_HAVE_SPRINTF_GROUPING', - '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE', -# GNU getopt - '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ '-pipe' - ], - LIBS = [ -# histogram math - 'm', -# clock_gettime() - 'rt' - ] -) - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Coverage analysis -if env['COVERAGE'] == 'full': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(CCFLAGS = '-ftest-coverage') - env.Append(LINKFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-lgcov') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = '-O2') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-gdb') - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -if env['WITH_SNMP'] == 'true': - env['SNMP_FLAGS'] = env.ParseFlags('!net-snmp-config --agent-libs'); - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -def CheckEventFD(context): - context.Message('Checking eventfd...'); - result = context.TryLink(""" -#include -int main(int argc, char**argv) -{ - eventfd(0,0); - return 0; -} -""", '.c') - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck, - 'CheckEventFD': CheckEventFD -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -if conf.CheckEventFD(): - print 'Enabling kernel eventfd notification mechanism.'; - conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097 b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097 deleted file mode 100644 index 9a1d029..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097 +++ /dev/null @@ -1,321 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 0, 97 ) -SConsignFile('scons.signatures'+ '-' + platform.system() + '-' + platform.machine()); - -opt = Options(None, ARGUMENTS) -opt.AddOptions ( - (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), - (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), - (EnumOption ('WITH_GETTEXT', 'l10n support via libintl', 'false', ('true', 'false'))), - (EnumOption ('WITH_GLIB', 'Build GLib dependent modules', 'false', ('true', 'false'))), - (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), - (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), - (EnumOption ('WITH_HTTP', 'HTTP administration', 'false', ('true', 'false'))), - (EnumOption ('WITH_SNMP', 'SNMP administration', 'false', ('true', 'false'))), - (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), - (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), - (EnumOption ('WITH_CC', 'C++ Examples', 'true', ('true', 'false'))), - (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), - (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), - (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), -) - -#----------------------------------------------------------------------------- -# Dependencies - -env = Environment(); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment(ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', - '-Wunsafe-loop-optimizations', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', - '-pedantic', -# C99 - '-std=gnu99', - '-D_XOPEN_SOURCE=600', -# re-entrant libc - '-D_REENTRANT', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R', - '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header - '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system - '-DCONFIG_HAVE_PROC', -# example: crash handling - '-DCONFIG_HAVE_BACKTRACE', -# timing - '-DCONFIG_HAVE_PSELECT', - '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', -# event handling - '-DCONFIG_HAVE_POLL', - '-DCONFIG_HAVE_EPOLL', -# interface enumeration - '-DCONFIG_HAVE_GETIFADDRS', - '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg -# '-DCONFIG_HAVE_WSACMSGHDR', -# multicast - '-DCONFIG_HAVE_MCAST_JOIN', - '-DCONFIG_HAVE_IP_MREQN', -# sprintf - '-DCONFIG_HAVE_SPRINTF_GROUPING', - '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE', -# GNU getopt - '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ '-pipe' - ], - LIBS = [ -# histogram math - 'm', -# clock_gettime() - 'rt' - ], - PROTOBUF_CCFLAGS = '-I/miru/projects/protobuf/protobuf-2.1.0/src', - PROTOBUF_LIBS = '/miru/projects/protobuf/protobuf-2.1.0/src/.libs/libprotobuf.a', - PROTOBUF_PROTOC = '/miru/projects/protobuf/protobuf-2.1.0/src/protoc' -) -opt.Update (env) - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Coverage analysis -if env['COVERAGE'] == 'full': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(CCFLAGS = '-ftest-coverage') - env.Append(LINKFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-lgcov') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = '-O2') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-gdb') - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O0','-pg'], LINKFLAGS = '-pg') - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -def CheckEventFD(context): - context.Message('Checking eventfd...'); - result = context.TryLink(""" -#include -int main(int argc, char**argv) -{ - eventfd(0,0); - return 0; -} -""", '.c') - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck, - 'CheckEventFD': CheckEventFD -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Enabling extra Red Hat dependencies for Net-SNMP.'; - conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); - lastLIBS = conf.env['LIBS']; - conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); - conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); - conf.env.Replace(LIBS = lastLIBS); - if not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -if conf.CheckEventFD(): - print 'Enabling kernel eventfd notification mechanism.'; - conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.intelc b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.intelc deleted file mode 100644 index e2099d5..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.intelc +++ /dev/null @@ -1,331 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 0, 97 ) -SConsignFile('scons.signatures'+ '-' + platform.system() + '-' + platform.machine() + '-intelc'); - -opt = Options(None, ARGUMENTS) -opt.AddOptions ( - (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), - (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), - (EnumOption ('WITH_GETTEXT', 'l10n support via libintl', 'false', ('true', 'false'))), - (EnumOption ('WITH_GLIB', 'Build GLib dependent modules', 'false', ('true', 'false'))), - (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), - (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), - (EnumOption ('WITH_HTTP', 'HTTP administration', 'false', ('true', 'false'))), - (EnumOption ('WITH_SNMP', 'SNMP administration', 'false', ('true', 'false'))), - (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), - (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), - (EnumOption ('WITH_CC', 'C++ Examples', 'true', ('true', 'false'))), - (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), - (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), - (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), -) - -#----------------------------------------------------------------------------- -# Dependencies - -def force_intelc(env): - env.Tool('intelc', version='11.1', topdir='/opt/intel/Compiler/11.1/064/bin/intel64'); - -env = Environment(); -force_intelc(env); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment(ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', -# '-Wextra', -# '-Wfloat-equal', - '-Wshadow', -# '-Wunsafe-loop-optimizations', - '-Wpointer-arith', -# '-Wbad-function-cast', -# '-Wcast-qual', -# '-Wcast-align', - '-Wwrite-strings', -# '-Waggregate-return', - '-Wstrict-prototypes', -# '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', -# '-Wmissing-noreturn', -# '-Wmissing-format-attribute', -# '-Wredundant-decls', -# '-Wnested-externs', - '-Winline', -# 981: operands are evaluated in unspecified order - '-wd981', -# 2259: non-pointer conversion from "*" to "*" may lose significant bits - '-wd2259', -# '-pedantic', -# C99 - '-std=c99', - '-D_XOPEN_SOURCE=600', - '-gcc-version=420', -# re-entrant libc - '-D_REENTRANT', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R', - '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header - '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system - '-DCONFIG_HAVE_PROC', -# example: crash handling - '-DCONFIG_HAVE_BACKTRACE', -# timing - '-DCONFIG_HAVE_PSELECT', - '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', -# event handling - '-DCONFIG_HAVE_POLL', - '-DCONFIG_HAVE_EPOLL', -# interface enumeration - '-DCONFIG_HAVE_GETIFADDRS', - '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg -# '-DCONFIG_HAVE_WSACMSGHDR', -# multicast - '-DCONFIG_HAVE_MCAST_JOIN', - '-DCONFIG_HAVE_IP_MREQN', -# sprintf - '-DCONFIG_HAVE_SPRINTF_GROUPING', - '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE', -# GNU getopt - '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ '-pipe' - ], - LIBS = [ -# histogram math - 'm', -# clock_gettime() - 'rt' - ], - PROTOBUF_CCFLAGS = '-I/miru/projects/protobuf/protobuf-2.1.0/src', - PROTOBUF_LIBS = '/miru/projects/protobuf/protobuf-2.1.0/src/.libs/libprotobuf.a', - PROTOBUF_PROTOC = '/miru/projects/protobuf/protobuf-2.1.0/src/protoc' -) -opt.Update (env) -force_intelc(env); - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Coverage analysis -if env['COVERAGE'] == 'full': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(CCFLAGS = '-ftest-coverage') - env.Append(LINKFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-lgcov') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = '-O2') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-gdb') - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O0','-pg'], LINKFLAGS = '-pg') - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -def CheckEventFD(context): - context.Message('Checking eventfd...'); - result = context.TryLink(""" -#include -int main(int argc, char**argv) -{ - eventfd(0,0); - return 0; -} -""", '.c') - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck, - 'CheckEventFD': CheckEventFD -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Enabling extra Red Hat dependencies for Net-SNMP.'; - conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); - lastLIBS = conf.env['LIBS']; - conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); - conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); - conf.env.Replace(LIBS = lastLIBS); - if not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -if conf.CheckEventFD(): - print 'Enabling kernel eventfd notification mechanism.'; - conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-intelc/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.mingw64 b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.mingw64 deleted file mode 100644 index 59b8063..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.mingw64 +++ /dev/null @@ -1,325 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 0, 97 ) -SConsignFile('scons.signatures'+ '-Win64-' + platform.machine()); - -opt = Options(None, ARGUMENTS) -opt.AddOptions ( - (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), - (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), - (EnumOption ('WITH_GETTEXT', 'l10n support via libintl', 'false', ('true', 'false'))), - (EnumOption ('WITH_GLIB', 'Build GLib dependent modules', 'false', ('true', 'false'))), - (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), - (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), - (EnumOption ('WITH_HTTP', 'HTTP administration', 'false', ('true', 'false'))), - (EnumOption ('WITH_SNMP', 'SNMP administration', 'false', ('true', 'false'))), - (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), - (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), -# C++ broken scope - (EnumOption ('WITH_CC', 'C++ examples', 'false', ('true', 'false'))), - (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), - (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), - (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), -) - -#----------------------------------------------------------------------------- -# Dependencies - -def force_mingw(env): - env.PrependENVPath('PATH', '/opt/mingw/bin'); - env.Tool('crossmingw64', toolpath=['.']); - -env = Environment(); -force_mingw(env); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('PKG_CONFIG_PATH=win64/lib/pkgconfig pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('PKG_CONFIG_PATH=win64/lib/pkgconfig pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment(ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', - '-Wunsafe-loop-optimizations', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', - '-pedantic', -# C99 - '-std=gnu99', - '-D_GNU_SOURCE', - '-D_WIN32_WINNT=0x0501', -# re-entrant libc - '-D_REENTRANT', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header -# '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system -# '-DCONFIG_HAVE_PROC', -# example: crash handling -# '-DCONFIG_HAVE_BACKTRACE', -# timing -# '-DCONFIG_HAVE_PSELECT', -# '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', -# event handling -# '-DCONFIG_HAVE_POLL', -# '-DCONFIG_HAVE_EPOLL', -# interface enumeration -# '-DCONFIG_HAVE_GETIFADDRS', -# '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg - '-DCONFIG_HAVE_WSACMSGHDR', -# multicast -# '-DCONFIG_HAVE_MCAST_JOIN', -# '-DCONFIG_HAVE_IP_MREQN', -# sprintf -# '-DCONFIG_HAVE_SPRINTF_GROUPING', -# '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE' -# GNU getopt -# '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ '-pipe' - ], - LIBS = [ - 'iphlpapi.lib', - 'ws2_32.lib' - ] -) -opt.Update (env) -force_mingw(env); - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Coverage analysis -if env['COVERAGE'] == 'full': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(CCFLAGS = '-ftest-coverage') - env.Append(LINKFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-lgcov') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = '-O2') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-gdb') - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O0','-pg'], LINKFLAGS = '-pg') - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!PKG_CONFIG_PATH=win64/lib/pkgconfig pkg-config --cflags --libs glib-2.0 gthread-2.0'); - env.MergeFlags('-Iwin/include -Lwin64/lib'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('PKG_CONFIG_PATH=win64/lib/pkgconfig pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -def CheckEventFD(context): - context.Message('Checking eventfd...'); - result = context.TryLink(""" -#include -int main(int argc, char**argv) -{ - eventfd(0,0); - return 0; -} -""", '.c') - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck, - 'CheckEventFD': CheckEventFD -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Enabling extra Red Hat dependencies for Net-SNMP.'; - conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); - lastLIBS = conf.env['LIBS']; - conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); - conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); - conf.env.Replace(LIBS = lastLIBS); - if not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -if conf.CheckEventFD(): - print 'Enabling kernel eventfd notification mechanism.'; - conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-Win64-' + platform.machine() + '/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm89'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript89'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.sunstudio b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.sunstudio deleted file mode 100644 index 1664b9b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.097.sunstudio +++ /dev/null @@ -1,312 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 0, 97 ) -SConsignFile('scons.signatures'+ '-' + platform.system() + '-' + platform.machine() + '-sunstudio'); - -opt = Options(None, ARGUMENTS) -opt.AddOptions ( - (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), - (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), - (EnumOption ('WITH_GETTEXT', 'l10n support via libintl', 'false', ('true', 'false'))), - (EnumOption ('WITH_GLIB', 'Build GLib dependent modules', 'false', ('true', 'false'))), - (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), - (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), - (EnumOption ('WITH_HTTP', 'HTTP administration', 'false', ('true', 'false'))), - (EnumOption ('WITH_SNMP', 'SNMP administration', 'false', ('true', 'false'))), - (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), - (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), - (EnumOption ('WITH_CC', 'C++ Examples', 'true', ('true', 'false'))), - (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), - (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), - (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), -) - -#----------------------------------------------------------------------------- -# Dependencies - -def force_sunstudio(env): - env.PrependENVPath('PATH', '/opt/sun/sunstudio12.1/bin'); - env.Tool('sunc++'); - env.Tool('suncc'); - env.Tool('sunlink'); - env.Tool('sunar'); - -env = Environment(); -force_sunstudio(env); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment(ENV = os.environ, - CCFLAGS = [ '-v', -# C99 - '-xc99=all', - '-D_XOPEN_SOURCE=600', - '-D__EXTENSIONS__', - '-DBSD_COMP', - '-D_BSD_SOURCE', -# re-entrant libc - '-D_REENTRANT', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R', - '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header - '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system - '-DCONFIG_HAVE_PROC', -# example: crash handling - '-DCONFIG_HAVE_BACKTRACE', -# timing - '-DCONFIG_HAVE_PSELECT', - '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', -# event handling - '-DCONFIG_HAVE_POLL', - '-DCONFIG_HAVE_EPOLL', -# interface enumeration - '-DCONFIG_HAVE_GETIFADDRS', - '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg -# '-DCONFIG_HAVE_WSACMSGHDR', -# multicast - '-DCONFIG_HAVE_MCAST_JOIN', - '-DCONFIG_HAVE_IP_MREQN', -# sprintf - '-DCONFIG_HAVE_SPRINTF_GROUPING', - '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE', -# GNU getopt - '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ - ], - LIBS = [ -# histogram math - 'm', -# clock_gettime() - 'rt' - ], - PROTOBUF_CCFLAGS = '-I/miru/projects/protobuf/protobuf-2.1.0/src', - PROTOBUF_LIBS = '/miru/projects/protobuf/protobuf-2.1.0/src/.libs/libprotobuf.a', - PROTOBUF_PROTOC = '/miru/projects/protobuf/protobuf-2.1.0/src/protoc' -) -opt.Update (env) -force_sunstudio(env); - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Coverage analysis -if env['COVERAGE'] == 'full': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(CCFLAGS = '-ftest-coverage') - env.Append(LINKFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-lgcov') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = '-O2') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG','-g'], LINKFLAGS = '-g') - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O0','-pg'], LINKFLAGS = '-pg') - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -def CheckEventFD(context): - context.Message('Checking eventfd...'); - result = context.TryLink(""" -#include -int main(int argc, char**argv) -{ - eventfd(0,0); - return 0; -} -""", '.c') - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck, - 'CheckEventFD': CheckEventFD -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Enabling extra Red Hat dependencies for Net-SNMP.'; - conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); - lastLIBS = conf.env['LIBS']; - conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); - conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); - conf.env.Replace(LIBS = lastLIBS); - if not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -if conf.CheckEventFD(): - print 'Enabling kernel eventfd notification mechanism.'; - conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-sunstudio/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Debian4 b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Debian4 deleted file mode 100644 index 952013e..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Debian4 +++ /dev/null @@ -1,281 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import os -import time -import sys - -EnsureSConsVersion( 0, 97 ) -SConsignFile('scons.signatures'); - -opt = Options(None, ARGUMENTS) -opt.AddOptions ( - (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), - (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), - (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), - (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), - (EnumOption ('WITH_HTTP', 'HTTP administration', 'true', ('true', 'false'))), - (EnumOption ('WITH_SNMP', 'SNMP administration', 'true', ('true', 'false'))), - (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), - (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), - (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), - (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), - (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), - (EnumOption ('WITH_PLUS', 'libpgmplus GPL library', 'false', ('true', 'false'))), -) - -#----------------------------------------------------------------------------- -# Dependencies - -env = Environment(); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' - Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' - Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' - Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment(ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', - '-Wunsafe-loop-optimizations', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', - '-pedantic', - '-std=gnu99', - '--param', 'max-inline-insns-single=600', - '-D_REENTRANT', - '-D_GNU_SOURCE', - '-D__need_IOV_MAX', - '-DCONFIG_16BIT_CHECKSUM', - '-DCONFIG_HAVE_PROC', - '-DCONFIG_HAVE_BACKTRACE', - '-DCONFIG_HAVE_PSELECT', - '-DCONFIG_HAVE_POLL', - '-DCONFIG_HAVE_EPOLL', - '-DCONFIG_HAVE_CLOCK_GETTIME', - '-DCONFIG_HAVE_CLOCK_NANOSLEEP', - '-DCONFIG_HAVE_NANOSLEEP', - '-DCONFIG_HAVE_USLEEP', - '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', - '-DCONFIG_HAVE_IFR_NETMASK', - '-DCONFIG_HAVE_GETIFADDRS', - '-DCONFIG_HAVE_GETHOSTBYNAME2', - '-DCONFIG_HAVE_GETPROTOBYNAME_R', - '-DCONFIG_HAVE_MCAST_JOIN', - '-DCONFIG_HAVE_IP_MREQN', - '-DCONFIG_HAVE_DSO_VISIBILITY', - '-DCONFIG_BIND_INADDR_ANY', - '-DCONFIG_GALOIS_MUL_LUT', - ], - LINKFLAGS = [ '-pipe', - '-lm' - ] -) -opt.Update (env) - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Coverage analysis -if env['COVERAGE'] == 'full': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(CCFLAGS = '-ftest-coverage') - env.Append(LINKFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-lgcov') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = '-O2') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = '-ggdb', LINKFLAGS = '-gdb') - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -env.ParseConfig('pkg-config --cflags --libs glib-2.0 gthread-2.0'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -def CheckEventFD(context): - context.Message('Checking eventfd...'); - result = context.TryLink(""" -#include -int main(int argc, char**argv) -{ - eventfd(0,0); - return 0; -} -""", '.c') - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck, - 'CheckEventFD': CheckEventFD -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Enabling extra Red Hat dependencies for Net-SNMP.'; - conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); - lastLIBS = conf.env['LIBS']; - conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); - conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); - conf.env.Replace(LIBS = lastLIBS); - if not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -if conf.CheckEventFD(): - print 'Enabling kernel eventfd notification mechanism.'; - conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); - -env = conf.Finish(); - -# DSO visibility flags -if '-DCONFIG_HAVE_DSO_VISIBILITY' in env['CCFLAGS']: - env.Append(CCFLAGS = '-DPGM_GNUC_INTERNAL=G_GNUC_INTERNAL') -else: - env.Append(CCFLAGS = '-DPGM_GNUC_INTERNAL=') - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -SConscript(ref_node + 'SConscript.libpgm'); -SConscript(ref_node + 'SConscript.libpgmex'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.FreeBSD80 b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.FreeBSD80 deleted file mode 100644 index 4d2b9a5..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.FreeBSD80 +++ /dev/null @@ -1,337 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 1, 0 ) -SConsignFile('scons.signatures' + '-' + platform.system() + '-' + platform.machine()); - -vars = Variables() -vars.AddVariables ( - EnumVariable ('BUILD', 'build environment', 'debug', - allowed_values=('release', 'debug', 'profile')), - EnumVariable ('BRANCH', 'branch prediction', 'none', - allowed_values=('none', 'profile', 'seed')), - EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', - allowed_values=('true', 'false')), - EnumVariable ('COVERAGE', 'test coverage', 'none', - allowed_values=('none', 'full')), - EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CHECK', 'Check test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_TEST', 'Network test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CC', 'C++ examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', - allowed_values=('true', 'false')), -) - -#----------------------------------------------------------------------------- -# Dependencies - -env = Environment(); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment( - variables = vars, - ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', - '-Wunsafe-loop-optimizations', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', - '-pedantic', -# C99 - '-std=gnu99', -# re-entrant libc - '-D_REENTRANT', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header -# '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system -# '-DCONFIG_HAVE_PROC', -# example: crash handling -# '-DCONFIG_HAVE_BACKTRACE', -# timing - '-DCONFIG_HAVE_PSELECT', -# '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', -# '-DCONFIG_HAVE_HPET', -# event handling - '-DCONFIG_HAVE_POLL', -# '-DCONFIG_HAVE_EPOLL', -# interface enumeration - '-DCONFIG_HAVE_GETIFADDRS', - '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg -# '-DCONFIG_HAVE_WSACMSGHDR', -# multicast -# '-DCONFIG_HAVE_MCAST_JOIN', - '-DCONFIG_HAVE_IP_MREQN', -# sprintf - '-DCONFIG_HAVE_SPRINTF_GROUPING', - '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD - '-DCONFIG_HOST_ORDER_IP_LEN', - '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE', -# GNU getopt - '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ '-pipe' - ], - LIBS = [ -# histogram math - 'm', -# clock_gettime() - 'rt', -# ftime() - 'compat', -# POSIX threads - 'pthread' - ] -) - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Coverage analysis -if env['COVERAGE'] == 'full': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(CCFLAGS = '-ftest-coverage') - env.Append(LINKFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-lgcov') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = '-O2') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-gdb') - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -def CheckEventFD(context): - context.Message('Checking eventfd...'); - result = context.TryLink(""" -#include -int main(int argc, char**argv) -{ - eventfd(0,0); - return 0; -} -""", '.c') - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck, - 'CheckEventFD': CheckEventFD -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Enabling extra Red Hat dependencies for Net-SNMP.'; - conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); - lastLIBS = conf.env['LIBS']; - conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); - conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); - conf.env.Replace(LIBS = lastLIBS); - if not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -if conf.CheckEventFD(): - print 'Enabling kernel eventfd notification mechanism.'; - conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.OpenSolaris b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.OpenSolaris deleted file mode 100644 index c9833ed..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.OpenSolaris +++ /dev/null @@ -1,310 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 1, 0 ) -SConsignFile('scons.signatures'+ '-OpenSolaris-' + platform.machine() + '-gcc'); - -vars = Variables() -vars.AddVariables ( - EnumVariable ('BUILD', 'build environment', 'debug', - allowed_values=('release', 'debug', 'profile')), - EnumVariable ('BRANCH', 'branch prediction', 'none', - allowed_values=('none', 'profile', 'seed')), - EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CHECK', 'Check test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_TEST', 'Network test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CC', 'C++ examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', - allowed_values=('true', 'false')), -) - -#----------------------------------------------------------------------------- -# Dependencies - -env = Environment(); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment( - variables = vars, - ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', -# '-Wunsafe-loop-optimizations', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', - '-pedantic', -# C99 - '-std=gnu99', - '-D_XOPEN_SOURCE=600', - '-D__EXTENSIONS__', - '-DBSD_COMP', - '-D_BSD_SOURCE', -# re-entrant libc - '-D_REENTRANT', - '-DCONFIG_HAVE_GETPROTOBYNAME_R', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header - '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system -# '-DCONFIG_HAVE_PROC', -# example: crash handling -# '-DCONFIG_HAVE_BACKTRACE', -# timing - '-DCONFIG_HAVE_PSELECT', -# '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', -# '-DCONFIG_HAVE_HPET', -# event handling - '-DCONFIG_HAVE_POLL', -# '-DCONFIG_HAVE_EPOLL', -# interface enumeration -# '-DCONFIG_HAVE_GETIFADDRS', -# '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg -# '-DCONFIG_HAVE_WSACMSGHDR', -# multicast - '-DCONFIG_HAVE_MCAST_JOIN', -# '-DCONFIG_HAVE_IP_MREQN', -# sprintf - '-DCONFIG_HAVE_SPRINTF_GROUPING', -# '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE', -# GNU getopt - '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ '-pipe' - ], - LIBS = [ -# histogram math - 'm', -# clock_gettime() - 'rt', -# Solaris sockets - 'resolv', - 'socket', - 'nsl' - ] -) - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = ['-O2'], LINKFLAGS = []) - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG', '-ggdb'], LINKFLAGS = ['-gdb']) - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = ['-pg']) - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp', - 'ssl', 'kstat', 'wrap', 'adm' ], - 'CPPPATH' : ['/opt/cws/include'], - 'LIBPATH' : ['/opt/csw/lib'], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-OpenSolaris-' + platform.machine() + '-gcc/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.RHEL4 b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.RHEL4 deleted file mode 100644 index 1637ea5..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.RHEL4 +++ /dev/null @@ -1,279 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import os -import time -import sys - -EnsureSConsVersion( 0, 97 ) -SConsignFile('scons.signatures'); - -opt = Options(None, ARGUMENTS) -opt.AddOptions ( - (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), - (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), - (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), - (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), - (EnumOption ('WITH_HTTP', 'HTTP administration', 'true', ('true', 'false'))), - (EnumOption ('WITH_SNMP', 'SNMP administration', 'true', ('true', 'false'))), - (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), - (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), - (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), - (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), - (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), - (EnumOption ('WITH_PLUS', 'libpgmplus GPL library', 'false', ('true', 'false'))), -) - -#----------------------------------------------------------------------------- -# Dependencies - -env = Environment(); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('PKG_CONFIG_PATH=/usr/evolution28/lib/pkgconfig:/usr/lib/pkconfig pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('PKG_CONFIG_PATH=/usr/evolution28/lib/pkgconfig:/usr/lib/pkconfig pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' - Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' - Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' - Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment(ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', - '-pedantic', - '-std=gnu99', - '--param', 'max-inline-insns-single=600', - '-D_REENTRANT', - '-D_GNU_SOURCE', - '-D__need_IOV_MAX', - '-DCONFIG_16BIT_CHECKSUM', - '-DCONFIG_HAVE_PROC', - '-DCONFIG_HAVE_BACKTRACE', - '-DCONFIG_HAVE_PSELECT', - '-DCONFIG_HAVE_POLL', - '-DCONFIG_HAVE_EPOLL', - '-DCONFIG_HAVE_CLOCK_GETTIME', - '-DCONFIG_HAVE_CLOCK_NANOSLEEP', - '-DCONFIG_HAVE_NANOSLEEP', - '-DCONFIG_HAVE_USLEEP', - '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', - '-DCONFIG_HAVE_GETIFADDRS', - '-DCONFIG_HAVE_GETHOSTBYNAME2', - '-DCONFIG_HAVE_GETPROTOBYNAME_R', - '-DCONFIG_HAVE_MCAST_JOIN', - '-DCONFIG_HAVE_IP_MREQN', - '-DCONFIG_HAVE_DSO_VISIBILITY', - '-DCONFIG_BIND_INADDR_ANY', - '-DCONFIG_GALOIS_MUL_LUT', - ], - LINKFLAGS = [ '-pipe', - '-lm' - ] -) -opt.Update (env) - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Coverage analysis -if env['COVERAGE'] == 'full': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(CCFLAGS = '-ftest-coverage') - env.Append(LINKFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-lgcov') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = '-O2') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = '-ggdb', LINKFLAGS = '-gdb') - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -env.ParseConfig('PKG_CONFIG_PATH=/usr/evolution28/lib/pkgconfig:/usr/lib/pkconfig pkg-config --cflags --libs glib-2.0 gthread-2.0'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -def CheckEventFD(context): - context.Message('Checking eventfd...'); - result = context.TryLink(""" -#include -int main(int argc, char**argv) -{ - eventfd(0,0); - return 0; -} -""", '.c') - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck, - 'CheckEventFD': CheckEventFD -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Enabling extra Red Hat dependencies for Net-SNMP.'; - conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); - lastLIBS = conf.env['LIBS']; - conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); - conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); - conf.env.Replace(LIBS = lastLIBS); - if not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -if conf.CheckEventFD(): - print 'Enabling kernel eventfd notification mechanism.'; - conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); - -env = conf.Finish(); - -# DSO visibility flags -if '-DCONFIG_HAVE_DSO_VISIBILITY' in env['CCFLAGS']: - env.Append(CCFLAGS = '-DPGM_GNUC_INTERNAL=G_GNUC_INTERNAL') -else: - env.Append(CCFLAGS = '-DPGM_GNUC_INTERNAL=') - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -SConscript(ref_node + 'SConscript.libpgm'); -SConscript(ref_node + 'SConscript.libpgmex'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.gcc64 b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.gcc64 deleted file mode 100644 index 953e120..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.gcc64 +++ /dev/null @@ -1,324 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 1, 0 ) -SConsignFile('scons.signatures' + '-' + platform.system() + '-' + platform.machine() + '-gcc64'); - -vars = Variables() -vars.AddVariables ( - EnumVariable ('BUILD', 'build environment', 'debug', - allowed_values=('release', 'debug', 'profile', 'thirtytwo')), - EnumVariable ('BRANCH', 'branch prediction', 'none', - allowed_values=('none', 'profile', 'seed')), - EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CHECK', 'Check test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_TEST', 'Network test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CC', 'C++ examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_PLUS', 'libpgmplus GPL library', 'false', - allowed_values=('true', 'false')), -) - -#----------------------------------------------------------------------------- -# Dependencies - -def force_gcc(env): - env.PrependENVPath('PATH', '/usr/sfw/bin'); - env.PrependENVPath('PATH', '/opt/glib-gcc64/bin'); - env.PrependENVPath('PATH', '/usr/local/bin'); - env.Tool('gcc'); - env.Tool('g++'); - -env = Environment(); -force_gcc(env); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment( - variables = vars, - ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', -# '-Wunsafe-loop-optimizations', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', - '-pedantic', -# C99 - '-std=gnu99', - '-D_XOPEN_SOURCE=600', - '-D__EXTENSIONS__', - '-DBSD_COMP', - '-D_BSD_SOURCE', -# re-entrant libc - '-D_REENTRANT', - '-DCONFIG_HAVE_GETPROTOBYNAME_R', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header - '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system -# '-DCONFIG_HAVE_PROC', -# example: crash handling -# '-DCONFIG_HAVE_BACKTRACE', -# timing -# '-DCONFIG_HAVE_PSELECT', -# '-DCONFIG_HAVE_RTC', -# '-DCONFIG_HAVE_TSC', -# '-DCONFIG_HAVE_HPET', -# event handling - '-DCONFIG_HAVE_POLL', -# '-DCONFIG_HAVE_EPOLL', -# interface enumeration -# '-DCONFIG_HAVE_GETIFADDRS', -# '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg -# '-DCONFIG_HAVE_WSACMSGHDR', -# multicast - '-DCONFIG_HAVE_MCAST_JOIN', -# '-DCONFIG_HAVE_IP_MREQN', -# sprintf -# '-DCONFIG_HAVE_SPRINTF_GROUPING', -# '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE', -# GNU getopt - '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ '-pipe' - ], - LIBS = [ -# histogram math - 'm', -# clock_gettime() - 'rt', -# Solaris sockets - 'resolv', - 'socket', - 'nsl' - ], - PROTOBUF_CCFLAGS = '-I/opt/glib-gcc64/include', - PROTOBUF_LIBS = '/opt/glib-gcc64/lib/sparcv9/libprotobuf.a', - PROTOBUF_PROTOC = '/opt/glib-gcc64/bin/protoc' -) -force_gcc(env); - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = ['-O2','-m64'], LINKFLAGS = '-m64') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb','-m64'], LINKFLAGS = ['-gdb','-m64']) - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O2','-pg','-m64'], LINKFLAGS = ['-pg','-m64']) - -thirtytwo = env.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = ['-O2','-m32'], LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp', - 'ssl', 'kstat', 'wrap', 'adm' ], - 'CPPPATH' : ['/opt/cws/include'], - 'LIBPATH' : ['/opt/csw/lib'], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-gcc64/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.sungcc b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.sungcc deleted file mode 100644 index a5be81f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.sungcc +++ /dev/null @@ -1,321 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 1, 0 ) -SConsignFile('scons.signatures'+ '-' + platform.system() + '-' + platform.machine() + '-sungcc'); - -vars = Variables() -vars.AddVariables ( - EnumVariable ('BUILD', 'build environment', 'debug', - allowed_values=('release', 'debug', 'profile')), - EnumVariable ('BRANCH', 'branch prediction', 'none', - allowed_values=('none', 'profile', 'seed')), - EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CHECK', 'Check test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_TEST', 'Network test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CC', 'C++ examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', - allowed_values=('true', 'false')), -) - -#----------------------------------------------------------------------------- -# Dependencies - -def force_gcc(env): - env.PrependENVPath('PATH', '/usr/sfw/bin'); - env.PrependENVPath('PATH', '/opt/glib-gcc/bin'); - env.Tool('gcc'); - env.Tool('g++'); - -env = Environment(); -force_gcc(env); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment( - variables = vars, - ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', -# '-Wunsafe-loop-optimizations', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', - '-pedantic', -# C99 - '-std=gnu99', - '-D_XOPEN_SOURCE=600', - '-D__EXTENSIONS__', - '-DBSD_COMP', - '-D_BSD_SOURCE', -# re-entrant libc - '-D_REENTRANT', - '-DCONFIG_HAVE_GETPROTOBYNAME_R', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header - '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system -# '-DCONFIG_HAVE_PROC', -# example: crash handling -# '-DCONFIG_HAVE_BACKTRACE', -# timing -# '-DCONFIG_HAVE_PSELECT', -# '-DCONFIG_HAVE_RTC', -# '-DCONFIG_HAVE_TSC', -# '-DCONFIG_HAVE_HPET', -# event handling - '-DCONFIG_HAVE_POLL', -# '-DCONFIG_HAVE_EPOLL', -# interface enumeration -# '-DCONFIG_HAVE_GETIFADDRS', -# '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg -# '-DCONFIG_HAVE_WSACMSGHDR', -# multicast - '-DCONFIG_HAVE_MCAST_JOIN', -# '-DCONFIG_HAVE_IP_MREQN', -# sprintf -# '-DCONFIG_HAVE_SPRINTF_GROUPING', -# '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE', -# GNU getopt - '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ '-pipe' - ], - LIBS = [ -# histogram math - 'm', -# clock_gettime() - 'rt', -# Solaris sockets - 'resolv', - 'socket', - 'nsl' - ], - PROTOBUF_CCFLAGS = '-I/opt/glib-gcc/include', - PROTOBUF_LIBS = '/opt/glib-gcc/lib/libprotobuf.a', - PROTOBUF_PROTOC = '/opt/glib-gcc/bin/protoc' -) -force_gcc(env); - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = ['-O2'], LINKFLAGS = []) - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG', '-ggdb'], LINKFLAGS = ['-gdb']) - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = ['-pg']) - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp', - 'ssl', 'kstat', 'wrap', 'adm' ], - 'CPPPATH' : ['/opt/cws/include'], - 'LIBPATH' : ['/opt/csw/lib'], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-sungcc/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.sunstudio b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.sunstudio deleted file mode 100644 index 435d907..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.Solaris.sunstudio +++ /dev/null @@ -1,306 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 1, 0 ) -SConsignFile('scons.signatures' + '-' + platform.system() + '-' + platform.machine() + '-sunstudio'); - -vars = Variables() -vars.AddVariables ( - EnumVariable ('BUILD', 'build environment', 'debug', - allowed_values=('release', 'debug', 'profile')), - EnumVariable ('BRANCH', 'branch prediction', 'none', - allowed_values=('none', 'profile', 'seed')), - EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CHECK', 'Check test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_TEST', 'Network test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CC', 'C++ examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_PLUS', 'libpgmplus GPL library', 'false', - allowed_values=('true', 'false')), -) - -#----------------------------------------------------------------------------- -# Dependencies - -def force_sunstudio(env): - env.PrependENVPath('PATH', '/usr/ccs/bin'); - env.PrependENVPath('PATH', '/opt/glib-sunstudio/bin'); - env.PrependENVPath('PATH', '/opt/sunstudio12.1/bin'); - env.Tool('sunc++'); - env.Tool('suncc'); - env.Tool('sunlink'); - env.Tool('sunar'); - -env = Environment(); -force_sunstudio(env); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' - Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' - Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' - Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment( - variables = vars, - ENV = os.environ, - CCFLAGS = [ '-v', -# C99 - '-xc99=all', - '-D_XOPEN_SOURCE=600', - '-D__EXTENSIONS__', - '-DBSD_COMP', - '-D_BSD_SOURCE', -# re-entrant libc - '-D_REENTRANT', - '-DCONFIG_HAVE_GETPROTOBYNAME_R', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header - '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system -# '-DCONFIG_HAVE_PROC', -# example: crash handling -# '-DCONFIG_HAVE_BACKTRACE', -# timing -# '-DCONFIG_HAVE_PSELECT', -# '-DCONFIG_HAVE_RTC', -# '-DCONFIG_HAVE_TSC', -# '-DCONFIG_HAVE_HPET', -# event handling - '-DCONFIG_HAVE_POLL', -# '-DCONFIG_HAVE_EPOLL', -# interface enumeration -# '-DCONFIG_HAVE_GETIFADDRS', -# '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg -# '-DCONFIG_HAVE_WSACMSGHDR', -# multicast - '-DCONFIG_HAVE_MCAST_JOIN', -# '-DCONFIG_HAVE_IP_MREQN', -# sprintf -# '-DCONFIG_HAVE_SPRINTF_GROUPING', -# '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE', -# GNU getopt - '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [], - LIBS = [ -# histogram math - 'm', -# clock_gettime() - 'rt', -# Solaris sockets - 'resolv', - 'socket', - 'nsl' - ], - PROTOBUF_CCFLAGS = '-I/opt/glib-sunstudio/include', - PROTOBUF_LIBS = '/opt/glib-sunstudio/lib/sparcv9/libprotobuf.a', - PROTOBUF_PROTOC = '/opt/glib-sunstudio/bin/protoc' -) -force_sunstudio(env); - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = ['-xO2','-m64'], LINKFLAGS = '-m64') - -# outstanding defect with 12u1 cannot compile extended asm without optimization.:w -# -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG','-xO1', '-g','-m64'], LINKFLAGS = ['-g','-m64']) - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-xO2','-pg','-m64'], LINKFLAGS = ['-pg','-m64']) - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = ['-xO2','-m32'], LINKFLAGS = '-m32'); - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp', - 'ssl', 'kstat', 'wrap', 'adm' ], - 'CPPPATH' : ['/opt/cws/include'], - 'LIBPATH' : ['/opt/csw/lib'], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-sunstudio/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.clang b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.clang deleted file mode 100644 index 7f0a54a..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.clang +++ /dev/null @@ -1,336 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 1, 0 ) -SConsignFile('scons.signatures' + '-' + platform.system() + '-' + platform.machine() + '-clang'); - -vars = Variables() -vars.AddVariables ( - EnumVariable ('BUILD', 'build environment', 'debug', - allowed_values=('release', 'debug', 'profile')), - EnumVariable ('BRANCH', 'branch prediction', 'none', - allowed_values=('none', 'profile', 'seed')), - EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', - allowed_values=('true', 'false')), - EnumVariable ('COVERAGE', 'test coverage', 'none', - allowed_values=('none', 'full')), - EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CHECK', 'Check test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_TEST', 'Network test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CC', 'C++ examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', - allowed_values=('true', 'false')), -) - -#----------------------------------------------------------------------------- -# Dependencies - -def force_clang(env): - env['CC'] = 'clang'; - -env = Environment(); -force_clang(env); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment( - variables = vars, - ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', -# '-Wunsafe-loop-optimizations', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', -# '-pedantic', -# C99 - '-std=gnu99', -# re-entrant libc - '-D_REENTRANT', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R', - '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system - '-DCONFIG_HAVE_PROC', -# example: crash handling - '-DCONFIG_HAVE_BACKTRACE', -# timing - '-DCONFIG_HAVE_PSELECT', - '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', - '-DCONFIG_HAVE_HPET', -# event handling - '-DCONFIG_HAVE_POLL', - '-DCONFIG_HAVE_EPOLL', -# interface enumeration - '-DCONFIG_HAVE_GETIFADDRS', - '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg -# '-DCONFIG_HAVE_WSACMSGHDR', -# multicast - '-DCONFIG_HAVE_MCAST_JOIN', - '-DCONFIG_HAVE_IP_MREQN', -# sprintf - '-DCONFIG_HAVE_SPRINTF_GROUPING', - '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE', -# GNU getopt - '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ '-pipe' - ], - LIBS = [ -# histogram math - 'm', -# clock_gettime() - 'rt' - ] -) -force_clang(env); - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Coverage analysis -if env['COVERAGE'] == 'full': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(CCFLAGS = '-ftest-coverage') - env.Append(LINKFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-lgcov') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = '-O2') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-gdb') - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -def CheckEventFD(context): - context.Message('Checking eventfd...'); - result = context.TryLink(""" -#include -int main(int argc, char**argv) -{ - eventfd(0,0); - return 0; -} -""", '.c') - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck, - 'CheckEventFD': CheckEventFD -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Enabling extra Red Hat dependencies for Net-SNMP.'; - conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); - lastLIBS = conf.env['LIBS']; - conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); - conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); - conf.env.Replace(LIBS = lastLIBS); - if not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -if conf.CheckEventFD(): - print 'Enabling kernel eventfd notification mechanism.'; - conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-clang/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.mingw b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.mingw deleted file mode 100644 index 5f54704..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.mingw +++ /dev/null @@ -1,330 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 1, 0 ) -SConsignFile('scons.signatures' + '-Win32-' + platform.machine()); - -vars = Variables() -vars.AddVariables ( - EnumVariable ('BUILD', 'build environment', 'debug', - allowed_values=('release', 'debug', 'profile')), - EnumVariable ('BRANCH', 'branch prediction', 'none', - allowed_values=('none', 'profile', 'seed')), - EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', - allowed_values=('true', 'false')), - EnumVariable ('COVERAGE', 'test coverage', 'none', - allowed_values=('none', 'full')), - EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CHECK', 'Check test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_TEST', 'Network test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CC', 'C++ examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', - allowed_values=('true', 'false')), -) - -#----------------------------------------------------------------------------- -# Dependencies - -def force_mingw(env): - env.Tool('crossmingw', toolpath=['.']); - -env = Environment(); -force_mingw(env); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment( - variables = vars, - ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', - '-Wunsafe-loop-optimizations', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', - '-pedantic', -# C99 - '-std=gnu99', - '-D_GNU_SOURCE', - '-D_WIN32_WINNT=0x0501', -# re-entrant libc - '-D_REENTRANT', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header -# '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system -# '-DCONFIG_HAVE_PROC', -# example: crash handling -# '-DCONFIG_HAVE_BACKTRACE', -# timing -# '-DCONFIG_HAVE_PSELECT', -# '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', -# '-DCONFIG_HAVE_HPET', -# event handling -# '-DCONFIG_HAVE_POLL', -# '-DCONFIG_HAVE_EPOLL', -# interface enumeration -# '-DCONFIG_HAVE_GETIFADDRS', -# '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg - '-DCONFIG_HAVE_WSACMSGHDR', -# multicast -# '-DCONFIG_HAVE_MCAST_JOIN', -# '-DCONFIG_HAVE_IP_MREQN', -# sprintf -# '-DCONFIG_HAVE_SPRINTF_GROUPING', -# '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support -# '-DCONFIG_TARGET_WINE', -# GNU getopt -# '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ '-pipe' - ], - LIBS = [ - 'iphlpapi.lib', - 'ws2_32.lib' - ] -) -force_mingw(env); - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Coverage analysis -if env['COVERAGE'] == 'full': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(CCFLAGS = '-ftest-coverage') - env.Append(LINKFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-lgcov') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = '-O2') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = ['-gdb']) - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --cflags --libs glib-2.0 gthread-2.0'); - env.MergeFlags('-Iwin/include -Lwin/lib'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -if env['WITH_SNMP'] == 'true': - env['SNMP_FLAGS'] = env.ParseFlags('-Iwin/include -Lwin/lib -lnetsnmpagent -lnetsnmphelpers -lnetsnmp'); - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -def CheckEventFD(context): - context.Message('Checking eventfd...'); - result = context.TryLink(""" -#include -int main(int argc, char**argv) -{ - eventfd(0,0); - return 0; -} -""", '.c') - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck, - 'CheckEventFD': CheckEventFD -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -if conf.CheckEventFD(): - print 'Enabling kernel eventfd notification mechanism.'; - conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-Win32-' + platform.machine() + '/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.mingw-wine b/3rdparty/openpgm-svn-r1085/pgm/SConstruct.mingw-wine deleted file mode 100644 index 6af1e0a..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/SConstruct.mingw-wine +++ /dev/null @@ -1,339 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script - -import platform -import os -import time -import sys - -EnsureSConsVersion( 1, 0 ) -SConsignFile('scons.signatures' + '-Wine-' + platform.machine()); - -vars = Variables() -vars.AddVariables ( - EnumVariable ('BUILD', 'build environment', 'debug', - allowed_values=('release', 'debug', 'profile')), - EnumVariable ('BRANCH', 'branch prediction', 'none', - allowed_values=('none', 'profile', 'seed')), - EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', - allowed_values=('true', 'false')), - EnumVariable ('COVERAGE', 'test coverage', 'none', - allowed_values=('none', 'full')), - EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CHECK', 'Check test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_TEST', 'Network test system', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_CC', 'C++ examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', - allowed_values=('true', 'false')), - EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', - allowed_values=('true', 'false')), - EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', - allowed_values=('true', 'false')), -) - -#----------------------------------------------------------------------------- -# Dependencies - -def force_mingw(env): - env.Tool('crossmingw', toolpath=['.']); - -env = Environment(); -force_mingw(env); - -def CheckPKGConfig(context, version): - context.Message( 'Checking for pkg-config... ' ) - ret = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --atleast-pkgconfig-version=%s' % version)[0] - context.Result( ret ) - return ret - -def CheckPKG(context, name): - context.Message( 'Checking for %s... ' % name ) - ret = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --exists \'%s\'' % name)[0] - context.Result( ret ) - return ret - -conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, - 'CheckPKG' : CheckPKG }) - -if not conf.CheckPKGConfig('0.15.0'): - print 'pkg-config >= 0.15.0 not found.' -# Exit(1) - -if not conf.CheckPKG('glib-2.0 >= 2.10'): - print 'glib-2.0 >= 2.10 not found.' -# Exit(1) - -if not conf.CheckPKG('gthread-2.0'): - print 'gthread-2.0 not found.' -# Exit(1) - -env = conf.Finish(); - -#----------------------------------------------------------------------------- -# Platform specifics - -env = Environment( - variables = vars, - ENV = os.environ, - CCFLAGS = [ '-pipe', - '-Wall', - '-Wextra', - '-Wfloat-equal', - '-Wshadow', - '-Wunsafe-loop-optimizations', - '-Wpointer-arith', - '-Wbad-function-cast', - '-Wcast-qual', - '-Wcast-align', - '-Wwrite-strings', - '-Waggregate-return', - '-Wstrict-prototypes', - '-Wold-style-definition', - '-Wmissing-prototypes', - '-Wmissing-declarations', - '-Wmissing-noreturn', - '-Wmissing-format-attribute', - '-Wredundant-decls', - '-Wnested-externs', - '-Winline', - '-pedantic', -# C99 - '-std=gnu99', - '-D_GNU_SOURCE', - '-D_WIN32_WINNT=0x0501', -# re-entrant libc - '-D_REENTRANT', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R', -# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', -# variadic macros - '-DCONFIG_HAVE_ISO_VARARGS', -# '-DCONFIG_HAVE_GNUC_VARARGS', -# stack memory api header -# '-DCONFIG_HAVE_ALLOCA_H', -# optimium checksum implementation -# '-DCONFIG_8BIT_CHECKSUM', - '-DCONFIG_16BIT_CHECKSUM', -# '-DCONFIG_32BIT_CHECKSUM', -# '-DCONFIG_64BIT_CHECKSUM', -# '-DCONFIG_VECTOR_CHECKSUM', -# useful /proc system -# '-DCONFIG_HAVE_PROC', -# example: crash handling -# '-DCONFIG_HAVE_BACKTRACE', -# timing -# '-DCONFIG_HAVE_PSELECT', -# '-DCONFIG_HAVE_RTC', - '-DCONFIG_HAVE_TSC', -# '-DCONFIG_HAVE_HPET', -# event handling -# '-DCONFIG_HAVE_POLL', -# '-DCONFIG_HAVE_EPOLL', -# interface enumeration -# '-DCONFIG_HAVE_GETIFADDRS', -# '-DCONFIG_HAVE_IFR_NETMASK', -# win32 cmsg -# '-DCONFIG_HAVE_WSACMSGHDR', -# multicast -# '-DCONFIG_HAVE_MCAST_JOIN', -# '-DCONFIG_HAVE_IP_MREQN', -# sprintf -# '-DCONFIG_HAVE_SPRINTF_GROUPING', -# '-DCONFIG_HAVE_VASPRINTF', -# symbol linking scope - '-DCONFIG_HAVE_DSO_VISIBILITY', -# socket binding - '-DCONFIG_BIND_INADDR_ANY', -# IP header order as per IP(4) on FreeBSD -# '-DCONFIG_HOST_ORDER_IP_LEN', -# '-DCONFIG_HOST_ORDER_IP_OFF', -# optimum galois field multiplication - '-DCONFIG_GALOIS_MUL_LUT', -# Wine limited API support - '-DCONFIG_TARGET_WINE', -# GNU getopt -# '-DCONFIG_HAVE_GETOPT' - ], - LINKFLAGS = [ '-pipe' - ], - LIBS = [ - 'iphlpapi.lib', - 'ws2_32.lib' - ] -) -force_mingw(env); - -# Branch prediction -if env['BRANCH'] == 'profile': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-fprofile-arcs') -elif env['BRANCH'] == 'seed': - env.Append(CCFLAGS = '-fbranch-probabilities') - -# Coverage analysis -if env['COVERAGE'] == 'full': - env.Append(CCFLAGS = '-fprofile-arcs') - env.Append(CCFLAGS = '-ftest-coverage') - env.Append(LINKFLAGS = '-fprofile-arcs') - env.Append(LINKFLAGS = '-lgcov') - -# Define separate build environments -release = env.Clone(BUILD = 'release') -release.Append(CCFLAGS = '-O2') - -debug = env.Clone(BUILD = 'debug') -debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = ['-gdb']) - -profile = env.Clone(BUILD = 'profile') -profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') - -thirtytwo = release.Clone(BUILD = 'thirtytwo') -thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') - -# choose and environment to build -if env['BUILD'] == 'release': - Export({'env':release}) -elif env['BUILD'] == 'profile': - Export({'env':profile}) -elif env['BUILD'] == 'thirtytwo': - Export({'env':thirtytwo}) -else: - Export({'env':debug}) - -#----------------------------------------------------------------------------- -# Re-analyse dependencies - -Import('env') - -# vanilla environment -if env['WITH_GLIB'] == 'true': - env['GLIB_FLAGS'] = env.ParseFlags('!PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --cflags --libs glib-2.0 gthread-2.0'); - env.MergeFlags('-Iwin/include -Lwin/lib'); -else: - env['GLIB_FLAGS'] = ''; - -# l10n -if env['WITH_GETTEXT'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); - -# instrumentation -if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': - env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); - -# managed environment for libpgmsnmp, libpgmhttp -env['SNMP_FLAGS'] = { - 'CCFLAGS' : [], - 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], -}; - -def CheckSNMP(context): - context.Message('Checking Net-SNMP...'); - lastLIBS = context.env['LIBS']; - lastCCFLAGS= context.env['CCFLAGS']; - context.env.MergeFlags(env['SNMP_FLAGS']); - result = context.TryLink(""" -int main(int argc, char**argv) -{ - init_agent("PGM"); - return 0; -} -""", '.c'); - context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); - context.Result(not result); - return result; - -def CheckCheck(context): - context.Message('Checking Check unit test framework...'); - result = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --cflags --libs check')[0]; - context.Result(result); - return result; - -def CheckEventFD(context): - context.Message('Checking eventfd...'); - result = context.TryLink(""" -#include -int main(int argc, char**argv) -{ - eventfd(0,0); - return 0; -} -""", '.c') - context.Result(result); - return result; - -tests = { - 'CheckCheck': CheckCheck, - 'CheckEventFD': CheckEventFD -} -if env['WITH_SNMP'] == 'true': - tests['CheckSNMP'] = CheckSNMP; -conf = Configure(env, custom_tests = tests); - -if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): - print 'Enabling extra Red Hat dependencies for Net-SNMP.'; - conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); - lastLIBS = conf.env['LIBS']; - conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); - conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); - conf.env.Replace(LIBS = lastLIBS); - if not conf.CheckSNMP(): - print 'Net-SNMP libraries not compatible.'; - Exit(1); - -if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): - print 'Enabling Check unit tests.'; - conf.env['CHECK'] = 'true'; -else: - print 'Disabling Check unit tests.'; - conf.env['CHECK'] = 'false'; - -if conf.CheckEventFD(): - print 'Enabling kernel eventfd notification mechanism.'; - conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); - -env = conf.Finish(); - -# add builder to create PIC static libraries for including in shared libraries -action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; -if env.Detect('ranlib'): - ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); - action_list.append(ranlib_action); -pic_lib = Builder( action = action_list, - emitter = '$LIBEMITTER', - prefix = '$LIBPREFIX', - suffix = '$LIBSUFFIX', - src_suffix = '$OBJSUFFIX', - src_builder = 'SharedObject') -env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); - - -#----------------------------------------------------------------------------- - -ref_node = 'ref/' + env['BUILD'] + '-Wine-' + platform.machine() + '/'; -BuildDir(ref_node, '.', duplicate=0) - -env.Append(CPPPATH = os.getcwd() + '/include'); -env.Append(LIBPATH = os.getcwd() + '/' + ref_node); - -if env['WITH_GLIB'] == 'true': - SConscript(ref_node + 'SConscript.libpgmex'); -SConscript(ref_node + 'SConscript.libpgm'); -if env['WITH_HTTP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmhttp'); -if env['WITH_SNMP'] == 'true': - SConscript(ref_node + 'SConscript.libpgmsnmp'); -if env['WITH_TEST'] == 'true': - SConscript(ref_node + 'test/SConscript'); -if env['WITH_EXAMPLES'] == 'true': - SConscript(ref_node + 'examples/SConscript'); - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/atomic_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/atomic_unittest.c deleted file mode 100644 index a301c28..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/atomic_unittest.c +++ /dev/null @@ -1,166 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for atomic operations. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include - - -/* mock state */ - - -/* mock functions for external references */ - -#define PGM_COMPILATION -#include "pgm/atomic.h" - - -/* target: - * uint32_t - * pgm_atomic_exchange_and_add32 ( - * volatile uint32_t* atomic, - * const uint32_t val - * ) - */ - -START_TEST (test_int32_exchange_and_add_pass_001) -{ - volatile uint32_t atomic = 0; - fail_unless (0 == pgm_atomic_exchange_and_add32 (&atomic, 5)); - fail_unless (5 == atomic); - fail_unless (5 == pgm_atomic_exchange_and_add32 (&atomic, (uint32_t)-10)); - fail_unless ((uint32_t)-5 == atomic); -} -END_TEST - -/* target: - * void - * pgm_atomic_add32 ( - * volatile uint32_t* atomic, - * const uint32_t val - * ) - */ - -START_TEST (test_int32_add_pass_001) -{ - volatile uint32_t atomic = (uint32_t)-5; - pgm_atomic_add32 (&atomic, 20); - fail_unless (15 == atomic); - pgm_atomic_add32 (&atomic, (uint32_t)-35); - fail_unless ((uint32_t)-20 == atomic); -} -END_TEST - -/* ensure wrap around when casting uint32 */ -START_TEST (test_int32_add_pass_002) -{ - volatile uint32_t atomic = 0; - pgm_atomic_add32 (&atomic, UINT32_MAX/2); - fail_unless ((UINT32_MAX/2) == atomic); - pgm_atomic_add32 (&atomic, UINT32_MAX - (UINT32_MAX/2)); - fail_unless (UINT32_MAX == atomic); - pgm_atomic_add32 (&atomic, 1); - fail_unless (0 == atomic); -} -END_TEST - -/* target: - * uint32_t - * pgm_atomic_read32 ( - * volatile uint32_t* atomic - * ) - */ - -START_TEST (test_int32_get_pass_001) -{ - volatile uint32_t atomic = (uint32_t)-20; - fail_unless ((uint32_t)-20 == pgm_atomic_read32 (&atomic)); -} -END_TEST - -/* target: - * void - * pgm_atomic_int32_set ( - * volatile int32_t* atomic, - * const int32_t val - * ) - */ - -START_TEST (test_int32_set_pass_001) -{ - volatile uint32_t atomic = (uint32_t)-20; - pgm_atomic_write32 (&atomic, 5); - fail_unless (5 == atomic); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_exchange_and_add = tcase_create ("exchange-and-add"); - suite_add_tcase (s, tc_exchange_and_add); - tcase_add_test (tc_exchange_and_add, test_int32_exchange_and_add_pass_001); - - TCase* tc_add = tcase_create ("add"); - suite_add_tcase (s, tc_add); - tcase_add_test (tc_add, test_int32_add_pass_001); - tcase_add_test (tc_add, test_int32_add_pass_002); - - TCase* tc_get = tcase_create ("get"); - suite_add_tcase (s, tc_get); - tcase_add_test (tc_get, test_int32_get_pass_001); - - TCase* tc_set = tcase_create ("set"); - suite_add_tcase (s, tc_set); - tcase_add_test (tc_set, test_int32_set_pass_001); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/backtrace.c b/3rdparty/openpgm-svn-r1085/pgm/backtrace.c deleted file mode 100644 index 2e9943d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/backtrace.c +++ /dev/null @@ -1,69 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Dump back trace to stderr and try gdb. - * - * Copyright (c) 2006-2007 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef CONFIG_HAVE_BACKTRACE -# include -# include -# include -# include -# include -#endif -#include -#include - - -void -on_sigsegv ( - G_GNUC_UNUSED int signum - ) -{ -#ifdef CONFIG_HAVE_BACKTRACE - void* array[256]; - char** names; - char cmd[1024]; - int i, size; - gchar *out, *err; - gint exit_status; - - fprintf (stderr, "\n======= Backtrace: =========\n"); - - size = backtrace (array, G_N_ELEMENTS(array)); - names = backtrace_symbols (array, size); - - for (i = 0; i < size; i++) - fprintf (stderr, "%s\n", names[i]); - - free (names); - fflush (stderr); - - sprintf (cmd, "gdb --ex 'attach %ld' --ex 'info threads' --ex 'thread apply all bt' --batch", (long)getpid ()); - if ( g_spawn_command_line_sync (cmd, &out, &err, &exit_status, NULL) ) - { - fprintf (stderr, "======= GDB Backtrace: =========\n"); - fprintf (stderr, "%s\n", out); - } -#endif /* CONFIG_HAVE_BACKTRACE */ - - abort (); -} - -/* eof */ - diff --git a/3rdparty/openpgm-svn-r1085/pgm/checksum.c b/3rdparty/openpgm-svn-r1085/pgm/checksum.c deleted file mode 100644 index 959aceb..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/checksum.c +++ /dev/null @@ -1,941 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM checksum routines - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - - -/* locals */ - -static inline uint16_t do_csum (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; -static uint16_t do_csum_8bit (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; -static uint16_t do_csum_16bit (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; -static uint16_t do_csum_32bit (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; -static uint16_t do_csum_64bit (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; -#if defined(__amd64) || defined(__x86_64__) -static uint16_t do_csum_vector (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; -#endif - - -/* endian independent checksum routine - */ - -static -uint16_t -do_csum_8bit ( - const void* addr, - uint16_t len, - uint32_t csum - ) -{ - uint_fast32_t acc; - uint16_t src; - const uint8_t* buf; - - acc = csum; - buf = (const uint8_t*)addr; - while (len > 1) { -/* first byte as most significant */ - src = (*buf++) << 8; -/* second byte as least significant */ - src |= (*buf++); - acc += src; - len -= 2; - } -/* trailing odd byte */ - if (len > 0) { - src = (*buf) << 8; - acc += src; - } - acc = (acc >> 16) + (acc & 0xffff); - acc += (acc >> 16); - return htons ((uint16_t)acc); -} - -static -uint16_t -do_csumcpy_8bit ( - const void* restrict srcaddr, - void* restrict dstaddr, - uint16_t len, - uint32_t csum - ) -{ - uint_fast32_t acc; - const uint8_t*restrict srcbuf; - uint8_t*restrict dstbuf; - uint_fast16_t val16; - - acc = csum; - srcbuf = (const uint8_t*restrict)srcaddr; - dstbuf = (uint8_t*restrict)dstaddr; - while (len > 1) { -/* first byte as most significant */ - val16 = (*dstbuf++ = *srcbuf++) << 8; -/* second byte as least significant */ - val16 |= (*dstbuf++ = *srcbuf++); - acc += val16; - len -= 2; - } -/* trailing odd byte */ - if (len > 0) { - val16 = (*dstbuf = *srcbuf) << 8; - acc += val16; - } - acc = (acc >> 16) + (acc & 0xffff); - acc += (acc >> 16); - return htons ((uint16_t)acc); -} - -static -uint16_t -do_csum_16bit ( - const void* addr, - uint16_t len, - uint32_t csum - ) -{ - uint_fast32_t acc; - const uint8_t* buf; - uint16_t remainder; - uint_fast16_t count8; - bool is_odd; - - acc = csum; - buf = (const uint8_t*)addr; - remainder = 0; - - if (PGM_UNLIKELY(len == 0)) - return acc; - is_odd = ((uintptr_t)buf & 1); -/* align first byte */ - if (PGM_UNLIKELY(is_odd)) { - ((uint8_t*)&remainder)[1] = *buf++; - len--; - } -/* 8-byte unrolls */ - count8 = len >> 3; - while (count8--) { - acc += ((const uint16_t*)buf)[ 0 ]; - acc += ((const uint16_t*)buf)[ 1 ]; - acc += ((const uint16_t*)buf)[ 2 ]; - acc += ((const uint16_t*)buf)[ 3 ]; - buf = &buf[ 8 ]; - } - len %= 8; -/* final 7 bytes */ - while (len > 1) { - acc += ((const uint16_t*)buf)[ 0 ]; - buf = &buf[ 2 ]; - len -= 2; - } -/* trailing odd byte */ - if (len > 0) { - ((uint8_t*)&remainder)[0] = *buf; - } - acc += remainder; - acc = (acc >> 16) + (acc & 0xffff); - acc += (acc >> 16); - if (PGM_UNLIKELY(is_odd)) - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - return acc; -} - -static -uint16_t -do_csumcpy_16bit ( - const void* restrict srcaddr, - void* restrict dstaddr, - uint16_t len, - uint32_t csum - ) -{ - uint_fast32_t acc; - const uint8_t*restrict srcbuf; - uint8_t*restrict dstbuf; - uint16_t remainder; - uint_fast16_t count8; - bool is_odd; - - acc = csum; - srcbuf = (const uint8_t*restrict)srcaddr; - dstbuf = (uint8_t*restrict)dstaddr; - remainder = 0; - - if (PGM_UNLIKELY(len == 0)) - return acc; - is_odd = ((uintptr_t)srcbuf & 1); -/* align first byte */ - if (PGM_UNLIKELY(is_odd)) { - ((uint8_t*restrict)&remainder)[1] = *dstbuf++ = *srcbuf++; - len--; - } -/* 8-byte unrolls, anything larger than 16-byte or less than 8 loses performance */ - count8 = len >> 3; - while (count8--) { - acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; - acc += ((uint16_t*restrict)dstbuf)[ 1 ] = ((const uint16_t*restrict)srcbuf)[ 1 ]; - acc += ((uint16_t*restrict)dstbuf)[ 2 ] = ((const uint16_t*restrict)srcbuf)[ 2 ]; - acc += ((uint16_t*restrict)dstbuf)[ 3 ] = ((const uint16_t*restrict)srcbuf)[ 3 ]; - srcbuf = &srcbuf[ 8 ]; - dstbuf = &dstbuf[ 8 ]; - } - len %= 8; -/* final 7 bytes */ - while (len > 1) { - acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; - srcbuf = &srcbuf[ 2 ]; - dstbuf = &dstbuf[ 2 ]; - len -= 2; - } -/* trailing odd byte */ - if (len > 0) { - ((uint8_t*restrict)&remainder)[0] = *dstbuf = *srcbuf; - } - acc += remainder; - acc = (acc >> 16) + (acc & 0xffff); - acc += (acc >> 16); - if (PGM_UNLIKELY(is_odd)) - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - return acc; -} - -static -uint16_t -do_csum_32bit ( - const void* addr, - uint16_t len, - uint32_t csum - ) -{ - uint_fast32_t acc; - const uint8_t* buf; - uint16_t remainder; - uint_fast16_t count; - bool is_odd; - - acc = csum; - buf = (const uint8_t*)addr; - remainder = 0; - - if (PGM_UNLIKELY(len == 0)) - return acc; - is_odd = ((uintptr_t)buf & 1); -/* align first byte */ - if (PGM_UNLIKELY(is_odd)) { - ((uint8_t*)&remainder)[1] = *buf++; - len--; - } -/* 16-bit words */ - count = len >> 1; - if (count) - { - if ((uintptr_t)buf & 2) { - acc += ((const uint16_t*)buf)[ 0 ]; - buf = &buf[ 2 ]; - count--; - len -= 2; - } -/* 32-bit words */ - count >>= 1; - if (count) - { - uint32_t carry = 0; - while (count) { - acc += carry; - acc += ((const uint32_t*)buf)[ 0 ]; - carry = ((const uint32_t*)buf)[ 0 ] > acc; - buf = &buf[ 4 ]; - count--; - } - acc += carry; - acc = (acc >> 16) + (acc & 0xffff); - } - if (len & 2) { - acc += ((const uint16_t*)buf)[ 0 ]; - buf = &buf[ 2 ]; - } - } -/* trailing odd byte */ - if (len & 1) { - ((uint8_t*)&remainder)[0] = *buf; - } - acc += remainder; - acc = (acc >> 16) + (acc & 0xffff); - acc += (acc >> 16); - if (PGM_UNLIKELY(is_odd)) - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - return acc; -} - -static -uint16_t -do_csumcpy_32bit ( - const void* restrict srcaddr, - void* restrict dstaddr, - uint16_t len, - uint32_t csum - ) -{ - uint_fast32_t acc; - const uint8_t*restrict srcbuf; - uint8_t*restrict dstbuf; - uint16_t remainder; - uint_fast16_t count; - bool is_odd; - - acc = csum; - srcbuf = (const uint8_t*restrict)srcaddr; - dstbuf = (uint8_t*restrict)dstaddr; - remainder = 0; - - if (PGM_UNLIKELY(len == 0)) - return acc; - is_odd = ((uintptr_t)srcbuf & 1); -/* align first byte */ - if (PGM_UNLIKELY(is_odd)) { - ((uint8_t*restrict)&remainder)[1] = *dstbuf++ = *srcbuf++; - len--; - } -/* 16-bit words */ - count = len >> 1; - if (count) - { - if ((uintptr_t)srcbuf & 2) { - acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; - srcbuf = &srcbuf[ 2 ]; - dstbuf = &dstbuf[ 2 ]; - count--; - len -= 2; - } -/* 32-bit words */ - count >>= 1; - if (count) - { - uint32_t carry = 0; - while (count) { - acc += carry; - acc += ((uint32_t*restrict)dstbuf)[ 0 ] = ((const uint32_t*restrict)srcbuf)[ 0 ]; - carry = ((const uint32_t*restrict)dstbuf)[ 0 ] > acc; - srcbuf = &srcbuf[ 4 ]; - dstbuf = &dstbuf[ 4 ]; - count--; - } - acc += carry; - acc = (acc >> 16) + (acc & 0xffff); - } - if (len & 2) { - acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; - srcbuf = &srcbuf[ 2 ]; - dstbuf = &dstbuf[ 2 ]; - } - } -/* trailing odd byte */ - if (len & 1) { - ((uint8_t*restrict)&remainder)[0] = *dstbuf = *srcbuf; - } - acc += remainder; - acc = (acc >> 16) + (acc & 0xffff); - acc += (acc >> 16); - if (PGM_UNLIKELY(is_odd)) - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - return acc; -} - -/* best if architecture has native 64-bit words - */ - -static -uint16_t -do_csum_64bit ( - const void* addr, - uint16_t len, - uint32_t csum - ) -{ - uint_fast64_t acc; - const uint8_t* buf; - uint16_t remainder; - uint_fast16_t count; - bool is_odd; - - acc = csum; - buf = (const uint8_t*)addr; - remainder = 0; - - if (PGM_UNLIKELY(len == 0)) - return acc; - is_odd = ((uintptr_t)buf & 1); -/* align first byte */ - if (PGM_UNLIKELY(is_odd)) { - ((uint8_t*)&remainder)[1] = *buf++; - len--; - } -/* 16-bit words */ - count = len >> 1; - if (count) - { - if ((uintptr_t)buf & 2) { - acc += ((const uint16_t*)buf)[ 0 ]; - buf = &buf[ 2 ]; - count--; - len -= 2; - } -/* 32-bit words */ - count >>= 1; - if (count) - { - if ((uintptr_t)buf & 4) { - acc += ((const uint32_t*)buf)[ 0 ]; - buf = &buf[ 4 ]; - count--; - len -= 4; - } -/* 64-bit words */ - count >>= 1; - if (count) - { - uint_fast64_t carry = 0; - while (count) { - acc += carry; - acc += ((const uint64_t*)buf)[ 0 ]; - carry = ((const uint64_t*)buf)[ 0 ] > acc; - buf = &buf[ 8 ]; - count--; - } - acc += carry; - acc = (acc >> 32) + (acc & 0xffffffff); - } - if (len & 4) { - acc += ((const uint32_t*)buf)[ 0 ]; - buf = &buf[ 4 ]; - } - } - if (len & 2) { - acc += ((const uint16_t*)buf)[ 0 ]; - buf = &buf[ 2 ]; - } - } -/* trailing odd byte */ - if (len & 1) { - ((uint8_t*)&remainder)[0] = *buf; - } - acc += remainder; - acc = (acc >> 32) + (acc & 0xffffffff); - acc = (acc >> 16) + (acc & 0xffff); - acc = (acc >> 16) + (acc & 0xffff); - acc += (acc >> 16); - if (PGM_UNLIKELY(is_odd)) - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - return acc; -} - -static -uint16_t -do_csumcpy_64bit ( - const void* restrict srcaddr, - void* restrict dstaddr, - uint16_t len, - uint32_t csum - ) -{ - uint_fast64_t acc; - const uint8_t* restrict srcbuf; - uint8_t* restrict dstbuf; - uint16_t remainder; - uint_fast16_t count; - bool is_odd; - - acc = csum; - srcbuf = (const uint8_t*restrict)srcaddr; - dstbuf = (uint8_t*restrict)dstaddr; - remainder = 0; - - if (PGM_UNLIKELY(len == 0)) - return acc; - is_odd = ((uintptr_t)srcbuf & 1); -/* align first byte */ - if (PGM_UNLIKELY(is_odd)) { - ((uint8_t*restrict)&remainder)[1] = *dstbuf++ = *srcbuf++; - len--; - } -/* 16-bit words */ - count = len >> 1; - if (count) - { - if ((uintptr_t)srcbuf & 2) { - acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; - srcbuf = &srcbuf[ 2 ]; - dstbuf = &dstbuf[ 2 ]; - count--; - len -= 2; - } -/* 32-bit words */ - count >>= 1; - if (count) - { - if ((uintptr_t)srcbuf & 4) { - acc += ((uint32_t*restrict)dstbuf)[ 0 ] = ((const uint32_t*restrict)srcbuf)[ 0 ]; - srcbuf = &srcbuf[ 4 ]; - dstbuf = &dstbuf[ 4 ]; - count--; - len -= 4; - } -/* 64-bit words */ - count >>= 1; - if (count) - { -/* 64-byte blocks */ - uint_fast64_t carry = 0; - uint_fast16_t count64 = count >> 3; - if (count64) - { - carry = 0; - while (count64) { - acc += carry; - acc += ((uint64_t*restrict)dstbuf)[ 0 ] = ((const uint64_t*restrict)srcbuf)[ 0 ]; - carry = ((const uint64_t*restrict)dstbuf)[ 0 ] > acc; - acc += carry; - acc += ((uint64_t*restrict)dstbuf)[ 1 ] = ((const uint64_t*restrict)srcbuf)[ 1 ]; - carry = ((const uint64_t*restrict)dstbuf)[ 1 ] > acc; - acc += carry; - acc += ((uint64_t*restrict)dstbuf)[ 2 ] = ((const uint64_t*restrict)srcbuf)[ 2 ]; - carry = ((const uint64_t*restrict)dstbuf)[ 2 ] > acc; - acc += carry; - acc += ((uint64_t*restrict)dstbuf)[ 3 ] = ((const uint64_t*restrict)srcbuf)[ 3 ]; - carry = ((const uint64_t*restrict)dstbuf)[ 3 ] > acc; - acc += carry; - acc += ((uint64_t*restrict)dstbuf)[ 4 ] = ((const uint64_t*restrict)srcbuf)[ 4 ]; - carry = ((const uint64_t*restrict)dstbuf)[ 4 ] > acc; - acc += carry; - acc += ((uint64_t*restrict)dstbuf)[ 5 ] = ((const uint64_t*restrict)srcbuf)[ 5 ]; - carry = ((const uint64_t*restrict)dstbuf)[ 5 ] > acc; - acc += carry; - acc += ((uint64_t*restrict)dstbuf)[ 6 ] = ((const uint64_t*restrict)srcbuf)[ 6 ]; - carry = ((const uint64_t*restrict)dstbuf)[ 6 ] > acc; - acc += carry; - acc += ((uint64_t*restrict)dstbuf)[ 7 ] = ((const uint64_t*restrict)srcbuf)[ 7 ]; - carry = ((const uint64_t*restrict)dstbuf)[ 7 ] > acc; - srcbuf = &srcbuf[ 64 ]; - dstbuf = &dstbuf[ 64 ]; - count64--; - } - acc += carry; - acc = (acc >> 32) + (acc & 0xffffffff); - count %= 8; - } - -/* last 56 bytes */ - carry = 0; - while (count) { - acc += carry; - acc += ((uint64_t*restrict)dstbuf)[ 0 ] = ((const uint64_t*restrict)srcbuf)[ 0 ]; - carry = ((const uint64_t*restrict)dstbuf)[ 0 ] > acc; - srcbuf = &srcbuf[ 8 ]; - dstbuf = &dstbuf[ 8 ]; - count--; - } - acc += carry; - acc = (acc >> 32) + (acc & 0xffffffff); - } - if (len & 4) { - acc += ((uint32_t*restrict)dstbuf)[ 0 ] = ((const uint32_t*restrict)srcbuf)[ 0 ]; - srcbuf = &srcbuf[ 4 ]; - dstbuf = &dstbuf[ 4 ]; - } - } - if (len & 2) { - acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; - srcbuf = &srcbuf[ 2 ]; - dstbuf = &dstbuf[ 2 ]; - } - } -/* trailing odd byte */ - if (len & 1) { - ((uint8_t*restrict)&remainder)[0] = *dstbuf = *srcbuf; - } - acc += remainder; - acc = (acc >> 32) + (acc & 0xffffffff); - acc = (acc >> 16) + (acc & 0xffff); - acc = (acc >> 16) + (acc & 0xffff); - acc += (acc >> 16); - if (PGM_UNLIKELY(is_odd)) - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - return acc; -} - -#if defined(__amd64) || defined(__x86_64__) -/* simd instructions unique to AMD/Intel 64-bit, so always little endian. - */ - -static -uint16_t -do_csum_vector ( - const void* addr, - uint16_t len, - uint32_t csum - ) -{ - uint64_t acc; /* fixed size for asm */ - const uint8_t* buf; - uint16_t remainder; /* fixed size for endian swap */ - uint_fast16_t count; - bool is_odd; - - acc = csum; - buf = (const uint8_t*)addr; - remainder = 0; - - if (PGM_UNLIKELY(len == 0)) - return acc; -/* align first byte */ - is_odd = ((uintptr_t)buf & 1); - if (PGM_UNLIKELY(is_odd)) { - ((uint8_t*)&remainder)[1] = *buf++; - len--; - } -/* 16-bit words */ - count = len >> 1; - if (count) - { - if ((uintptr_t)buf & 2) { - acc += ((const uint16_t*)buf)[ 0 ]; - buf = &buf[ 2 ]; - count--; - len -= 2; - } -/* 32-bit words */ - count >>= 1; - if (count) - { - if ((uintptr_t)buf & 4) { - acc += ((const uint32_t*)buf)[ 0 ]; - buf = &buf[ 4 ]; - count--; - len -= 4; - } -/* 64-bit words */ - count >>= 1; - if (count) - { - uint64_t carry = 0; - while (count) { - asm volatile ( "addq %1, %0\n\t" - "adcq %2, %0" - : "=r" (acc) - : "m" (*(const uint64_t*)buf), "r" (carry), "0" (acc) - : "cc" ); - buf = &buf[ 8 ]; - count--; - } - acc += carry; - acc = (acc >> 32) + (acc & 0xffffffff); - } - if (len & 4) { - acc += ((const uint32_t*)buf)[ 0 ]; - buf = &buf[ 4 ]; - } - } - if (len & 2) { - acc += ((const uint16_t*)buf)[ 0 ]; - buf = &buf[ 2 ]; - } - } -/* trailing odd byte */ - if (len & 1) { - ((uint8_t*)&remainder)[0] = *buf; - } - acc += remainder; - acc = (acc >> 32) + (acc & 0xffffffff); - acc = (acc >> 16) + (acc & 0xffff); - acc = (acc >> 16) + (acc & 0xffff); - acc += (acc >> 16); - if (PGM_UNLIKELY(is_odd)) - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - return acc; -} - -static -uint16_t -do_csumcpy_vector ( - const void* restrict srcaddr, - void* restrict dstaddr, - uint16_t len, - uint32_t csum - ) -{ - uint64_t acc; /* fixed size for asm */ - const uint8_t*restrict srcbuf; - uint8_t*restrict dstbuf; - uint16_t remainder; /* fixed size for endian swap */ - uint_fast16_t count; - bool is_odd; - - acc = csum; - srcbuf = (const uint8_t*restrict)srcaddr; - dstbuf = (uint8_t*restrict)dstaddr; - remainder = 0; - - if (PGM_UNLIKELY(len == 0)) - return acc; -/* fill cache line with source buffer, invalidate destination buffer, - * perversly for testing high temporal locality is better than no locality, - * whilst in production no locality may be preferred depending on skb re-use. - */ - pgm_prefetch (srcbuf); - pgm_prefetchw (dstbuf); -/* align first byte */ - is_odd = ((uintptr_t)srcbuf & 1); - if (PGM_UNLIKELY(is_odd)) { - ((uint8_t*restrict)&remainder)[1] = *dstbuf++ = *srcbuf++; - len--; - } -/* 16-bit words */ - count = len >> 1; - if (count) - { - if ((uintptr_t)srcbuf & 2) { - acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; - srcbuf = &srcbuf[ 2 ]; - dstbuf = &dstbuf[ 2 ]; - count--; - len -= 2; - } -/* 32-bit words */ - count >>= 1; - if (count) - { - if ((uintptr_t)srcbuf & 4) { - acc += ((uint32_t*restrict)dstbuf)[ 0 ] = ((const uint32_t*restrict)srcbuf)[ 0 ]; - srcbuf = &srcbuf[ 4 ]; - dstbuf = &dstbuf[ 4 ]; - count--; - len -= 4; - } -/* 64-bit words */ - count >>= 1; - if (count) - { -/* 64-byte blocks */ - uint64_t carry = 0; - uint_fast16_t count64 = count >> 3; - - while (count64) - { - pgm_prefetch (&srcbuf[ 64 ]); - pgm_prefetchw (&dstbuf[ 64 ]); - asm volatile ( "movq 0*8(%1), %%r8\n\t" /* load */ - "movq 1*8(%1), %%r9\n\t" - "movq 2*8(%1), %%r10\n\t" - "movq 3*8(%1), %%r11\n\t" - "movq 4*8(%1), %%r12\n\t" - "movq 5*8(%1), %%r13\n\t" - "movq 6*8(%1), %%r14\n\t" - "movq 7*8(%1), %%r15\n\t" - "adcq %%r8, %0\n\t" /* checksum */ - "adcq %%r9, %0\n\t" - "adcq %%r10, %0\n\t" - "adcq %%r11, %0\n\t" - "adcq %%r12, %0\n\t" - "adcq %%r13, %0\n\t" - "adcq %%r14, %0\n\t" - "adcq %%r15, %0\n\t" - "adcq %3, %0\n\t" - "movq %%r8, 0*8(%2)\n\t" /* save */ - "movq %%r9, 1*8(%2)\n\t" - "movq %%r10, 2*8(%2)\n\t" - "movq %%r11, 3*8(%2)\n\t" - "movq %%r12, 4*8(%2)\n\t" - "movq %%r13, 5*8(%2)\n\t" - "movq %%r14, 6*8(%2)\n\t" - "movq %%r15, 7*8(%2)" - : "=r" (acc) - : "r" (srcbuf), "r" (dstbuf), "r" (carry), "0" (acc) - : "cc", "memory", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" ); - srcbuf = &srcbuf[ 64 ]; - dstbuf = &dstbuf[ 64 ]; - count64--; - } - count %= 8; -/* last 56 bytes */ - while (count) { - asm volatile ( "addq %1, %0\n\t" - "adcq %2, %0" - : "=r" (acc) - : "m" (*(const uint64_t*restrict)srcbuf), "r" (carry), "0" (acc) - : "cc" ); - srcbuf = &srcbuf[ 8 ]; - count--; - } - acc += carry; - acc = (acc >> 32) + (acc & 0xffffffff); - } - if (len & 4) { - acc += ((uint32_t*restrict)dstbuf)[ 0 ] = ((const uint32_t*restrict)srcbuf)[ 0 ]; - srcbuf = &srcbuf[ 4 ]; - dstbuf = &dstbuf[ 4 ]; - } - } - if (len & 2) { - acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; - srcbuf = &srcbuf[ 2 ]; - dstbuf = &dstbuf[ 2 ]; - } - } -/* trailing odd byte */ - if (len & 1) { - ((uint8_t*restrict)&remainder)[0] = *dstbuf = *srcbuf; - } - acc += remainder; - acc = (acc >> 32) + (acc & 0xffffffff); - acc = (acc >> 16) + (acc & 0xffff); - acc = (acc >> 16) + (acc & 0xffff); - acc += (acc >> 16); - if (PGM_UNLIKELY(is_odd)) - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - return acc; -} - -#endif - -static inline -uint16_t -do_csum ( - const void* addr, - uint16_t len, - uint32_t csum - ) -{ -#if defined(CONFIG_8BIT_CHECKSUM) - return do_csum_8bit (addr, len, csum); -#elif defined(CONFIG_16BIT_CHECKSUM) - return do_csum_16bit (addr, len, csum); -#elif defined(CONFIG_32BIT_CHECKSUM) - return do_csum_32bit (addr, len, csum); -#elif defined(CONFIG_64BIT_CHECKSUM) - return do_csum_64bit (addr, len, csum); -#elif defined(CONFIG_VECTOR_CHECKSUM) - return do_csum_vector (addr, len, csum); -#else -# error "checksum routine undefined" -#endif -} - -/* Calculate an IP header style checksum - */ - -uint16_t -pgm_inet_checksum ( - const void* addr, - uint16_t len, - uint16_t csum - ) -{ -/* pre-conditions */ - pgm_assert (NULL != addr); - - return ~do_csum (addr, len, csum); -} - -/* Calculate a partial (unfolded) checksum - */ - -uint32_t -pgm_compat_csum_partial ( - const void* addr, - uint16_t len, - uint32_t csum - ) -{ -/* pre-conditions */ - pgm_assert (NULL != addr); - - csum = (csum >> 16) + (csum & 0xffff); - csum += do_csum (addr, len, 0); - csum = (csum >> 16) + (csum & 0xffff); - - return csum; -} - -/* Calculate & copy a partial PGM checksum - */ - -uint32_t -pgm_compat_csum_partial_copy ( - const void* restrict src, - void* restrict dst, - uint16_t len, - uint32_t csum - ) -{ -/* pre-conditions */ - pgm_assert (NULL != src); - pgm_assert (NULL != dst); - -#if defined(CONFIG_8BIT_CHECKSUM) - return do_csumcpy_8bit (src, dst, len, csum); -#elif defined(CONFIG_16BIT_CHECKSUM) - return do_csumcpy_16bit (src, dst, len, csum); -#elif defined(CONFIG_32BIT_CHECKSUM) - return do_csumcpy_32bit (src, dst, len, csum); -#elif defined(CONFIG_64BIT_CHECKSUM) - return do_csumcpy_64bit (src, dst, len, csum); -#elif defined(CONFIG_VECTOR_CHECKSUM) - return do_csumcpy_vector (src, dst, len, csum); -#else - memcpy (dst, src, len); - return pgm_csum_partial (dst, len, csum); -#endif -} - -/* Fold 32 bit checksum accumulator into 16 bit final value. - */ - -uint16_t -pgm_csum_fold ( - uint32_t csum - ) -{ - csum = (csum >> 16) + (csum & 0xffff); - csum += (csum >> 16); - -/* handle special case of no checksum */ - return csum == 0xffff ? csum : ~csum; -} - -/* Add together two unfolded checksum accumulators - */ - -uint32_t -pgm_csum_block_add ( - uint32_t csum, - uint32_t csum2, - const uint16_t offset - ) -{ - if (offset & 1) /* byte magic on odd offset */ - csum2 = ((csum2 & 0xff00ff) << 8) + - ((csum2 >> 8) & 0xff00ff); - - csum += csum2; - return csum + (csum < csum2); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/checksum_perftest.c b/3rdparty/openpgm-svn-r1085/pgm/checksum_perftest.c deleted file mode 100644 index 678a066..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/checksum_perftest.c +++ /dev/null @@ -1,807 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * performance tests for PGM checksum routines - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include -#include -#include - - -/* mock state */ - -static unsigned perf_testsize = 0; -static unsigned perf_answer = 0; - - -static -void -mock_setup_100b (void) -{ - perf_testsize = 100; - perf_answer = 0x6ea8; -} - -static -void -mock_setup_200b (void) -{ - perf_testsize = 200; - perf_answer = 0x86e1; -} - -static -void -mock_setup_1500b (void) -{ - perf_testsize = 1500; - perf_answer = 0xec69; -} - -static -void -mock_setup_9kb (void) -{ - perf_testsize = 9000; - perf_answer = 0x576e; -} - -static -void -mock_setup_64kb (void) -{ - perf_testsize = 65535; - perf_answer = 0x3fc0; -} - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - -#define CHECKSUM_DEBUG -#include "checksum.c" - - -static -void -mock_setup (void) -{ - g_assert (pgm_time_init (NULL)); -} - -static -void -mock_teardown (void) -{ - g_assert (pgm_time_shutdown ()); -} - - -/* target: - * guint16 - * pgm_inet_checksum ( - * const void* src, - * guint len, - * int csum - * ) - */ - -START_TEST (test_8bit) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - csum = ~do_csum_8bit (source, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("8-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -/* checksum + memcpy */ -START_TEST (test_8bit_memcpy) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - char* target = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - memcpy (target, source, perf_testsize); - csum = ~do_csum_8bit (target, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("8-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -/* checksum & copy */ -START_TEST (test_8bit_csumcpy) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - char* target = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - csum = ~do_csumcpy_8bit (source, target, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("8-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -START_TEST (test_16bit) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - csum = ~do_csum_16bit (source, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("16-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -START_TEST (test_16bit_memcpy) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - char* target = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - memcpy (target, source, perf_testsize); - csum = ~do_csum_16bit (target, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("16-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -START_TEST (test_16bit_csumcpy) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - char* target = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - csum = ~do_csumcpy_16bit (source, target, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("16-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -START_TEST (test_32bit) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - csum = ~do_csum_32bit (source, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("32-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -START_TEST (test_32bit_memcpy) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - char* target = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - memcpy (target, source, perf_testsize); - csum = ~do_csum_32bit (target, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("32-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -START_TEST (test_32bit_csumcpy) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - char* target = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - csum = ~do_csumcpy_32bit (source, target, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("32-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -START_TEST (test_64bit) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - csum = ~do_csum_64bit (source, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("64-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -START_TEST (test_64bit_memcpy) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - char* target = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - memcpy (target, source, perf_testsize); - csum = ~do_csum_64bit (target, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("64-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -START_TEST (test_64bit_csumcpy) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - char* target = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - csum = ~do_csumcpy_64bit (source, target, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("64-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -#if defined(__amd64) || defined(__x86_64__) -START_TEST (test_vector) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - csum = ~do_csum_vector (source, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("vector/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -START_TEST (test_vector_memcpy) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - char* target = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - memcpy (target, source, perf_testsize); - csum = ~do_csum_vector (target, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("vector/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST - -START_TEST (test_vector_csumcpy) -{ - const unsigned iterations = 1000; - char* source = alloca (perf_testsize); - char* target = alloca (perf_testsize); - for (unsigned i = 0, j = 0; i < perf_testsize; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = perf_answer; /* network order */ - - guint16 csum; - pgm_time_t start, check; - - start = pgm_time_update_now(); - for (unsigned i = iterations; i; i--) { - csum = ~do_csumcpy_vector (source, target, perf_testsize, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); - } - - check = pgm_time_update_now(); - g_message ("vector/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", - perf_testsize, - (guint64)(check - start), - (guint64)((check - start) / iterations)); -} -END_TEST -#endif /* defined(__amd64) || defined(__x86_64__) */ - - - -static -Suite* -make_csum_performance_suite (void) -{ - Suite* s; - - s = suite_create ("Raw checksum performance"); - - TCase* tc_100b = tcase_create ("100b"); - suite_add_tcase (s, tc_100b); - tcase_add_checked_fixture (tc_100b, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_100b, mock_setup_100b, NULL); - tcase_add_test (tc_100b, test_8bit); - tcase_add_test (tc_100b, test_16bit); - tcase_add_test (tc_100b, test_32bit); - tcase_add_test (tc_100b, test_64bit); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_100b, test_vector); -#endif - - TCase* tc_200b = tcase_create ("200b"); - suite_add_tcase (s, tc_200b); - tcase_add_checked_fixture (tc_200b, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_200b, mock_setup_200b, NULL); - tcase_add_test (tc_200b, test_8bit); - tcase_add_test (tc_200b, test_16bit); - tcase_add_test (tc_200b, test_32bit); - tcase_add_test (tc_200b, test_64bit); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_200b, test_vector); -#endif - - TCase* tc_1500b = tcase_create ("1500b"); - suite_add_tcase (s, tc_1500b); - tcase_add_checked_fixture (tc_1500b, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_1500b, mock_setup_1500b, NULL); - tcase_add_test (tc_1500b, test_8bit); - tcase_add_test (tc_1500b, test_16bit); - tcase_add_test (tc_1500b, test_32bit); - tcase_add_test (tc_1500b, test_64bit); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_1500b, test_vector); -#endif - - TCase* tc_9kb = tcase_create ("9KB"); - suite_add_tcase (s, tc_9kb); - tcase_add_checked_fixture (tc_9kb, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_9kb, mock_setup_9kb, NULL); - tcase_add_test (tc_9kb, test_8bit); - tcase_add_test (tc_9kb, test_16bit); - tcase_add_test (tc_9kb, test_32bit); - tcase_add_test (tc_9kb, test_64bit); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_9kb, test_vector); -#endif - - TCase* tc_64kb = tcase_create ("64KB"); - suite_add_tcase (s, tc_64kb); - tcase_add_checked_fixture (tc_64kb, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_64kb, mock_setup_64kb, NULL); - tcase_add_test (tc_64kb, test_8bit); - tcase_add_test (tc_64kb, test_16bit); - tcase_add_test (tc_64kb, test_32bit); - tcase_add_test (tc_64kb, test_64bit); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_64kb, test_vector); -#endif - - return s; -} - -static -Suite* -make_csum_memcpy_performance_suite (void) -{ - Suite* s; - - s = suite_create ("Checksum and memcpy performance"); - - TCase* tc_100b = tcase_create ("100b"); - suite_add_tcase (s, tc_100b); - tcase_add_checked_fixture (tc_100b, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_100b, mock_setup_100b, NULL); - tcase_add_test (tc_100b, test_8bit_memcpy); - tcase_add_test (tc_100b, test_16bit_memcpy); - tcase_add_test (tc_100b, test_32bit_memcpy); - tcase_add_test (tc_100b, test_64bit_memcpy); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_100b, test_vector_memcpy); -#endif - - TCase* tc_200b = tcase_create ("200b"); - suite_add_tcase (s, tc_200b); - tcase_add_checked_fixture (tc_200b, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_200b, mock_setup_200b, NULL); - tcase_add_test (tc_200b, test_8bit_memcpy); - tcase_add_test (tc_200b, test_16bit_memcpy); - tcase_add_test (tc_200b, test_32bit_memcpy); - tcase_add_test (tc_200b, test_64bit_memcpy); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_200b, test_vector_memcpy); -#endif - - TCase* tc_1500b = tcase_create ("1500b"); - suite_add_tcase (s, tc_1500b); - tcase_add_checked_fixture (tc_1500b, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_1500b, mock_setup_1500b, NULL); - tcase_add_test (tc_1500b, test_8bit_memcpy); - tcase_add_test (tc_1500b, test_16bit_memcpy); - tcase_add_test (tc_1500b, test_32bit_memcpy); - tcase_add_test (tc_1500b, test_64bit_memcpy); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_1500b, test_vector_memcpy); -#endif - - TCase* tc_9kb = tcase_create ("9KB"); - suite_add_tcase (s, tc_9kb); - tcase_add_checked_fixture (tc_9kb, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_9kb, mock_setup_9kb, NULL); - tcase_add_test (tc_9kb, test_8bit_memcpy); - tcase_add_test (tc_9kb, test_16bit_memcpy); - tcase_add_test (tc_9kb, test_32bit_memcpy); - tcase_add_test (tc_9kb, test_64bit_memcpy); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_9kb, test_vector_memcpy); -#endif - - TCase* tc_64kb = tcase_create ("64KB"); - suite_add_tcase (s, tc_64kb); - tcase_add_checked_fixture (tc_64kb, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_64kb, mock_setup_64kb, NULL); - tcase_add_test (tc_64kb, test_8bit_memcpy); - tcase_add_test (tc_64kb, test_16bit_memcpy); - tcase_add_test (tc_64kb, test_32bit_memcpy); - tcase_add_test (tc_64kb, test_64bit_memcpy); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_64kb, test_vector_memcpy); -#endif - - return s; -} - -static -Suite* -make_csumcpy_performance_suite (void) -{ - Suite* s; - - s = suite_create ("Checksum copy performance"); - - TCase* tc_100b = tcase_create ("100b"); - suite_add_tcase (s, tc_100b); - tcase_add_checked_fixture (tc_100b, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_100b, mock_setup_100b, NULL); - tcase_add_test (tc_100b, test_8bit_csumcpy); - tcase_add_test (tc_100b, test_16bit_csumcpy); - tcase_add_test (tc_100b, test_32bit_csumcpy); - tcase_add_test (tc_100b, test_64bit_csumcpy); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_100b, test_vector_csumcpy); -#endif - - TCase* tc_200b = tcase_create ("200b"); - suite_add_tcase (s, tc_200b); - tcase_add_checked_fixture (tc_200b, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_200b, mock_setup_200b, NULL); - tcase_add_test (tc_200b, test_8bit_csumcpy); - tcase_add_test (tc_200b, test_16bit_csumcpy); - tcase_add_test (tc_200b, test_32bit_csumcpy); - tcase_add_test (tc_200b, test_64bit_csumcpy); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_200b, test_vector_csumcpy); -#endif - - TCase* tc_1500b = tcase_create ("1500b"); - suite_add_tcase (s, tc_1500b); - tcase_add_checked_fixture (tc_1500b, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_1500b, mock_setup_1500b, NULL); - tcase_add_test (tc_1500b, test_8bit_csumcpy); - tcase_add_test (tc_1500b, test_16bit_csumcpy); - tcase_add_test (tc_1500b, test_32bit_csumcpy); - tcase_add_test (tc_1500b, test_64bit_csumcpy); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_1500b, test_vector_csumcpy); -#endif - - TCase* tc_9kb = tcase_create ("9KB"); - suite_add_tcase (s, tc_9kb); - tcase_add_checked_fixture (tc_9kb, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_9kb, mock_setup_9kb, NULL); - tcase_add_test (tc_9kb, test_8bit_csumcpy); - tcase_add_test (tc_9kb, test_16bit_csumcpy); - tcase_add_test (tc_9kb, test_32bit_csumcpy); - tcase_add_test (tc_9kb, test_64bit_csumcpy); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_9kb, test_vector_csumcpy); -#endif - - TCase* tc_64kb = tcase_create ("64KB"); - suite_add_tcase (s, tc_64kb); - tcase_add_checked_fixture (tc_64kb, mock_setup, mock_teardown); - tcase_add_checked_fixture (tc_64kb, mock_setup_64kb, NULL); - tcase_add_test (tc_64kb, test_8bit_csumcpy); - tcase_add_test (tc_64kb, test_16bit_csumcpy); - tcase_add_test (tc_64kb, test_32bit_csumcpy); - tcase_add_test (tc_64kb, test_64bit_csumcpy); -#if defined(__amd64) || defined(__x86_64__) - tcase_add_test (tc_64kb, test_vector_csumcpy); -#endif - - return s; -} - - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_csum_performance_suite ()); - srunner_add_suite (sr, make_csum_memcpy_performance_suite ()); - srunner_add_suite (sr, make_csumcpy_performance_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/checksum_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/checksum_unittest.c deleted file mode 100644 index a25d36a..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/checksum_unittest.c +++ /dev/null @@ -1,278 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for PGM checksum routines - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include - - -/* mock state */ - - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - - -#define CHECKSUM_DEBUG -#include "checksum.c" - - -/* target: - * uint16_t - * pgm_inet_checksum ( - * const void* src, - * uint16_t len, - * uint16_t csum - * ) - */ - -START_TEST (test_inet_pass_001) -{ - const char source[] = "i am not a string"; - const guint16 answer = 0x1fda; /* network order */ - - guint16 csum = pgm_inet_checksum (source, sizeof(source), 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - g_message ("IP checksum of \"%s\" (%d) is %u (%u)", - source, sizeof(source), csum, answer); - - fail_unless (answer == csum, "checksum mismatch"); -} -END_TEST - -START_TEST (test_inet_pass_002) -{ - char* source = alloca (65535); - for (unsigned i = 0, j = 0; i < 65535; i++) { - j = j * 1103515245 + 12345; - source[i] = j; - } - const guint16 answer = 0x3fc0; /* network order */ - - guint16 csum = pgm_inet_checksum (source, 65535, 0); -/* function calculates answer in host order */ - csum = g_htons (csum); - g_message ("IP checksum of 64KB is %u (%u)", - csum, answer); - - fail_unless (answer == csum, "checksum mismatch"); -} -END_TEST - -START_TEST (test_inet_fail_001) -{ - pgm_inet_checksum (NULL, 0, 0); - fail ("reached"); -} -END_TEST - -/* target: - * guint16 - * pgm_csum_fold ( - * guint32 csum - * ) - */ - -START_TEST (test_fold_pass_001) -{ - const guint32 csum = 0xdd250300; /* network order */ - const guint16 answer = 0x1fda; - - guint16 folded_csum = pgm_csum_fold (g_ntohl (csum)); - folded_csum = g_htons (folded_csum); - g_message ("32-bit checksum %u folds into %u (%u)", csum, folded_csum, answer); - - fail_unless (answer == folded_csum, "folded checksum mismatch"); -} -END_TEST - - -/* target: - * guint32 - * pgm_csum_partial ( - * const void* src, - * guint len, - * guint32 sum - * ) - */ - -START_TEST (test_partial_pass_001) -{ - const char source[] = "i am not a string"; -#if __BYTE_ORDER == __BIG_ENDIAN - const guint32 answer = 0x0000e025; /* network order */ -#elif __BYTE_ORDER == __LITTLE_ENDIAN - const guint32 answer = 0xe0250000; /* network order */ -#else -# error "__BYTE_ORDER not supported." -#endif - - guint32 csum = pgm_csum_partial (source, sizeof(source), 0); - csum = g_htonl (csum); - g_message ("Partial checksum of \"%s\" is %u (%u)", source, csum, answer); - - fail_unless (answer == csum, "checksum mismatch"); -} -END_TEST - -START_TEST (test_partial_fail_001) -{ - pgm_csum_partial (NULL, 0, 0); - fail ("reached"); -} -END_TEST - -/* target: - * guint32 - * pgm_csum_partial_copy ( - * const void* src, - * void* dst, - * guint len, - * guint32 sum - * ) - */ - -START_TEST (test_partial_copy_pass_001) -{ - const char source[] = "i am not a string"; -#if __BYTE_ORDER == __BIG_ENDIAN - const guint32 answer = 0x0000e025; /* network order */ -#elif __BYTE_ORDER == __LITTLE_ENDIAN - const guint32 answer = 0xe0250000; /* network order */ -#else -# error "__BYTE_ORDER not supported." -#endif - - char dest[1024]; - guint32 csum_source = pgm_csum_partial_copy (source, dest, sizeof(source), 0); - csum_source = g_htonl (csum_source); - guint32 csum_dest = pgm_csum_partial (dest, sizeof(source), 0); - csum_dest = g_htonl (csum_dest); - g_message ("Partial copy checksum of \"%s\" is %u, partial checksum is %u (%u)", - source, csum_source, csum_dest, answer); - fail_unless (answer == csum_source, "checksum mismatch in partial-copy"); - fail_unless (answer == csum_dest, "checksum mismatch in partial"); -} -END_TEST - -START_TEST (test_partial_copy_fail_001) -{ - pgm_csum_partial_copy (NULL, NULL, 0, 0); - fail ("reached"); -} -END_TEST - -/* target: - * guint32 - * pgm_csum_block_add ( - * guint32 csum, - * guint32 csum2, - * guint offset - * ) - */ - -START_TEST (test_block_add_pass_001) -{ - const char source[] = "i am not a string"; - const guint16 answer = 0x1fda; /* network order */ - - guint32 csum_a = pgm_csum_partial (source, sizeof(source) / 2, 0); - guint32 csum_b = pgm_csum_partial (source + (sizeof(source) / 2), sizeof(source) - (sizeof(source) / 2), 0); - guint32 csum = pgm_csum_block_add (csum_a, csum_b, sizeof(source) / 2); - guint16 fold = pgm_csum_fold (csum); -/* convert to display in network order */ - csum_a = g_htonl (csum_a); - csum_b = g_htonl (csum_b); - csum = g_htonl (csum); - fold = g_htons (fold); - g_message ("Checksum A:%u + B:%u = %u -> %u (%u)", - csum_a, csum_b, csum, fold, answer); - fail_unless (answer == fold, "checksum mismatch"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_inet = tcase_create ("inet"); - suite_add_tcase (s, tc_inet); - tcase_add_test (tc_inet, test_inet_pass_001); - tcase_add_test (tc_inet, test_inet_pass_002); - tcase_add_test_raise_signal (tc_inet, test_inet_fail_001, SIGABRT); - - TCase* tc_fold = tcase_create ("fold"); - suite_add_tcase (s, tc_fold); - tcase_add_test (tc_fold, test_fold_pass_001); - - TCase* tc_block_add = tcase_create ("block-add"); - suite_add_tcase (s, tc_block_add); - tcase_add_test (tc_block_add, test_block_add_pass_001); - - TCase* tc_partial = tcase_create ("partial"); - suite_add_tcase (s, tc_partial); - tcase_add_test (tc_partial, test_partial_pass_001); - tcase_add_test_raise_signal (tc_partial, test_partial_fail_001, SIGABRT); - - TCase* tc_partial_copy = tcase_create ("partial-copy"); - suite_add_tcase (s, tc_partial_copy); - tcase_add_test (tc_partial_copy, test_partial_copy_pass_001); - tcase_add_test_raise_signal (tc_partial_copy, test_partial_copy_fail_001, SIGABRT); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/crossmingw.py b/3rdparty/openpgm-svn-r1085/pgm/crossmingw.py deleted file mode 100644 index 2981506..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/crossmingw.py +++ /dev/null @@ -1,144 +0,0 @@ -import os -import os.path -import string - -import SCons.Action -import SCons.Builder -import SCons.Tool -import SCons.Util - -# This is what we search for to find mingw: -prefixes = SCons.Util.Split(""" - mingw32- - i386-mingw32msvc- - i486-mingw32msvc- - i586-mingw32msvc- - i686-mingw32msvc- -""") - -def find(env): - for prefix in prefixes: - # First search in the SCons path and then the OS path: - if env.WhereIs(prefix + 'gcc') or SCons.Util.WhereIs(prefix + 'gcc'): - return prefix - - return '' - -def shlib_generator(target, source, env, for_signature): - cmd = SCons.Util.CLVar(['$SHLINK', '$SHLINKFLAGS']) - - dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') - if dll: cmd.extend(['-o', dll]) - - cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) - - implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX') - if implib: cmd.append('-Wl,--out-implib,'+implib.get_string(for_signature)) - - def_target = env.FindIxes(target, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') - if def_target: cmd.append('-Wl,--output-def,'+def_target.get_string(for_signature)) - - return [cmd] - -def shlib_emitter(target, source, env): - dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') - no_import_lib = env.get('no_import_lib', 0) - - if not dll: - raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX") - - if not no_import_lib and \ - not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'): - - # Append an import library to the list of targets. - target.append(env.ReplaceIxes(dll, - 'SHLIBPREFIX', 'SHLIBSUFFIX', - 'LIBPREFIX', 'LIBSUFFIX')) - - # Append a def file target if there isn't already a def file target - # or a def file source. There is no option to disable def file - # target emitting, because I can't figure out why someone would ever - # want to turn it off. - def_source = env.FindIxes(source, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') - def_target = env.FindIxes(target, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') - if not def_source and not def_target: - target.append(env.ReplaceIxes(dll, - 'SHLIBPREFIX', 'SHLIBSUFFIX', - 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX')) - - return (target, source) - -# TODO: Backported to old scons version -#shlib_action = SCons.Action.CommandGenerator(shlib_generator) -shlib_action = SCons.Action.Action(shlib_generator,generator=1) - -res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR') - -res_builder = SCons.Builder.Builder(action=res_action, suffix='.o', - source_scanner=SCons.Tool.SourceFileScanner) -SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan) - -def generate(env): - mingw_prefix = find(env) - - if mingw_prefix: - dir = os.path.dirname(env.WhereIs(mingw_prefix + 'gcc') or SCons.Util.WhereIs(mingw_prefix + 'gcc')) - - # The mingw bin directory must be added to the path: - path = env['ENV'].get('PATH', []) - if not path: - path = [] - if SCons.Util.is_String(path): - path = string.split(path, os.pathsep) - - env['ENV']['PATH'] = string.join([dir] + path, os.pathsep) - - # Most of mingw is the same as gcc and friends... - gnu_tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas'] - for tool in gnu_tools: - SCons.Tool.Tool(tool)(env) - - #... but a few things differ: - env['CC'] = mingw_prefix + 'gcc' - env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') - env['CXX'] = mingw_prefix + 'g++' - env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') - env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') - env['SHLINKCOM'] = shlib_action - env.Append(SHLIBEMITTER = [shlib_emitter]) - # This line isn't required and breaks C++ linking - #env['LINK'] = mingw_prefix + 'g++' - env['AS'] = mingw_prefix + 'as' - env['AR'] = mingw_prefix + 'ar' - env['RANLIB'] = mingw_prefix + 'ranlib' - env['WIN32DEFPREFIX'] = '' - env['WIN32DEFSUFFIX'] = '.def' - env['SHOBJSUFFIX'] = '.o' - env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 - - env['RC'] = mingw_prefix + 'windres' - env['RCFLAGS'] = SCons.Util.CLVar('') - env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET)} $)' - env['RCINCPREFIX'] = '--include-dir ' - env['RCINCSUFFIX'] = '' - env['RCCOM'] = '$RC $RCINCFLAGS $RCINCPREFIX $SOURCE.dir $RCFLAGS -i $SOURCE -o $TARGET' - env['BUILDERS']['RES'] = res_builder - - # Some setting from the platform also have to be overridden: - env['OBJPREFIX'] = '' - env['OBJSUFFIX'] = '.o' - env['LIBPREFIX'] = 'lib' - env['LIBSUFFIX'] = '.a' - env['SHOBJPREFIX'] = '$OBJPREFIX' - env['SHOBJSUFFIX'] = '$OBJSUFFIX' - env['PROGPREFIX'] = '' - env['PROGSUFFIX'] = '.exe' - env['LIBPREFIX'] = '' - env['LIBSUFFIX'] = '.lib' - env['SHLIBPREFIX'] = '' - env['SHLIBSUFFIX'] = '.dll' - env['LIBPREFIXES'] = [ '$LIBPREFIX' ] - env['LIBSUFFIXES'] = [ '$LIBSUFFIX' ] - -def exists(env): - return find(env) diff --git a/3rdparty/openpgm-svn-r1085/pgm/crossmingw64.py b/3rdparty/openpgm-svn-r1085/pgm/crossmingw64.py deleted file mode 100644 index 111e0ed..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/crossmingw64.py +++ /dev/null @@ -1,140 +0,0 @@ -import os -import os.path -import string - -import SCons.Action -import SCons.Builder -import SCons.Tool -import SCons.Util - -# This is what we search for to find mingw: -prefixes = SCons.Util.Split(""" - x86_64-w64-mingw32- -""") - -def find(env): - for prefix in prefixes: - # First search in the SCons path and then the OS path: - if env.WhereIs(prefix + 'gcc') or SCons.Util.WhereIs(prefix + 'gcc'): - return prefix - - return '' - -def shlib_generator(target, source, env, for_signature): - cmd = SCons.Util.CLVar(['$SHLINK', '$SHLINKFLAGS']) - - dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') - if dll: cmd.extend(['-o', dll]) - - cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) - - implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX') - if implib: cmd.append('-Wl,--out-implib,'+implib.get_string(for_signature)) - - def_target = env.FindIxes(target, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') - if def_target: cmd.append('-Wl,--output-def,'+def_target.get_string(for_signature)) - - return [cmd] - -def shlib_emitter(target, source, env): - dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') - no_import_lib = env.get('no_import_lib', 0) - - if not dll: - raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX") - - if not no_import_lib and \ - not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'): - - # Append an import library to the list of targets. - target.append(env.ReplaceIxes(dll, - 'SHLIBPREFIX', 'SHLIBSUFFIX', - 'LIBPREFIX', 'LIBSUFFIX')) - - # Append a def file target if there isn't already a def file target - # or a def file source. There is no option to disable def file - # target emitting, because I can't figure out why someone would ever - # want to turn it off. - def_source = env.FindIxes(source, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') - def_target = env.FindIxes(target, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') - if not def_source and not def_target: - target.append(env.ReplaceIxes(dll, - 'SHLIBPREFIX', 'SHLIBSUFFIX', - 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX')) - - return (target, source) - -# TODO: Backported to old scons version -#shlib_action = SCons.Action.CommandGenerator(shlib_generator) -shlib_action = SCons.Action.Action(shlib_generator,generator=1) - -res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR') - -res_builder = SCons.Builder.Builder(action=res_action, suffix='.o', - source_scanner=SCons.Tool.SourceFileScanner) -SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan) - -def generate(env): - mingw_prefix = find(env) - - if mingw_prefix: - dir = os.path.dirname(env.WhereIs(mingw_prefix + 'gcc') or SCons.Util.WhereIs(mingw_prefix + 'gcc')) - - # The mingw bin directory must be added to the path: - path = env['ENV'].get('PATH', []) - if not path: - path = [] - if SCons.Util.is_String(path): - path = string.split(path, os.pathsep) - - env['ENV']['PATH'] = string.join([dir] + path, os.pathsep) - - # Most of mingw is the same as gcc and friends... - gnu_tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas'] - for tool in gnu_tools: - SCons.Tool.Tool(tool)(env) - - #... but a few things differ: - env['CC'] = mingw_prefix + 'gcc' - env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') - env['CXX'] = mingw_prefix + 'g++' - env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') - env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') - env['SHLINKCOM'] = shlib_action - env.Append(SHLIBEMITTER = [shlib_emitter]) - # This line isn't required and breaks C++ linking - #env['LINK'] = mingw_prefix + 'g++' - env['AS'] = mingw_prefix + 'as' - env['AR'] = mingw_prefix + 'ar' - env['RANLIB'] = mingw_prefix + 'ranlib' - env['WIN32DEFPREFIX'] = '' - env['WIN32DEFSUFFIX'] = '.def' - env['SHOBJSUFFIX'] = '.o' - env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 - - env['RC'] = mingw_prefix + 'windres' - env['RCFLAGS'] = SCons.Util.CLVar('') - env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET)} $)' - env['RCINCPREFIX'] = '--include-dir ' - env['RCINCSUFFIX'] = '' - env['RCCOM'] = '$RC $RCINCFLAGS $RCINCPREFIX $SOURCE.dir $RCFLAGS -i $SOURCE -o $TARGET' - env['BUILDERS']['RES'] = res_builder - - # Some setting from the platform also have to be overridden: - env['OBJPREFIX'] = '' - env['OBJSUFFIX'] = '.o' - env['LIBPREFIX'] = 'lib' - env['LIBSUFFIX'] = '.a' - env['SHOBJPREFIX'] = '$OBJPREFIX' - env['SHOBJSUFFIX'] = '$OBJSUFFIX' - env['PROGPREFIX'] = '' - env['PROGSUFFIX'] = '.exe' - env['LIBPREFIX'] = '' - env['LIBSUFFIX'] = '.lib' - env['SHLIBPREFIX'] = '' - env['SHLIBSUFFIX'] = '.dll' - env['LIBPREFIXES'] = [ '$LIBPREFIX' ] - env['LIBSUFFIXES'] = [ '$LIBSUFFIX' ] - -def exists(env): - return find(env) diff --git a/3rdparty/openpgm-svn-r1085/pgm/engine.c b/3rdparty/openpgm-svn-r1085/pgm/engine.c deleted file mode 100644 index 994bca2..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/engine.c +++ /dev/null @@ -1,277 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM engine. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _WIN32 -# include -#endif -#include -#include -#include -#include -#include -#include -#include - - -//#define ENGINE_DEBUG - - -/* globals */ -int pgm_ipproto_pgm PGM_GNUC_READ_MOSTLY = IPPROTO_PGM; - -#ifdef _WIN32 -LPFN_WSARECVMSG pgm_WSARecvMsg PGM_GNUC_READ_MOSTLY = NULL; -#endif - -#ifdef PGM_DEBUG -unsigned pgm_loss_rate PGM_GNUC_READ_MOSTLY = 0; -#endif - -/* locals */ -static bool pgm_is_supported = FALSE; -static volatile uint32_t pgm_ref_count = 0; - -#ifdef _WIN32 -# ifndef WSAID_WSARECVMSG -/* http://cvs.winehq.org/cvsweb/wine/include/mswsock.h */ -# define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} -# endif -#endif - - -/* startup PGM engine, mainly finding PGM protocol definition, if any from NSS - * - * returns TRUE on success, returns FALSE if an error occurred, implying some form of - * system re-configuration is required to resolve before trying again. - * - * NB: Valgrind loves generating errors in getprotobyname(). - */ -bool -pgm_init ( - pgm_error_t** error - ) -{ - if (pgm_atomic_exchange_and_add32 (&pgm_ref_count, 1) > 0) - return TRUE; - -/* initialise dependent modules */ - pgm_messages_init(); - - pgm_minor ("OpenPGM %d.%d.%d%s%s%s %s %s %s %s", - pgm_major_version, pgm_minor_version, pgm_micro_version, - pgm_build_revision ? " (" : "", pgm_build_revision ? pgm_build_revision : "", pgm_build_revision ? ")" : "", - pgm_build_date, pgm_build_time, pgm_build_system, pgm_build_machine); - - pgm_thread_init(); - pgm_mem_init(); - pgm_rand_init(); - -#ifdef _WIN32 - WORD wVersionRequested = MAKEWORD (2, 2); - WSADATA wsaData; - if (WSAStartup (wVersionRequested, &wsaData) != 0) - { - const int save_errno = WSAGetLastError (); - pgm_set_error (error, - PGM_ERROR_DOMAIN_ENGINE, - pgm_error_from_wsa_errno (save_errno), - _("WSAStartup failure: %s"), - pgm_wsastrerror (save_errno)); - goto err_shutdown; - } - - if (LOBYTE (wsaData.wVersion) != 2 || HIBYTE (wsaData.wVersion) != 2) - { - WSACleanup(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_ENGINE, - PGM_ERROR_FAILED, - _("WSAStartup failed to provide requested version 2.2.")); - goto err_shutdown; - } - -# ifndef CONFIG_TARGET_WINE -/* find WSARecvMsg API */ - if (NULL == pgm_WSARecvMsg) { - GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; - DWORD cbBytesReturned; - const SOCKET sock = socket (AF_INET, SOCK_DGRAM, 0); - if (SOCKET_ERROR == sock) { - WSACleanup(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_ENGINE, - PGM_ERROR_FAILED, - _("Cannot open socket.")); - goto err_shutdown; - } - if (SOCKET_ERROR == WSAIoctl (sock, - SIO_GET_EXTENSION_FUNCTION_POINTER, - &WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID), - &pgm_WSARecvMsg, sizeof(pgm_WSARecvMsg), - &cbBytesReturned, - NULL, - NULL)) - { - closesocket (sock); - WSACleanup(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_ENGINE, - PGM_ERROR_FAILED, - _("WSARecvMsg function not found.")); - goto err_shutdown; - } - pgm_debug ("Retrieved address of WSARecvMsg."); - closesocket (sock); - } -# endif -#endif /* _WIN32 */ - -/* find PGM protocol id overriding default value, use first value from NIS */ -#ifdef CONFIG_HAVE_GETPROTOBYNAME_R - char b[1024]; - struct protoent protobuf; - const struct protoent* proto = getprotobyname_r ("pgm", &protobuf, b, sizeof(b)); - if (NULL != proto) { - if (proto->p_proto != pgm_ipproto_pgm) { - pgm_minor (_("Setting PGM protocol number to %i from /etc/protocols."), - proto->p_proto); - pgm_ipproto_pgm = proto->p_proto; - } - } -#elif defined(CONFIG_HAVE_GETPROTOBYNAME_R2) - char b[1024]; - struct protoent protobuf, *proto; - const int e = getprotobyname_r ("pgm", &protobuf, b, sizeof(b), &proto); - if (e != -1 && proto != NULL) { - if (proto->p_proto != pgm_ipproto_pgm) { - pgm_minor (_("Setting PGM protocol number to %i from /etc/protocols."), - proto->p_proto); - pgm_ipproto_pgm = proto->p_proto; - } - } -#else - const struct protoent *proto = getprotobyname ("pgm"); - if (proto != NULL) { - if (proto->p_proto != pgm_ipproto_pgm) { -#ifndef _WIN32 - pgm_minor (_("Setting PGM protocol number to %i from /etc/protocols."), - proto->p_proto); -#else - pgm_minor (_("Setting PGM protocol number to %i from %%SYSTEMROOT%%\\system32\\drivers\\etc\\protocols."), - proto->p_proto); -#endif - pgm_ipproto_pgm = proto->p_proto; - } - } -#endif - -/* ensure timing enabled */ - pgm_error_t* sub_error = NULL; - if (!pgm_time_init (&sub_error)) { - if (sub_error) - pgm_propagate_error (error, sub_error); -#ifdef _WIN32 - WSACleanup(); -#endif - goto err_shutdown; - } - -/* receiver simulated loss rate */ -#ifdef PGM_DEBUG - const char *loss_rate = getenv ("PGM_LOSS_RATE"); - if (NULL != loss_rate) { - int value = atoi (loss_rate); - if (value > 0 && value <= 100) { - pgm_loss_rate = value; - pgm_minor (_("Setting PGM packet loss rate to %i%%."), pgm_loss_rate); - } - } -#endif - -/* create global sock list lock */ - pgm_rwlock_init (&pgm_sock_list_lock); - - pgm_is_supported = TRUE; - return TRUE; - -err_shutdown: - pgm_rand_shutdown(); - pgm_mem_shutdown(); - pgm_thread_shutdown(); - pgm_messages_shutdown(); - pgm_atomic_dec32 (&pgm_ref_count); - return FALSE; -} - -/* returns TRUE if PGM engine has been initialized - */ - -bool -pgm_supported (void) -{ - return ( pgm_is_supported == TRUE ); -} - -/* returns TRUE on success, returns FALSE if an error occurred. - */ - -bool -pgm_shutdown (void) -{ - pgm_return_val_if_fail (pgm_atomic_read32 (&pgm_ref_count) > 0, FALSE); - - if (pgm_atomic_exchange_and_add32 (&pgm_ref_count, (uint32_t)-1) != 1) - return TRUE; - - pgm_is_supported = FALSE; - -/* destroy all open socks */ - while (pgm_sock_list) { - pgm_close ((pgm_sock_t*)pgm_sock_list->data, FALSE); - } - - pgm_time_shutdown(); - -#ifdef _WIN32 - WSACleanup(); -#endif - - pgm_rand_shutdown(); - pgm_mem_shutdown(); - pgm_thread_shutdown(); - pgm_messages_shutdown(); - return TRUE; -} - -/* helper to drop out of setuid 0 after creating PGM sockets - */ -void -pgm_drop_superuser (void) -{ -#ifndef _WIN32 - if (0 == getuid()) { - setuid((gid_t)65534); - setgid((uid_t)65534); - } -#endif -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/engine_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/engine_unittest.c deleted file mode 100644 index f434e35..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/engine_unittest.c +++ /dev/null @@ -1,232 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for PGM engine. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include - - -/* mock state */ - -struct pgm_rwlock_t; -struct pgm_slist_t; - -static gint mock_time_init = 0; -static struct pgm_rwlock_t mock_pgm_sock_list_lock; -static struct pgm_slist_t* mock_pgm_sock_list = NULL; - -#define pgm_time_init mock_pgm_time_init -#define pgm_time_shutdown mock_pgm_time_shutdown -#define pgm_close mock_pgm_close -#define pgm_sock_list_lock mock_pgm_sock_list_lock -#define pgm_sock_list mock_pgm_sock_list - -#define ENGINE_DEBUG -#include "engine.c" - - -static -void -mock_setup (void) -{ - mock_time_init = FALSE; -} - -static -void -mock_teardown (void) -{ -// null -} - - -/* mock functions for external references */ - -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return 0; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_time_init ( - pgm_error_t** error - ) -{ - mock_time_init++; - return TRUE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_time_shutdown (void) -{ - if (!mock_time_init) - return FALSE; - mock_time_init--; - return TRUE; -} - -bool -mock_pgm_close ( - pgm_sock_t* sock, - bool flush - ) -{ - return TRUE; -} - - -/* target: - * bool - * pgm_init (pgm_error_t** error) - */ - -/* reference counting on init */ -START_TEST (test_init_pass_001) -{ - fail_unless (TRUE == pgm_init (NULL), "init failed"); - fail_unless (TRUE == pgm_init (NULL), "init failed"); -} -END_TEST - -/* timing module already init */ -START_TEST (test_init_pass_003) -{ - pgm_error_t* err = NULL; - fail_unless (TRUE == pgm_time_init (&err), "time-init failed: %s", (err && err->message) ? err->message : "(null)"); - fail_unless (TRUE == pgm_init (&err), "init failed: %s", (err && err->message) ? err->message : "(null)"); - fail_unless (TRUE == pgm_init (&err), "init failed: %s", (err && err->message) ? err->message : "(null)"); -} -END_TEST - -/* target: - * bool - * pgm_shutdown (void) - */ - -START_TEST (test_shutdown_pass_001) -{ - fail_unless (TRUE == pgm_init (NULL), "init failed"); - fail_unless (TRUE == pgm_shutdown (), "shutdown failed"); -} -END_TEST - -/* no init */ -START_TEST (test_shutdown_pass_002) -{ - fail_unless (FALSE == pgm_shutdown (), "shutdown failed"); -} -END_TEST - -/* double call */ -START_TEST (test_shutdown_pass_003) -{ - fail_unless (TRUE == pgm_init (NULL), "init failed"); - fail_unless (TRUE == pgm_shutdown (), "shutdown failed"); - fail_unless (FALSE == pgm_shutdown (), "shutdown failed"); -} -END_TEST - -/* check reference counting */ -START_TEST (test_shutdown_pass_004) -{ - fail_unless (TRUE == pgm_init (NULL), "init failed"); - fail_unless (TRUE == pgm_init (NULL), "init failed"); - fail_unless (TRUE == pgm_shutdown (), "shutdown failed"); - fail_unless (TRUE == pgm_shutdown (), "shutdown failed"); - fail_unless (FALSE == pgm_shutdown (), "shutdown failed"); -} -END_TEST - -/* target: - * bool - * pgm_supported (void) - */ - -START_TEST (test_supported_pass_001) -{ - fail_unless (FALSE == pgm_supported(), "supported failed"); - fail_unless (TRUE == pgm_init (NULL), "init failed"); - fail_unless (TRUE == pgm_supported(), "supported failed"); - fail_unless (TRUE == pgm_shutdown (), "shutdown failed"); - fail_unless (FALSE == pgm_supported(), "supported failed"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_init = tcase_create ("init"); - tcase_add_checked_fixture (tc_init, mock_setup, mock_teardown); - suite_add_tcase (s, tc_init); - tcase_add_test (tc_init, test_init_pass_001); - tcase_add_test (tc_init, test_init_pass_003); - - TCase* tc_shutdown = tcase_create ("shutdown"); - tcase_add_checked_fixture (tc_shutdown, mock_setup, mock_teardown); - suite_add_tcase (s, tc_shutdown); - tcase_add_test (tc_shutdown, test_shutdown_pass_001); - tcase_add_test (tc_shutdown, test_shutdown_pass_002); - tcase_add_test (tc_shutdown, test_shutdown_pass_003); - tcase_add_test (tc_shutdown, test_shutdown_pass_004); - - TCase* tc_supported = tcase_create ("supported"); - tcase_add_checked_fixture (tc_supported, mock_setup, mock_teardown); - suite_add_tcase (s, tc_supported); - tcase_add_test (tc_supported, test_supported_pass_001); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/error.c b/3rdparty/openpgm-svn-r1085/pgm/error.c deleted file mode 100644 index 3f3fe30..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/error.c +++ /dev/null @@ -1,518 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable error reporting. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _WIN32 -# include -#endif -#include -#include - - -//#define ERROR_DEBUG - - -#define ERROR_OVERWRITTEN_WARNING "pgm_error_t set over the top of a previous pgm_error_t or uninitialized memory.\n" \ - "This indicates a bug. You must ensure an error is NULL before it's set.\n" \ - "The overwriting error message was: %s" - -static pgm_error_t* pgm_error_new_valist (const int, const int, const char*, va_list) PGM_GNUC_PRINTF(3, 0); -static void pgm_error_add_prefix (char**restrict, const char*restrict, va_list) PGM_GNUC_PRINTF(2, 0); - - -static -pgm_error_t* -pgm_error_new_valist ( - const int error_domain, - const int error_code, - const char* format, - va_list args - ) -{ - pgm_error_t *error = pgm_new (pgm_error_t, 1); - error->domain = error_domain; - error->code = error_code; - error->message = pgm_strdup_vprintf (format, args); - return error; -} - -void -pgm_error_free ( - pgm_error_t* error - ) -{ - pgm_return_if_fail (error != NULL); - pgm_free (error->message); - pgm_free (error); -} - -void -pgm_set_error ( - pgm_error_t** restrict err, - const int error_domain, - const int error_code, - const char* restrict format, - ... - ) -{ - pgm_error_t *new; - va_list args; - - if (NULL == err) - return; - - va_start (args, format); - new = pgm_error_new_valist (error_domain, error_code, format, args); - va_end (args); - - if (NULL == *err) - *err = new; - else - pgm_warn (_(ERROR_OVERWRITTEN_WARNING), new->message); -} - -void -pgm_propagate_error ( - pgm_error_t** restrict dest, - pgm_error_t* restrict src - ) -{ - pgm_return_if_fail (src != NULL); - - if (NULL == dest) { - if (src) - pgm_error_free (src); - return; - } else { - if (NULL != *dest) { - pgm_warn (_(ERROR_OVERWRITTEN_WARNING), src->message); - } else { - *dest = src; - } - } -} - -void -pgm_clear_error ( - pgm_error_t** err - ) -{ - if (err && *err) { - pgm_error_free (*err); - *err = NULL; - } -} - -static -void -pgm_error_add_prefix ( - char** restrict string, - const char* restrict format, - va_list ap - ) -{ - char* prefix = pgm_strdup_vprintf (format, ap); - char* oldstring = *string; - *string = pgm_strconcat (prefix, oldstring, NULL); - pgm_free (oldstring); - pgm_free (prefix); -} - -void -pgm_prefix_error ( - pgm_error_t** restrict err, - const char* restrict format, - ... - ) -{ - if (err && *err) { - va_list ap; - va_start (ap, format); - pgm_error_add_prefix (&(*err)->message, format, ap); - va_end (ap); - } -} - -/* error from libc. - */ - -int -pgm_error_from_errno ( - const int from_errno - ) -{ - switch (from_errno) { -#ifdef EAFNOSUPPORT - case EAFNOSUPPORT: - return PGM_ERROR_AFNOSUPPORT; - break; -#endif - -#ifdef EAGAIN - case EAGAIN: - return PGM_ERROR_AGAIN; - break; -#endif - -#ifdef EBADF - case EBADF: - return PGM_ERROR_BADF; - break; -#endif - -#ifdef ECONNRESET - case ECONNRESET: - return PGM_ERROR_CONNRESET; - break; -#endif - -#ifdef EFAULT - case EFAULT: - return PGM_ERROR_FAULT; - break; -#endif - -#ifdef EINTR - case EINTR: - return PGM_ERROR_INTR; - break; -#endif - -#ifdef EINVAL - case EINVAL: - return PGM_ERROR_INVAL; - break; -#endif - -#ifdef EMFILE - case EMFILE: - return PGM_ERROR_MFILE; - break; -#endif - -#ifdef ENFILE - case ENFILE: - return PGM_ERROR_NFILE; - break; -#endif - -#ifdef ENODEV - case ENODEV: - return PGM_ERROR_NODEV; - break; -#endif - -#ifdef ENOENT - case ENOENT: - return PGM_ERROR_NOENT; - break; -#endif - -#ifdef ENOMEM - case ENOMEM: - return PGM_ERROR_NOMEM; - break; -#endif - -#ifdef ENONET - case ENONET: - return PGM_ERROR_NONET; - break; -#endif - -#ifdef ENOPROTOOPT - case ENOPROTOOPT: - return PGM_ERROR_NOPROTOOPT; - break; -#endif - -#ifdef ENOTUNIQ - case ENOTUNIQ: - return PGM_ERROR_NOTUNIQ; - break; -#endif - -#ifdef ENXIO - case ENXIO: - return PGM_ERROR_NXIO; - break; -#endif - -#ifdef EPERM - case EPERM: - return PGM_ERROR_PERM; - break; -#endif - -#ifdef EPROTO - case EPROTO: - return PGM_ERROR_PROTO; - break; -#endif - -#ifdef ERANGE - case ERANGE: - return PGM_ERROR_RANGE; - break; -#endif - -#ifdef EXDEV - case EXDEV: - return PGM_ERROR_XDEV; - break; -#endif - - default : - return PGM_ERROR_FAILED; - break; - } -} - -/* h_errno from gethostbyname. - */ - -int -pgm_error_from_h_errno ( - const int from_h_errno - ) -{ - switch (from_h_errno) { -#ifdef HOST_NOT_FOUND - case HOST_NOT_FOUND: - return PGM_ERROR_NONAME; - break; -#endif - -#ifdef TRY_AGAIN - case TRY_AGAIN: - return PGM_ERROR_AGAIN; - break; -#endif - -#ifdef NO_RECOVERY - case NO_RECOVERY: - return PGM_ERROR_FAIL; - break; -#endif - -#ifdef NO_DATA - case NO_DATA: - return PGM_ERROR_NODATA; - break; -#endif - - default: - return PGM_ERROR_FAILED; - break; - } -} - -/* errno must be preserved before calling to catch correct error - * status with EAI_SYSTEM. - */ - -int -pgm_error_from_eai_errno ( - const int from_eai_errno, -#ifdef EAI_SYSTEM - const int from_errno -#else - PGM_GNUC_UNUSED const int from_errno -#endif - ) -{ - switch (from_eai_errno) { -#ifdef EAI_ADDRFAMILY - case EAI_ADDRFAMILY: - return PGM_ERROR_ADDRFAMILY; - break; -#endif - -#ifdef EAI_AGAIN - case EAI_AGAIN: - return PGM_ERROR_AGAIN; - break; -#endif - -#ifdef EAI_BADFLAGS - case EAI_BADFLAGS: - return PGM_ERROR_INVAL; - break; -#endif - -#ifdef EAI_FAIL - case EAI_FAIL: - return PGM_ERROR_FAIL; - break; -#endif - -#ifdef EAI_FAMILY - case EAI_FAMILY: - return PGM_ERROR_AFNOSUPPORT; - break; -#endif - -#ifdef EAI_MEMORY - case EAI_MEMORY: - return PGM_ERROR_NOMEM; - break; -#endif - -#ifdef EAI_NODATA - case EAI_NODATA: - return PGM_ERROR_NODATA; - break; -#endif - -#if defined(EAI_NONAME) && EAI_NONAME != EAI_NODATA - case EAI_NONAME: - return PGM_ERROR_NONAME; - break; -#endif - -#ifdef EAI_SERVICE - case EAI_SERVICE: - return PGM_ERROR_SERVICE; - break; -#endif - -#ifdef EAI_SOCKTYPE - case EAI_SOCKTYPE: - return PGM_ERROR_SOCKTNOSUPPORT; - break; -#endif - -#ifdef EAI_SYSTEM - case EAI_SYSTEM: - return pgm_error_from_errno (from_errno); - break; -#endif - - default : - return PGM_ERROR_FAILED; - break; - } -} - -/* from WSAGetLastError() - */ - -int -pgm_error_from_wsa_errno ( - const int from_wsa_errno - ) -{ - switch (from_wsa_errno) { -#ifdef WSAEINVAL - case WSAEINVAL: - return PGM_ERROR_INVAL; - break; -#endif -#ifdef WSAEMFILE - case WSAEMFILE: - return PGM_ERROR_MFILE; - break; -#endif -#ifdef WSA_NOT_ENOUGH_MEMORY - case WSA_NOT_ENOUGH_MEMORY: - return PGM_ERROR_NOMEM; - break; -#endif -#ifdef WSAENOPROTOOPT - case WSAENOPROTOOPT: - return PGM_ERROR_NOPROTOOPT; - break; -#endif -#ifdef WSAECONNRESET - case WSAECONNRESET: - return PGM_ERROR_CONNRESET; - break; -#endif - - default : - return PGM_ERROR_FAILED; - break; - } -} - -/* from Last-Error codes, i.e. Windows non-WinSock and non-DOS errors. - */ - -int -pgm_error_from_win_errno ( - const int from_win_errno - ) -{ - switch (from_win_errno) { -#ifdef ERROR_ADDRESS_NOT_ASSOCIATED - case ERROR_ADDRESS_NOT_ASSOCIATED: - return PGM_ERROR_NODATA; - break; -#endif - -#ifdef ERROR_BUFFER_OVERFLOW - case ERROR_BUFFER_OVERFLOW: - return PGM_ERROR_NOBUFS; - break; -#endif - -#ifdef ERROR_INVALID_DATA - case ERROR_INVALID_DATA: - return PGM_ERROR_BADE; - break; -#endif - -#ifdef ERROR_INSUFFICIENT_BUFFER - case ERROR_INSUFFICIENT_BUFFER: - return PGM_ERROR_NOMEM; - break; -#endif - -#ifdef ERROR_INVALID_PARAMETER - case ERROR_INVALID_PARAMETER: - return PGM_ERROR_INVAL; - break; -#endif - -#ifdef ERROR_NOT_ENOUGH_MEMORY - case ERROR_NOT_ENOUGH_MEMORY: - return PGM_ERROR_NOMEM; - break; -#endif - -#ifdef ERROR_NO_DATA - case ERROR_NO_DATA: - return PGM_ERROR_NODATA; - break; -#endif - -#ifdef ERROR_NOT_SUPPORTED - case ERROR_NOT_SUPPORTED: - return PGM_ERROR_NOSYS; - break; -#endif - - default : - return PGM_ERROR_FAILED; - break; - } -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/error_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/error_unittest.c deleted file mode 100644 index 035c0f3..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/error_unittest.c +++ /dev/null @@ -1,292 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for error reporting. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include - - -/* mock state */ - - - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - - -#define ERROR_DEBUG -#include "error.c" - - -/* target: - * void - * pgm_set_error ( - * pgm_error_t** err, - * int err_domain, - * int err_code, - * const char* format, - * ... - * ) - */ - -START_TEST (test_set_error_pass_001) -{ - pgm_error_t* err = NULL; - const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; - const gint err_code = 100; - pgm_set_error (&err, err_domain, err_code, "an error occurred."); - fail_unless (NULL != err); -} -END_TEST - -START_TEST (test_set_error_pass_002) -{ - pgm_error_t* err = NULL; - const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; - const gint err_code = 100; - pgm_set_error (&err, err_domain, err_code, "an error occurred: value=%d.", 123); - fail_unless (NULL != err); -} -END_TEST - -/* ignore NULL error */ -START_TEST (test_set_error_pass_003) -{ - pgm_error_t* err = NULL; - const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; - const gint err_code = 100; - pgm_set_error (NULL, err_domain, err_code, "an error occurred."); -} -END_TEST - -/* overwritten error */ -START_TEST (test_set_error_pass_004) -{ - pgm_error_t* err = NULL; - const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; - const gint err_code = 100; - pgm_set_error (&err, err_domain, err_code, "an error occurred."); - fail_unless (NULL != err); - pgm_set_error (&err, err_domain, err_code, "another error occurred."); -} -END_TEST - -/* target: - * void - * pgm_prefix_error ( - * pgm_error_t** err, - * const char* format, - * ... - * ) - */ - -START_TEST (test_prefix_error_pass_001) -{ - pgm_error_t* err = NULL; - const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; - const gint err_code = 100; - pgm_set_error (&err, err_domain, err_code, "an error occurred."); - fail_unless (NULL != err); - pgm_prefix_error (&err, "i am a prefix:"); - pgm_prefix_error (&err, "i am another prefix, value=%d:", 123); -} -END_TEST - -/* ignore null original error */ -START_TEST (test_prefix_error_pass_002) -{ - pgm_error_t* err = NULL; - pgm_prefix_error (&err, "i am a prefix:"); -} -END_TEST - -/* target: - * void - * pgm_propagate_error ( - * pgm_error_t** dest, - * pgm_error_t* src, - * ) - */ - -START_TEST (test_propagate_error_pass_001) -{ - pgm_error_t* dest = NULL; - pgm_error_t* err = NULL; - const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; - const gint err_code = 100; - pgm_set_error (&err, err_domain, err_code, "an error occurred."); - fail_unless (NULL != err); - pgm_propagate_error (&dest, err); - fail_unless (NULL != dest); -} -END_TEST - -/* ignore NULL destination */ -START_TEST (test_propagate_error_pass_002) -{ - pgm_error_t* err = NULL; - const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; - const gint err_code = 100; - pgm_set_error (&err, err_domain, err_code, "an error occurred."); - fail_unless (NULL != err); - pgm_propagate_error (NULL, err); -} -END_TEST - -/* src error SHOULD be valid */ -START_TEST (test_propagate_error_pass_003) -{ - pgm_error_t* dest = NULL; - pgm_error_t* err = NULL; - pgm_propagate_error (&dest, err); -} -END_TEST - -/* target: - * void - * pgm_clear_error ( - * pgm_error_t** err - * ) - */ - -START_TEST (test_clear_error_pass_001) -{ - pgm_error_t* err = NULL; - const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; - const gint err_code = 100; - pgm_set_error (&err, err_domain, err_code, "an error occurred."); - fail_unless (NULL != err); - pgm_clear_error (&err); - fail_unless (NULL == err); -} -END_TEST - -START_TEST (test_clear_error_pass_002) -{ - pgm_error_t* err = NULL; - pgm_clear_error (&err); - fail_unless (NULL == err); -} -END_TEST - -START_TEST (test_clear_error_pass_003) -{ - pgm_clear_error (NULL); -} -END_TEST - -/* target: - * void - * pgm_error_free ( - * pgm_error_t* err - * ) - */ - -START_TEST (test_error_free_pass_001) -{ - pgm_error_t* err = NULL; - const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; - const gint err_code = 100; - pgm_set_error (&err, err_domain, err_code, "an error occurred."); - fail_unless (NULL != err); - pgm_error_free (err); -} -END_TEST - -START_TEST (test_error_free_pass_002) -{ - pgm_error_free (NULL); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_set_error = tcase_create ("set-error"); - suite_add_tcase (s, tc_set_error); - tcase_add_test (tc_set_error, test_set_error_pass_001); - tcase_add_test (tc_set_error, test_set_error_pass_002); - tcase_add_test (tc_set_error, test_set_error_pass_003); - tcase_add_test (tc_set_error, test_set_error_pass_004); - - TCase* tc_prefix_error = tcase_create ("prefix-error"); - suite_add_tcase (s, tc_prefix_error); - tcase_add_test (tc_prefix_error, test_prefix_error_pass_001); - tcase_add_test (tc_prefix_error, test_prefix_error_pass_002); - - TCase* tc_propagate_error = tcase_create ("propagate-error"); - suite_add_tcase (s, tc_propagate_error); - tcase_add_test (tc_propagate_error, test_propagate_error_pass_001); - tcase_add_test (tc_propagate_error, test_propagate_error_pass_002); - tcase_add_test (tc_propagate_error, test_propagate_error_pass_003); - - TCase* tc_clear_error = tcase_create ("clear-error"); - suite_add_tcase (s, tc_clear_error); - tcase_add_test (tc_clear_error, test_clear_error_pass_001); - tcase_add_test (tc_clear_error, test_clear_error_pass_002); - tcase_add_test (tc_clear_error, test_clear_error_pass_003); - - TCase* tc_error_free = tcase_create ("error-free"); - suite_add_tcase (s, tc_error_free); - tcase_add_test (tc_error_free, test_error_free_pass_001); - tcase_add_test (tc_error_free, test_error_free_pass_002); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/SConscript b/3rdparty/openpgm-svn-r1085/pgm/examples/SConscript deleted file mode 100644 index 46ebce3..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/SConscript +++ /dev/null @@ -1,88 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script -# $Id$ - -import os; - -Import('env'); -e = env.Clone(); -e.Prepend(LIBS = ['libpgm']); -p = e.Clone(); -if '-DCONFIG_HAVE_GETOPT' in env['CCFLAGS']: - getopt = [] -else: - getopt = ['getopt.c'] - -if e['WITH_GLIB'] == 'true': - e.Prepend(LIBS = ['libpgmex']); - e.MergeFlags(env['GLIB_FLAGS']); - e2 = e.Clone(); - if e2['WITH_SNMP'] == 'true': - e2.Append(CCFLAGS = ['-DCONFIG_WITH_SNMP']); - e2.Prepend(LIBS = ['libpgmsnmp']); - e2.MergeFlags(e['SNMP_FLAGS']); - if e2['WITH_HTTP'] == 'true': - e2.Append(CCFLAGS = ['-DCONFIG_WITH_HTTP']); - e2.Prepend(LIBS = ['libpgmhttp']); - -# core preferred examples - e.Program(['pgmdump.c']) - e2.Program(['pgmsend.c']) - e2.Program(['pgmrecv.c']) - -# sync examples - e.Program(['blocksyncrecv.c']) - e.Program(['snonblocksyncrecv.c']) - if '-DCONFIG_HAVE_POLL' in e['CCFLAGS']: - e.Program(['pnonblocksyncrecv.c']) - -# epoll based examples - if '-DCONFIG_HAVE_EPOLL' in e['CCFLAGS']: - e.Program(['enonblocksyncrecv.c']) - e.Program(['enonblocksyncrecvmsg.c']) - e.Program(['enonblocksyncrecvmsgv.c']) - -# ncurses examples - if e['WITH_NCURSES'] == 'true': - en = e.Clone() - en.Append(LIBS = ['panel', 'ncurses']); - en.Program(['pgmtop.c']) - -# Google Protocol Buffer example - if e['WITH_PROTOBUF'] == 'true': - ep = e2.Clone(); - newCCFLAGS = []; - for flag in ep['CCFLAGS']: - if ("-W" != flag[:2]) and ("-std=gnu99" != flag[:10]) and ("-pedantic" != flag[:9]) and ("-D_XOPEN_SOURCE=600" != flag[:19]) and ("-xc99=all" != flag[:9]): - newCCFLAGS.append(flag); - if ("-D_XOPEN_SOURCE=600" == flag[:19]): - newCCFLAGS.append("-D_XOPEN_SOURCE=500"); - ep['CCFLAGS'] = newCCFLAGS; - ep.Append(CPPPATH = '.'); - ep.Append(CCFLAGS = ep['PROTOBUF_CCFLAGS']); - ep.Depends('pgmping.cc', ['ping.pb.cc', 'ping.pb.h']); - protobuf = Builder(action = 'cd ${SOURCE.dir} && %s ${SOURCE.file} --cpp_out=../${TARGET.dir}' % ep['PROTOBUF_PROTOC']) - ep.Append(BUILDERS = {'Protobuf' : protobuf}) - ep.Protobuf('ping.pb.cc', 'ping.proto') - ep.Program(['pgmping.cc', 'ping.pb.cc', ep['PROTOBUF_LIBS']]) - -# Vanilla example -p.Program(['purinsend.c'] + getopt) -p.Program(['purinrecv.c'] + getopt) -p.Program(['daytime.c'] + getopt) -p.Program(['shortcakerecv.c', 'async.c'] + getopt) - -# Vanilla C++ example -if e['WITH_CC'] == 'true': - pcc = p.Clone(); - newCCFLAGS = []; - for flag in pcc['CCFLAGS']: - if ("-W" != flag[:2]) and ("-std=gnu99" != flag[:10]) and ("-pedantic" != flag[:9]) and ("-D_XOPEN_SOURCE=600" != flag[:19]) and ("-xc99=all" != flag[:9]): - newCCFLAGS.append(flag); - if ("-D_XOPEN_SOURCE=600" == flag[:19]): - newCCFLAGS.append("-D_XOPEN_SOURCE=500"); - pcc['CCFLAGS'] = newCCFLAGS; - pcc.Program('purinsendcc', ['purinsendcc.cc'] + p.Object(getopt)) - pcc.Program('purinrecvcc', ['purinrecvcc.cc'] + p.Object(getopt)) - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/SConscript89 b/3rdparty/openpgm-svn-r1085/pgm/examples/SConscript89 deleted file mode 100644 index 5595d3d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/SConscript89 +++ /dev/null @@ -1,41 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script -# $Id$ - -import os; - -Import('env'); -e = env.Clone(); -e.Prepend(LIBS = ['libpgm89']); -p = e.Clone(); -if '-DCONFIG_HAVE_GETOPT' in env['CCFLAGS']: - getopt = [] -else: - getopt = ['getopt.c'] - -c89source = Builder(action = 'perl -p -e "s/%z(u|d)/%l\\1/g" $SOURCE > $TARGET', - suffix = '.c89.c', - src_suffix = '.c', - single_source = 1); -p.Append(BUILDERS = {'C89Source' : c89source}) - -for c99file in ['purinsend.c', 'purinrecv.c']: - p.C89Source(c99file); - -p.Program('purinsend', ['purinsend.c89.c'] + getopt) -p.Program('purinrecv', ['purinrecv.c89.c'] + getopt) - -# Vanilla C++ example -if e['WITH_CC'] == 'true': - pcc = p.Clone(); - newCCFLAGS = []; - for flag in pcc['CCFLAGS']: - if ("-W" != flag[:2]) and ("-std=gnu99" != flag[:10]) and ("-pedantic" != flag[:9]) and ("-D_XOPEN_SOURCE=600" != flag[:19]) and ("-xc99=all" != flag[:9]): - newCCFLAGS.append(flag); - if ("-D_XOPEN_SOURCE=600" == flag[:19]): - newCCFLAGS.append("-D_XOPEN_SOURCE=500"); - pcc['CCFLAGS'] = newCCFLAGS; - pcc.Program('purinsendcc', ['purinsendcc.cc'] + p.Object(getopt)) - pcc.Program('purinrecvcc', ['purinrecvcc.cc'] + p.Object(getopt)) - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/async.c b/3rdparty/openpgm-svn-r1085/pgm/examples/async.c deleted file mode 100644 index 042bf8e..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/async.c +++ /dev/null @@ -1,441 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Asynchronous queue for receiving packets in a separate managed thread. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#ifndef _WIN32 -# include -# include -# include -#else -# include -#endif -#include - -#include "async.h" - - -/* locals */ - -struct async_event_t { - struct async_event_t *next, *prev; - size_t len; - struct pgm_sockaddr_t addr; -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - char data[]; -#elif defined(__cplusplus) - char data[1]; -#else - char data[0]; -#endif -}; - - -static void on_data (async_t*const restrict, const void*restrict, const size_t, const struct pgm_sockaddr_t*restrict, const socklen_t); - - -/* queued data is stored as async_event_t objects - */ - -static inline -struct async_event_t* -async_event_alloc ( - size_t len - ) -{ - struct async_event_t* event; - event = (struct async_event_t*)calloc (1, len + sizeof(struct async_event_t)); - event->len = len; - return event; -} - -static inline -void -async_event_unref ( - struct async_event_t* const event - ) -{ - free (event); -} - -/* async_t implements a queue - */ - -static inline -void -async_push_event ( - async_t* restrict async, - struct async_event_t* restrict event - ) -{ - event->next = async->head; - if (async->head) - async->head->prev = event; - else - async->tail = event; - async->head = event; - async->length++; -} - -static inline -struct async_event_t* -async_pop_event ( - async_t* async - ) -{ - if (async->tail) - { - struct async_event_t *event = async->tail; - - async->tail = event->prev; - if (async->tail) - { - async->tail->next = NULL; - event->prev = NULL; - } - else - async->head = NULL; - async->length--; - - return event; - } - - return NULL; -} - -/* asynchronous receiver thread, sits in a loop processing incoming packets - */ - -static -#ifndef _WIN32 -void* -#else -unsigned -__stdcall -#endif -receiver_routine ( - void* arg - ) -{ - assert (NULL != arg); - async_t* async = (async_t*)arg; - assert (NULL != async->sock); -#ifndef _WIN32 - int fds; - fd_set readfds; -#else - int n_handles = 3, recv_sock, pending_sock; - HANDLE waitHandles[ 3 ]; - DWORD dwTimeout, dwEvents; - WSAEVENT recvEvent, pendingEvent; - socklen_t socklen = sizeof(int); - - recvEvent = WSACreateEvent (); - pgm_getsockopt (async->sock, PGM_RECV_SOCK, &recv_sock, &socklen); - WSAEventSelect (recv_sock, recvEvent, FD_READ); - pendingEvent = WSACreateEvent (); - pgm_getsockopt (async->sock, PGM_PENDING_SOCK, &pending_sock, &socklen); - WSAEventSelect (pending_sock, pendingEvent, FD_READ); - - waitHandles[0] = async->destroy_event; - waitHandles[1] = recvEvent; - waitHandles[2] = pendingEvent; -#endif /* !_WIN32 */ - -/* dispatch loop */ - do { - struct timeval tv; - char buffer[4096]; - size_t len; - struct pgm_sockaddr_t from; - socklen_t fromlen = sizeof (from); - const int status = pgm_recvfrom (async->sock, - buffer, - sizeof(buffer), - 0, - &len, - &from, - &fromlen, - NULL); - switch (status) { - case PGM_IO_STATUS_NORMAL: - on_data (async, buffer, len, &from, fromlen); - break; - case PGM_IO_STATUS_TIMER_PENDING: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (async->sock, PGM_TIME_REMAIN, &tv, &optlen); - } - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (async->sock, PGM_RATE_REMAIN, &tv, &optlen); - } - case PGM_IO_STATUS_WOULD_BLOCK: -/* select for next event */ -block: -#ifndef _WIN32 - fds = async->destroy_pipe[0] + 1; - FD_ZERO(&readfds); - FD_SET(async->destroy_pipe[0], &readfds); - pgm_select_info (async->sock, &readfds, NULL, &fds); - fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); -#else - dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv. -tv_usec / 1000)); - dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout); - switch (dwEvents) { - case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; - case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break; - default: break; - } -#endif /* !_WIN32 */ - break; - - default: - if (PGM_IO_STATUS_ERROR == status) - break; - } - } while (!async->is_destroyed); - -/* cleanup */ -#ifndef _WIN32 - return NULL; -#else - WSACloseEvent (recvEvent); - WSACloseEvent (pendingEvent); - _endthread(); - return 0; -#endif /* !_WIN32 */ -} - -/* enqueue a new data event. - */ - -static -void -on_data ( - async_t*const restrict async, - const void* restrict data, - const size_t len, - const struct pgm_sockaddr_t* restrict from, - const socklen_t fromlen - ) -{ - struct async_event_t* event = async_event_alloc (len); - memcpy (&event->addr, from, fromlen); - memcpy (&event->data, data, len); -#ifndef _WIN32 - pthread_mutex_lock (&async->pthread_mutex); - async_push_event (async, event); - if (1 == async->length) { - const char one = '1'; - const size_t writelen = write (async->notify_pipe[1], &one, sizeof(one)); - assert (sizeof(one) == writelen); - } - pthread_mutex_unlock (&async->pthread_mutex); -#else - WaitForSingleObject (async->win32_mutex, INFINITE); - async_push_event (async, event); - if (1 == async->length) { - SetEvent (async->notify_event); - } - ReleaseMutex (async->win32_mutex); -#endif /* _WIN32 */ -} - -/* create asynchronous thread handler from bound PGM sock. - * - * on success, 0 is returned. on error, -1 is returned, and errno set appropriately. - */ - -int -async_create ( - async_t** restrict async, - pgm_sock_t* const restrict sock - ) -{ - async_t* new_async; - - if (NULL == async || NULL == sock) { - errno = EINVAL; - return -1; - } - - new_async = (async_t*)calloc (1, sizeof(async_t)); - new_async->sock = sock; -#ifndef _WIN32 - int e; - e = pthread_mutex_init (&new_async->pthread_mutex, NULL); - if (0 != e) goto err_destroy; - e = pipe (new_async->notify_pipe); - const int flags = fcntl (new_async->notify_pipe[0], F_GETFL); - fcntl (new_async->notify_pipe[0], F_SETFL, flags | O_NONBLOCK); - if (0 != e) goto err_destroy; - e = pipe (new_async->destroy_pipe); - if (0 != e) goto err_destroy; - const int status = pthread_create (&new_async->thread, NULL, &receiver_routine, new_async); - if (0 != status) goto err_destroy; -#else - new_async->win32_mutex = CreateMutex (NULL, FALSE, NULL); - new_async->notify_event = CreateEvent (NULL, TRUE, FALSE, TEXT("AsyncNotify")); - new_async->destroy_event = CreateEvent (NULL, TRUE, FALSE, TEXT("AsyncDestroy")); - new_async->thread = (HANDLE)_beginthreadex (NULL, 0, &receiver_routine, new_async, 0, NULL); - if (0 == new_async->thread) goto err_destroy; -#endif /* _WIN32 */ - -/* return new object */ - *async = new_async; - return 0; - -err_destroy: -#ifndef _WIN32 - close (new_async->destroy_pipe[0]); - close (new_async->destroy_pipe[1]); - close (new_async->notify_pipe[0]); - close (new_async->notify_pipe[1]); - pthread_mutex_destroy (&new_async->pthread_mutex); -#else - CloseHandle (new_async->destroy_event); - CloseHandle (new_async->notify_event); - CloseHandle (new_async->win32_mutex); -#endif /* _WIN32 */ - if (new_async) - free (new_async); - return -1; -} - -/* Destroy asynchronous receiver, there must be no active queue consumer. - * - * on success, 0 is returned, on error -1 is returned and errno set appropriately. - */ - -int -async_destroy ( - async_t* const async - ) -{ - if (NULL == async || async->is_destroyed) { - errno = EINVAL; - return -1; - } - - async->is_destroyed = TRUE; -#ifndef _WIN32 - const char one = '1'; - const size_t writelen = write (async->destroy_pipe[1], &one, sizeof(one)); - assert (sizeof(one) == writelen); - pthread_join (async->thread, NULL); - close (async->destroy_pipe[0]); - close (async->destroy_pipe[1]); - close (async->notify_pipe[0]); - close (async->notify_pipe[1]); - pthread_mutex_destroy (&async->pthread_mutex); -#else - SetEvent (async->destroy_event); - WaitForSingleObject (async->thread, INFINITE); - CloseHandle (async->thread); - CloseHandle (async->destroy_event); - CloseHandle (async->notify_event); - CloseHandle (async->win32_mutex); -#endif /* !_WIN32 */ - while (async->head) { - struct async_event_t *next = async->head->next; - async_event_unref (async->head); - async->head = next; - async->length--; - } - free (async); - return 0; -} - -/* synchronous reading from the queue. - * - * returns GIOStatus with success, error, again, or eof. - */ - -ssize_t -async_recvfrom ( - async_t* const restrict async, - void* restrict buf, - size_t len, - struct pgm_sockaddr_t* restrict from, - socklen_t* restrict fromlen - ) -{ - struct async_event_t* event; - - if (NULL == async || NULL == buf || async->is_destroyed) { - errno = EINVAL; - return -1; - } - -#ifndef _WIN32 - pthread_mutex_lock (&async->pthread_mutex); - if (0 == async->length) { -/* flush event pipe */ - char tmp; - while (sizeof(tmp) == read (async->notify_pipe[0], &tmp, sizeof(tmp))); - pthread_mutex_unlock (&async->pthread_mutex); - errno = EAGAIN; - return -1; - } - event = async_pop_event (async); - pthread_mutex_unlock (&async->pthread_mutex); -#else - WaitForSingleObject (async->win32_mutex, INFINITE); - if (0 == async->length) { -/* clear event */ - ResetEvent (async->notify_event); - ReleaseMutex (async->win32_mutex); - errno = EAGAIN; - return -1; - } - event = async_pop_event (async); - ReleaseMutex (async->win32_mutex); -#endif /* _WIN32 */ - assert (NULL != event); - -/* pass data back to callee */ - const size_t event_len = MIN(event->len, len); - if (NULL != from && sizeof(struct pgm_sockaddr_t) == *fromlen) { - memcpy (from, &event->addr, *fromlen); - } - memcpy (buf, event->data, event_len); - async_event_unref (event); - return event_len; -} - -ssize_t -async_recv ( - async_t* const restrict async, - void* restrict buf, - size_t len - ) -{ - return async_recvfrom (async, buf, len, NULL, NULL); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/async.h b/3rdparty/openpgm-svn-r1085/pgm/examples/async.h deleted file mode 100644 index 788a777..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/async.h +++ /dev/null @@ -1,82 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Asynchronous receive thread helper - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_ASYNC_H__ -#define __PGM_ASYNC_H__ - -struct async_event_t; - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct async_t { - pgm_sock_t* sock; -#ifndef _WIN32 - pthread_t thread; - int notify_pipe[2]; - int destroy_pipe[2]; - pthread_mutex_t pthread_mutex; -#else - HANDLE thread; - HANDLE notify_event; - HANDLE destroy_event; - HANDLE win32_mutex; -#endif - struct async_event_t *head, *tail; - unsigned length; - bool is_destroyed; -}; -typedef struct async_t async_t; - -int async_create (async_t** restrict, pgm_sock_t*const restrict); -int async_destroy (async_t* const); -ssize_t async_recv (async_t*const restrict, void* restrict, size_t); -ssize_t async_recvfrom (async_t*const restrict, void*restrict, size_t, struct pgm_sockaddr_t*restrict, socklen_t*restrict); - -#ifndef _WIN32 -static inline int async_get_fd (async_t* async) -{ - if (NULL == async) { - errno = EINVAL; - return -1; - } - return async->notify_pipe[0]; -} -#else -static inline HANDLE async_get_event (async_t* async) -{ - if (NULL == async) { - errno = EINVAL; - return NULL; - } - return async->notify_event; -} -#endif /* _WIN32 */ - -#ifdef __cplusplus -} -#endif - -#endif /* __PGM_ASYNC_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/blocksyncrecv.c b/3rdparty/openpgm-svn-r1085/pgm/examples/blocksyncrecv.c deleted file mode 100644 index ec43d17..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/blocksyncrecv.c +++ /dev/null @@ -1,350 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Simple PGM receiver: blocking synchronous receiver - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#ifndef G_OS_WIN32 -# include -#else -# include "getopt.h" -#endif -#include - -/* example dependencies */ -#include -#include - - -/* typedefs */ - -/* globals */ - -static int g_port = 0; -static const char* g_network = ""; -static gboolean g_multicast_loop = FALSE; -static int g_udp_encap_port = 0; - -static int g_max_tpdu = 1500; -static int g_sqns = 100; - -static pgm_sock_t* g_sock = NULL; -static gboolean g_quit = FALSE; - -#ifdef G_OS_UNIX -static void on_signal (int); -#else -static BOOL on_console_ctrl (DWORD); -#endif -static gboolean on_startup (void); -static int on_data (gconstpointer, size_t, struct pgm_sockaddr_t*); - - -G_GNUC_NORETURN static -void -usage ( - const char* bin - ) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); - exit (1); -} - -int -main ( - int argc, - char* argv[] - ) -{ - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - - log_init (); - g_message ("blocksyncrecv"); - - if (!pgm_init (&pgm_err)) { - g_error ("Unable to start PGM engine: %s", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) - { - switch (c) { - case 'n': g_network = optarg; break; - case 's': g_port = atoi (optarg); break; - case 'p': g_udp_encap_port = atoi (optarg); break; - case 'l': g_multicast_loop = TRUE; break; - - case 'h': - case '?': usage (binary_name); - } - } - -/* setup signal handlers */ - signal(SIGSEGV, on_sigsegv); -#ifdef SIGHUP - signal(SIGHUP, SIG_IGN); -#endif -#ifdef G_OS_UNIX - signal(SIGINT, on_signal); - signal(SIGTERM, on_signal); -#else - SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); -#endif - - on_startup(); - -/* dispatch loop */ - g_message ("entering PGM message loop ... "); - do { - char buffer[4096]; - size_t len; - struct pgm_sockaddr_t from; - socklen_t fromlen = sizeof(from); - const int status = pgm_recvfrom (g_sock, - buffer, - sizeof(buffer), - 0, - &len, - &from, - &fromlen, - &pgm_err); - if (PGM_IO_STATUS_NORMAL == status) - on_data (buffer, len, &from); - else { - if (pgm_err) { - g_warning ("%s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_err = NULL; - } - if (PGM_IO_STATUS_ERROR == status) - break; - } - } while (!g_quit); - - g_message ("message loop terminated, cleaning up."); - -/* cleanup */ - if (g_sock) { - g_message ("closing PGM socket."); - pgm_close (g_sock, TRUE); - g_sock = NULL; - } - - g_message ("PGM engine shutdown."); - pgm_shutdown (); - g_message ("finished."); - return EXIT_SUCCESS; -} - -#ifdef G_OS_UNIX -static -void -on_signal ( - int signum - ) -{ - g_message ("on_signal (signum:%d)", signum); - g_quit = TRUE; -} -#else -static -BOOL -on_console_ctrl ( - DWORD dwCtrlType - ) -{ - g_message ("on_console_ctrl (dwCtrlType:%lu)", (unsigned long)dwCtrlType); - g_quit = TRUE; - return TRUE; -} -#endif /* !G_OS_UNIX */ - -static -gboolean -on_startup (void) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - - g_message ("startup."); - -/* parse network parameter into transport address structure */ - if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { - g_error ("parsing network parameter: %s", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - if (g_udp_encap_port) { - g_message ("create PGM/UDP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - } else { - g_message ("create PGM/IP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (g_sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int recv_only = 1, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (50), - nak_rpt_ivl = pgm_secs (2), - nak_rdata_ivl = pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50; - - pgm_setsockopt (g_sock, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - pgm_setsockopt (g_sock, PGM_PASSIVE, &passive, sizeof(passive)); - pgm_setsockopt (g_sock, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); - pgm_setsockopt (g_sock, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); - pgm_setsockopt (g_sock, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - pgm_setsockopt (g_sock, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - pgm_setsockopt (g_sock, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - pgm_setsockopt (g_sock, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - g_error ("creating GSI: %s", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (g_sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - g_error ("binding PGM socket: %s", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (g_sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (g_sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int blocking = 0, - multicast_loop = g_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (g_sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (g_sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (g_sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (g_sock, PGM_NOBLOCK, &blocking, sizeof(blocking)); - - if (!pgm_connect (g_sock, &pgm_err)) { - g_error ("connecting PGM socket: %s", pgm_err->message); - goto err_abort; - } - - g_message ("startup complete."); - return TRUE; - -err_abort: - if (NULL != g_sock) { - pgm_close (g_sock, FALSE); - g_sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -static -int -on_data ( - gconstpointer data, - size_t len, - struct pgm_sockaddr_t* from - ) -{ -/* protect against non-null terminated strings */ - char buf[1024], tsi[PGM_TSISTRLEN]; - const size_t buflen = MIN( sizeof(buf) - 1, len ); - strncpy (buf, data, buflen); - buf[buflen] = '\0'; - pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); - - g_message ("\"%s\" (%u bytes from %s)", - buf, - (unsigned)len, - tsi); - - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/daytime.c b/3rdparty/openpgm-svn-r1085/pgm/examples/daytime.c deleted file mode 100644 index dda619b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/daytime.c +++ /dev/null @@ -1,546 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Daytime broadcast service. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#ifndef _WIN32 -# include -# include -# include -#else -# include -# include -# include "getopt.h" -# define snprintf _snprintf -#endif -#include - - -/* globals */ -#define TIME_FORMAT "%a, %d %b %Y %H:%M:%S %z" - -static int port = 0; -static const char* network = ""; -static bool use_multicast_loop = FALSE; -static int udp_encap_port = 0; - -static int max_tpdu = 1500; -static int max_rte = 400*1000; /* very conservative rate, 2.5mb/s */ -static int sqns = 100; - -static bool use_pgmcc = FALSE; -static bool use_fec = FALSE; -static bool use_ondemand_parity = FALSE; -static int proactive_packets = 0; -static int rs_k = 8; -static int rs_n = 255; - -static pgm_sock_t* sock = NULL; -static bool is_terminated = FALSE; - -#ifndef _WIN32 -static pthread_t nak_thread; -static int terminate_pipe[2]; -static void on_signal (int); -static void* nak_routine (void*); -#else -static HANDLE nak_thread; -static HANDLE terminate_event; -static BOOL on_console_ctrl (DWORD); -static unsigned __stdcall nak_routine (void*); -#endif -#ifndef _MSC_VER -static void usage (const char*) __attribute__((__noreturn__)); -#else -static void usage (const char*); -#endif - -static bool on_startup (void); -static bool create_sock (void); -static bool create_nak_thread (void); - - -static void -usage ( - const char* bin - ) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -r : Regulate to rate bytes per second\n"); - fprintf (stderr, " -c : Enable PGMCC\n"); - fprintf (stderr, " -f : Enable FEC: proactive, ondemand, or both\n"); - fprintf (stderr, " -N : Reed-Solomon block size (255)\n"); - fprintf (stderr, " -K : Reed-Solomon group size (8)\n"); - fprintf (stderr, " -P : Number of pro-active parity packets (h)\n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); - fprintf (stderr, " -i : List available interfaces\n"); - exit (EXIT_SUCCESS); -} - -int -main ( - int argc, - char *argv[] - ) -{ - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - - puts ("PGM daytime service"); - - if (!pgm_init (&pgm_err)) { - fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:r:cf:N:K:P:lih")) != -1) - { - switch (c) { - case 'n': network = optarg; break; - case 's': port = atoi (optarg); break; - case 'p': udp_encap_port = atoi (optarg); break; - case 'r': max_rte = atoi (optarg); break; - case 'c': use_pgmcc = TRUE; break; - case 'f': - use_fec = TRUE; - switch (optarg[0]) { - case 'p': - case 'P': - proactive_packets = 1; - break; - case 'b': - case 'B': - proactive_packets = 1; - case 'o': - case 'O': - use_ondemand_parity = TRUE; - break; - } - break; - case 'N': rs_n = atoi (optarg); break; - case 'K': rs_k = atoi (optarg); break; - case 'P': proactive_packets = atoi (optarg); break; - - case 'l': use_multicast_loop = TRUE; break; - - case 'i': - pgm_if_print_all(); - return EXIT_SUCCESS; - - case 'h': - case '?': - usage (binary_name); - } - } - - if (use_fec && ( !rs_n || !rs_k )) { - fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); - usage (binary_name); - } - -/* setup signal handlers */ -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif -#ifndef _WIN32 - int e = pipe (terminate_pipe); - assert (0 == e); - const int flags = fcntl (terminate_pipe[0], F_GETFL); - fcntl (terminate_pipe[0], F_SETFL, flags | O_NONBLOCK); - signal (SIGINT, on_signal); - signal (SIGTERM, on_signal); -#else - terminate_event = CreateEvent (NULL, TRUE, FALSE, TEXT("TerminateEvent")); - SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); -#endif /* !_WIN32 */ - - if (!on_startup()) { - fprintf (stderr, "Startup failed\n"); - return EXIT_FAILURE; - } - -/* service loop */ - do { - time_t now; - time (&now); - const struct tm* time_ptr = localtime(&now); -#ifndef _WIN32 - char s[1024]; - const size_t slen = strftime (s, sizeof(s), TIME_FORMAT, time_ptr); - const int status = pgm_send (sock, s, slen + 1, NULL); -#else - char s[1024]; - const size_t slen = strftime (s, sizeof(s), TIME_FORMAT, time_ptr); - wchar_t ws[1024]; - size_t wslen = MultiByteToWideChar (CP_ACP, 0, s, slen, ws, 1024); - char us[1024]; - size_t uslen = WideCharToMultiByte (CP_UTF8, 0, ws, wslen + 1, us, sizeof(us), NULL, NULL); - const int status = pgm_send (sock, us, uslen + 1, NULL); -#endif - if (PGM_IO_STATUS_NORMAL != status) { - fprintf (stderr, "pgm_send() failed.\n"); - } -#ifndef _WIN32 - sleep (1); -#else - Sleep (1 * 1000); -#endif - } while (!is_terminated); - -/* cleanup */ - puts ("Waiting for NAK thread."); -#ifndef _WIN32 - pthread_join (nak_thread, NULL); - close (terminate_pipe[0]); - close (terminate_pipe[1]); -#else - WaitForSingleObject (nak_thread, INFINITE); - CloseHandle (nak_thread); - CloseHandle (terminate_event); -#endif /* !_WIN32 */ - - if (sock) { - puts ("Closing PGM sock."); - pgm_close (sock, TRUE); - sock = NULL; - } - - puts ("PGM engine shutdown."); - pgm_shutdown(); - puts ("finished."); - return EXIT_SUCCESS; -} - -#ifndef _WIN32 -static -void -on_signal ( - int signum - ) -{ - printf ("on_signal (signum:%d)\n", signum); - is_terminated = TRUE; - const char one = '1'; - const size_t writelen = write (terminate_pipe[1], &one, sizeof(one)); - assert (sizeof(one) == writelen); -} -#else -static -BOOL -on_console_ctrl ( - DWORD dwCtrlType - ) -{ - printf ("on_console_ctrl (dwCtrlType:%lu)\n", (unsigned long)dwCtrlType); - is_terminated = TRUE; - SetEvent (terminate_event); - return TRUE; -} -#endif /* !_WIN32 */ - -static -bool -on_startup (void) -{ - bool status = (create_sock() && create_nak_thread()); - if (status) - puts ("Startup complete."); - return status; -} - -static -bool -create_sock (void) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - -/* parse network parameter into sock address structure */ - if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { - fprintf (stderr, "Parsing network parameter: %s\n", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - puts ("Create PGM socket."); - if (udp_encap_port) { - if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - fprintf (stderr, "Creating PGM/UDP socket: %s\n", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (sock, PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - pgm_setsockopt (sock, PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - } else { - if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - fprintf (stderr, "Creating PGM/IP socket: %s\n", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int send_only = 1, - ambient_spm = pgm_secs (30), - heartbeat_spm[] = { pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (1300), - pgm_secs (7), - pgm_secs (16), - pgm_secs (25), - pgm_secs (30) }; - - pgm_setsockopt (sock, PGM_SEND_ONLY, &send_only, sizeof(send_only)); - pgm_setsockopt (sock, PGM_MTU, &max_tpdu, sizeof(max_tpdu)); - pgm_setsockopt (sock, PGM_TXW_SQNS, &sqns, sizeof(sqns)); - pgm_setsockopt (sock, PGM_TXW_MAX_RTE, &max_rte, sizeof(max_rte)); - pgm_setsockopt (sock, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm)); - pgm_setsockopt (sock, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm)); - -#ifdef I_UNDERSTAND_PGMCC_AND_FEC_ARE_NOT_SUPPORTED - if (use_pgmcc) { - struct pgm_pgmccinfo_t pgmccinfo; - pgmccinfo.ack_bo_ivl = pgm_msecs (50); - pgmccinfo.ack_c = 75; - pgmccinfo.ack_c_p = 500; - pgm_setsockopt (sock, PGM_USE_PGMCC, &pgmccinfo, sizeof(pgmccinfo)); - } - if (use_fec) { - struct pgm_fecinfo_t fecinfo; - fecinfo.block_size = rs_n; - fecinfo.proactive_packets = proactive_packets; - fecinfo.group_size = rs_k; - fecinfo.ondemand_parity_enabled = use_ondemand_parity; - fecinfo.var_pktlen_enabled = TRUE; - pgm_setsockopt (sock, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); - } -#endif - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = port ? port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - fprintf (stderr, "Creating GSI: %s\n", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - fprintf (stderr, "Binding PGM socket: %s\n", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int nonblocking = 1, - multicast_loop = use_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (sock, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); - - if (!pgm_connect (sock, &pgm_err)) { - fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message); - goto err_abort; - } - - return TRUE; - -err_abort: - if (NULL != sock) { - pgm_close (sock, FALSE); - sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -static -bool -create_nak_thread (void) -{ -#ifndef _WIN32 - const int status = pthread_create (&nak_thread, NULL, &nak_routine, sock); - if (0 != status) { - fprintf (stderr, "Creating new thread: %s\n", strerror (status)); - return FALSE; - } -#else - nak_thread = (HANDLE)_beginthreadex (NULL, 0, &nak_routine, sock, 0, NULL); - const int save_errno = errno; - if (0 == nak_thread) { - fprintf (stderr, "Creating new thread: %s\n", strerror (save_errno)); - return FALSE; - } -#endif /* _WIN32 */ - return TRUE; -} - -static -#ifndef _WIN32 -void* -#else -unsigned -__stdcall -#endif -nak_routine ( - void* arg - ) -{ -/* dispatch loop */ - pgm_sock_t* nak_sock = (pgm_sock_t*)arg; -#ifndef _WIN32 - int fds; - fd_set readfds; -#else - int n_handles = 4, recv_sock, repair_sock, pending_sock; - HANDLE waitHandles[ 4 ]; - DWORD dwTimeout, dwEvents; - WSAEVENT recvEvent, repairEvent, pendingEvent; - socklen_t socklen = sizeof(int); - - recvEvent = WSACreateEvent (); - pgm_getsockopt (nak_sock, PGM_RECV_SOCK, &recv_sock, &socklen); - WSAEventSelect (recv_sock, recvEvent, FD_READ); - repairEvent = WSACreateEvent (); - pgm_getsockopt (nak_sock, PGM_REPAIR_SOCK, &repair_sock, &socklen); - WSAEventSelect (repair_sock, repairEvent, FD_READ); - pendingEvent = WSACreateEvent (); - pgm_getsockopt (nak_sock, PGM_PENDING_SOCK, &pending_sock, &socklen); - WSAEventSelect (pending_sock, pendingEvent, FD_READ); - - waitHandles[0] = terminate_event; - waitHandles[1] = recvEvent; - waitHandles[2] = repairEvent; - waitHandles[3] = pendingEvent; -#endif /* !_WIN32 */ - do { - struct timeval tv; - char buf[4064]; - pgm_error_t* pgm_err = NULL; - const int status = pgm_recv (nak_sock, buf, sizeof(buf), 0, NULL, &pgm_err); - switch (status) { - case PGM_IO_STATUS_TIMER_PENDING: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (sock, PGM_TIME_REMAIN, &tv, &optlen); - } - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (sock, PGM_RATE_REMAIN, &tv, &optlen); - } - case PGM_IO_STATUS_WOULD_BLOCK: -block: -#ifndef _WIN32 - fds = terminate_pipe[0] + 1; - FD_ZERO(&readfds); - FD_SET(terminate_pipe[0], &readfds); - pgm_select_info (nak_sock, &readfds, NULL, &fds); - fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); -#else - dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout); - switch (dwEvents) { - case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; - case WAIT_OBJECT_0+2: WSAResetEvent (repairEvent); break; - case WAIT_OBJECT_0+3: WSAResetEvent (pendingEvent); break; - default: break; - } -#endif /* !_WIN32 */ - break; - - default: - if (pgm_err) { - fprintf (stderr, "%s\n", pgm_err->message ? pgm_err->message : "(null)"); - pgm_error_free (pgm_err); - pgm_err = NULL; - } - if (PGM_IO_STATUS_ERROR == status) - break; - } - } while (!is_terminated); -#ifndef _WIN32 - return NULL; -#else - WSACloseEvent (recvEvent); - WSACloseEvent (repairEvent); - WSACloseEvent (pendingEvent); - _endthread(); - return 0; -#endif -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecv.c b/3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecv.c deleted file mode 100644 index 27625ce..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecv.c +++ /dev/null @@ -1,382 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Simple PGM receiver: epoll based non-blocking synchronous receiver. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef G_OS_UNIX -# include -# include -# include -# include -#endif -#include - -/* example dependencies */ -#include -#include - - -/* typedefs */ - -/* globals */ - -static int g_port = 0; -static const char* g_network = ""; -static gboolean g_multicast_loop = FALSE; -static int g_udp_encap_port = 0; - -static int g_max_tpdu = 1500; -static int g_sqns = 100; - -static pgm_sock_t* g_sock = NULL; -static gboolean g_quit = FALSE; - -static void on_signal (int); -static gboolean on_startup (void); - -static int on_data (gconstpointer, size_t, struct pgm_sockaddr_t*); - - -G_GNUC_NORETURN static -void -usage ( - const char* bin - ) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); - exit (1); -} - -int -main ( - int argc, - char* argv[] - ) -{ - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - - log_init (); - g_message ("enonblocksyncrecv"); - - if (!pgm_init (&pgm_err)) { - g_error ("Unable to start PGM engine: %s", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) - { - switch (c) { - case 'n': g_network = optarg; break; - case 's': g_port = atoi (optarg); break; - case 'p': g_udp_encap_port = atoi (optarg); break; - case 'l': g_multicast_loop = TRUE; break; - - case 'h': - case '?': usage (binary_name); - } - } - - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); - signal (SIGINT, on_signal); - signal (SIGTERM, on_signal); -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif - - if (!on_startup ()) { - g_error ("startup failed"); - return EXIT_FAILURE; - } - -/* epoll file descriptor */ - int efd = epoll_create (IP_MAX_MEMBERSHIPS); - if (efd < 0) { - g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); - return EXIT_FAILURE; - } - - int retval = pgm_epoll_ctl (g_sock, efd, EPOLL_CTL_ADD, EPOLLIN); - if (retval < 0) { - g_error ("pgm_epoll_ctl failed."); - return EXIT_FAILURE; - } - - struct epoll_event events[1]; /* wait for maximum 1 event */ - -/* dispatch loop */ - g_message ("entering PGM message loop ... "); - do { - struct timeval tv; - int timeout; - char buffer[4096]; - size_t len; - struct pgm_sockaddr_t from; - socklen_t fromlen = sizeof(from); - const int status = pgm_recvfrom (g_sock, - buffer, - sizeof(buffer), - 0, - &len, - &from, - &fromlen, - &pgm_err); - switch (status) { - case PGM_IO_STATUS_NORMAL: - on_data (buffer, len, &from); - break; - - case PGM_IO_STATUS_TIMER_PENDING: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_TIME_REMAIN, &tv, &optlen); - } - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_RATE_REMAIN, &tv, &optlen); - } -/* fall through */ - case PGM_IO_STATUS_WOULD_BLOCK: -/* poll for next event */ -block: - timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); - break; - - default: - if (pgm_err) { - g_warning ("%s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_err = NULL; - } - if (PGM_IO_STATUS_ERROR == status) - break; - } - } while (!g_quit); - - g_message ("message loop terminated, cleaning up."); - -/* cleanup */ - close (efd); - if (g_sock) { - g_message ("closing PGM socket."); - pgm_close (g_sock, TRUE); - g_sock = NULL; - } - - g_message ("PGM engine shutdown."); - pgm_shutdown (); - g_message ("finished."); - return EXIT_SUCCESS; -} - -static -void -on_signal ( - int signum - ) -{ - g_message ("on_signal (signum:%d)", signum); - g_quit = TRUE; -} - -static -gboolean -on_startup (void) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - - g_message ("startup."); - -/* parse network parameter into transport address structure */ - if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { - g_error ("parsing network parameter: %s", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - if (g_udp_encap_port) { - g_message ("create PGM/UDP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - } else { - g_message ("create PGM/IP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (g_sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int recv_only = 1, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (50), - nak_rpt_ivl = pgm_secs (2), - nak_rdata_ivl = pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50; - - pgm_setsockopt (g_sock, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - pgm_setsockopt (g_sock, PGM_PASSIVE, &passive, sizeof(passive)); - pgm_setsockopt (g_sock, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); - pgm_setsockopt (g_sock, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); - pgm_setsockopt (g_sock, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - pgm_setsockopt (g_sock, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - pgm_setsockopt (g_sock, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - pgm_setsockopt (g_sock, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - g_error ("creating GSI: %s", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (g_sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - g_error ("binding PGM socket: %s", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (g_sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (g_sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int nonblocking = 1, - multicast_loop = g_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (g_sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (g_sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (g_sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (g_sock, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); - - if (!pgm_connect (g_sock, &pgm_err)) { - g_error ("connecting PGM socket: %s", pgm_err->message); - goto err_abort; - } - - g_message ("startup complete."); - return TRUE; - -err_abort: - if (NULL != g_sock) { - pgm_close (g_sock, FALSE); - g_sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -static -int -on_data ( - gconstpointer data, - size_t len, - struct pgm_sockaddr_t* from - ) -{ -/* protect against non-null terminated strings */ - char buf[1024], tsi[PGM_TSISTRLEN]; - const size_t buflen = MIN(sizeof(buf) - 1, len); - strncpy (buf, (const char*)data, buflen); - buf[buflen] = '\0'; - pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); - - g_message ("\"%s\" (%u bytes from %s)", - buf, - (unsigned)len, - tsi); - - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecvmsg.c b/3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecvmsg.c deleted file mode 100644 index 9a0e9c6..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecvmsg.c +++ /dev/null @@ -1,382 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Simple PGM receiver: blocking synchronous receiver with scatter/gather io - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef G_OS_UNIX -# include -# include -# include -# include -#endif -#include - -/* example dependencies */ -#include -#include - - -/* typedefs */ - -/* globals */ - -static int g_port = 0; -static const char* g_network = ""; -static gboolean g_multicast_loop = FALSE; -static int g_udp_encap_port = 0; - -static int g_max_tpdu = 1500; -static int g_sqns = 100; - -static pgm_sock_t* g_sock = NULL; -static gboolean g_quit = FALSE; - -static void on_signal (int); -static gboolean on_startup (void); - -static int on_datav (struct pgm_msgv_t*, size_t); - - -G_GNUC_NORETURN static -void -usage ( - const char* bin - ) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); - exit (1); -} - -int -main ( - int argc, - char* argv[] - ) -{ - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - - log_init (); - g_message ("enonblocksyncrecvmsg"); - - if (!pgm_init (&pgm_err)) { - g_error ("Unable to start PGM engine: %s", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) - { - switch (c) { - case 'n': g_network = optarg; break; - case 's': g_port = atoi (optarg); break; - case 'p': g_udp_encap_port = atoi (optarg); break; - case 'l': g_multicast_loop = TRUE; break; - - case 'h': - case '?': usage (binary_name); - } - } - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); - signal (SIGINT, on_signal); - signal (SIGTERM, on_signal); -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif - - if (!on_startup ()) { - g_error ("startup failed"); - return EXIT_FAILURE; - } - -/* epoll file descriptor */ - int efd = epoll_create (IP_MAX_MEMBERSHIPS); - if (efd < 0) { - g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); - return EXIT_FAILURE; - } - - int retval = pgm_epoll_ctl (g_sock, efd, EPOLL_CTL_ADD, EPOLLIN); - if (retval < 0) { - g_error ("pgm_epoll_ctl failed."); - return EXIT_FAILURE; - } - -/* incoming message buffer */ - struct pgm_msgv_t msgv; - struct epoll_event events[1]; /* wait for maximum 1 event */ - -/* dispatch loop */ - g_message ("entering PGM message loop ... "); - do { - struct timeval tv; - int timeout; - size_t len; - const int status = pgm_recvmsg (g_sock, - &msgv, - 0, - &len, - &pgm_err); - switch (status) { - case PGM_IO_STATUS_NORMAL: - on_datav (&msgv, len); - break; - - case PGM_IO_STATUS_TIMER_PENDING: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_TIME_REMAIN, &tv, &optlen); - } - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_RATE_REMAIN, &tv, &optlen); - } -/* fall through */ - case PGM_IO_STATUS_WOULD_BLOCK: -/* poll for next event */ -block: - timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); - break; - - default: - if (pgm_err) { - g_warning ("%s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_err = NULL; - } - if (PGM_IO_STATUS_ERROR == status) - break; - } - } while (!g_quit); - - g_message ("message loop terminated, cleaning up."); - -/* cleanup */ - close (efd); - if (g_sock) { - g_message ("closing PGM socket."); - pgm_close (g_sock, TRUE); - g_sock = NULL; - } - - g_message ("PGM engine shutdown."); - pgm_shutdown (); - g_message ("finished."); - return EXIT_SUCCESS; -} - -static -void -on_signal ( - int signum - ) -{ - g_message ("on_signal (signum:%d)", signum); - g_quit = TRUE; -} - -static -gboolean -on_startup (void) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - - g_message ("startup."); - -/* parse network parameter into transport address structure */ - if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { - g_error ("parsing network parameter: %s", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - if (g_udp_encap_port) { - g_message ("create PGM/UDP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - } else { - g_message ("create PGM/IP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (g_sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int recv_only = 1, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (50), - nak_rpt_ivl = pgm_secs (2), - nak_rdata_ivl = pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50; - - pgm_setsockopt (g_sock, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - pgm_setsockopt (g_sock, PGM_PASSIVE, &passive, sizeof(passive)); - pgm_setsockopt (g_sock, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); - pgm_setsockopt (g_sock, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); - pgm_setsockopt (g_sock, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - pgm_setsockopt (g_sock, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - pgm_setsockopt (g_sock, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - pgm_setsockopt (g_sock, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - g_error ("creating GSI: %s", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (g_sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - g_error ("binding PGM socket: %s", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (g_sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (g_sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int nonblocking = 1, - multicast_loop = g_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (g_sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (g_sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (g_sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (g_sock, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); - - if (!pgm_connect (g_sock, &pgm_err)) { - g_error ("connecting PGM socket: %s", pgm_err->message); - goto err_abort; - } - - g_message ("startup complete."); - return TRUE; - -err_abort: - if (NULL != g_sock) { - pgm_close (g_sock, FALSE); - g_sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -static -int -on_datav ( - struct pgm_msgv_t* datav, /* one msgv object */ - size_t len - ) -{ - char tsi[PGM_TSISTRLEN]; - pgm_tsi_print_r (&datav->msgv_skb[0]->tsi, tsi, sizeof(tsi)); - g_message ("(%u bytes from %s)", (unsigned)len, tsi); - -/* protect against non-null terminated strings */ - const struct pgm_sk_buff_t* skb = datav->msgv_skb[0]; - int i = 0; - while (len) - { - char buf[1024]; - const size_t buflen = MIN( sizeof(buf) - 1, skb->len ); - strncpy (buf, (const char*)skb->data, buflen); - buf[buflen] = '\0'; - g_message ("\t%i: %s (%" G_GUINT16_FORMAT " bytes)", ++i, buf, skb->len); - len -= skb->len; - skb++; - } - - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecvmsgv.c b/3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecvmsgv.c deleted file mode 100644 index 0a04056..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/enonblocksyncrecvmsgv.c +++ /dev/null @@ -1,397 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Simple PGM receiver: epoll based non-blocking synchronous receiver with scatter/gather io - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef G_OS_UNIX -# include -# include -# include -# include -# include -#endif -#include - -/* example dependencies */ -#include -#include - - -/* typedefs */ - -/* globals */ - -static int g_port = 0; -static const char* g_network = ""; -static gboolean g_multicast_loop = FALSE; -static int g_udp_encap_port = 0; - -static int g_max_tpdu = 1500; -static int g_sqns = 100; - -static pgm_sock_t* g_sock = NULL; -static gboolean g_quit = FALSE; - -static void on_signal (int); -static gboolean on_startup (void); - -static int on_msgv (struct pgm_msgv_t*, size_t); - - -G_GNUC_NORETURN static -void -usage ( - const char* bin - ) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); - exit (1); -} - -int -main ( - int argc, - char* argv[] - ) -{ - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - - log_init (); - g_message ("enonblocksyncrecvmsgv"); - - if (!pgm_init (&pgm_err)) { - g_error ("Unable to start PGM engine: %s", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) - { - switch (c) { - case 'n': g_network = optarg; break; - case 's': g_port = atoi (optarg); break; - case 'p': g_udp_encap_port = atoi (optarg); break; - case 'l': g_multicast_loop = TRUE; break; - - case 'h': - case '?': usage (binary_name); - } - } - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); - signal (SIGINT, on_signal); - signal (SIGTERM, on_signal); -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif - - if (!on_startup ()) { - g_error ("startup failed"); - return EXIT_FAILURE; - } - -/* incoming message buffer, iov_len must be less than SC_IOV_MAX */ - const long iov_len = 8; - const long ev_len = 1; - g_message ("Using iov_len %li ev_len %li", iov_len, ev_len); - - struct pgm_msgv_t msgv[iov_len]; - struct epoll_event events[ev_len]; /* wait for maximum 1 event */ - -/* epoll file descriptor */ - const int efd = epoll_create (IP_MAX_MEMBERSHIPS); - if (efd < 0) { - g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); - return EXIT_FAILURE; - } - - const int retval = pgm_epoll_ctl (g_sock, efd, EPOLL_CTL_ADD, EPOLLIN); - if (retval < 0) { - g_error ("pgm_epoll_ctl failed."); - return EXIT_FAILURE; - } - -/* dispatch loop */ - g_message ("entering PGM message loop ... "); - do { - struct timeval tv; - int timeout; - size_t len; - const int status = pgm_recvmsgv (g_sock, - msgv, - iov_len, - 0, - &len, - &pgm_err); - switch (status) { - case PGM_IO_STATUS_NORMAL: - on_msgv (msgv, len); - break; - - case PGM_IO_STATUS_TIMER_PENDING: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_TIME_REMAIN, &tv, &optlen); - } - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_RATE_REMAIN, &tv, &optlen); - } -/* fall through */ - case PGM_IO_STATUS_WOULD_BLOCK: -/* poll for next event */ -block: - timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); - break; - - default: - if (pgm_err) { - g_warning ("%s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_err = NULL; - } - if (PGM_IO_STATUS_ERROR == status) - break; - } - } while (!g_quit); - - g_message ("message loop terminated, cleaning up."); - -/* cleanup */ - close (efd); - if (g_sock) { - g_message ("closing PGM socket."); - pgm_close (g_sock, TRUE); - g_sock = NULL; - } - - g_message ("PGM engine shutdown."); - pgm_shutdown (); - g_message ("finished."); - return EXIT_SUCCESS; -} - -static -void -on_signal ( - int signum - ) -{ - g_message ("on_signal (signum:%d)", signum); - g_quit = TRUE; -} - -static -gboolean -on_startup (void) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - - g_message ("startup."); - -/* parse network parameter into transport address structure */ - if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { - g_error ("parsing network parameter: %s", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - if (g_udp_encap_port) { - g_message ("create PGM/UDP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - } else { - g_message ("create PGM/IP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (g_sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int recv_only = 1, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (50), - nak_rpt_ivl = pgm_secs (2), - nak_rdata_ivl = pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50; - - pgm_setsockopt (g_sock, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - pgm_setsockopt (g_sock, PGM_PASSIVE, &passive, sizeof(passive)); - pgm_setsockopt (g_sock, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); - pgm_setsockopt (g_sock, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); - pgm_setsockopt (g_sock, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - pgm_setsockopt (g_sock, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - pgm_setsockopt (g_sock, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - pgm_setsockopt (g_sock, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - g_error ("creating GSI: %s", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (g_sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - g_error ("binding PGM socket: %s", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (g_sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (g_sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int nonblocking = 1, - multicast_loop = g_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (g_sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (g_sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (g_sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (g_sock, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); - - if (!pgm_connect (g_sock, &pgm_err)) { - g_error ("connecting PGM socket: %s", pgm_err->message); - goto err_abort; - } - - g_message ("startup complete."); - return TRUE; - -err_abort: - if (NULL != g_sock) { - pgm_close (g_sock, FALSE); - g_sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -static -int -on_msgv ( - struct pgm_msgv_t* msgv, /* an array of msgv's */ - size_t len /* total size of all msgv's */ - ) -{ - g_message ("(%u bytes)", - (unsigned)len); - - guint i = 0; - -/* for each apdu display each fragment */ - do { - const struct pgm_sk_buff_t* pskb = msgv[i].msgv_skb[0]; - gsize apdu_len = 0; - for (unsigned j = 0; j < msgv[i].msgv_len; j++) - apdu_len += msgv[i].msgv_skb[j]->len; -/* truncate to first fragment to make GLib printing happy */ - char buf[1024], tsi[PGM_TSISTRLEN]; - const size_t buflen = MIN( sizeof(buf) - 1, pskb->len ); - strncpy (buf, (const char*)pskb->data, buflen); - buf[buflen] = '\0'; - pgm_tsi_print_r (&pskb->tsi, tsi, sizeof(tsi)); - if (msgv[i].msgv_len > 1) { - g_message ("\t%u: \"%s\" ... (%" G_GSIZE_FORMAT " bytes from %s)", i, buf, apdu_len, tsi); - } else { - g_message ("\t%u: \"%s\" (%" G_GSIZE_FORMAT " bytes from %s)", i, buf, apdu_len, tsi); - } - i++; - len -= apdu_len; - } while (len); - - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/getopt.c b/3rdparty/openpgm-svn-r1085/pgm/examples/getopt.c deleted file mode 100644 index 8c655b6..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/getopt.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 1987, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include "getopt.h" - -int opterr = 1, /* if error message should be printed */ - optind = 1, /* index into parent argv vector */ - optopt, /* character checked for validity */ - optreset; /* reset getopt */ -char *optarg; /* argument associated with option */ - -#define BADCH (int)'?' -#define BADARG (int)':' -#define EMSG "" - -/* - * getopt -- - * Parse argc/argv argument vector. - */ -int -getopt(int nargc, char* const* nargv, const char* ostr) -{ - static char *place = EMSG; /* option letter processing */ - char *oli; /* option letter list index */ - - if (optreset || !*place) { /* update scanning pointer */ - optreset = 0; - if (optind >= nargc || *(place = nargv[optind]) != '-') { - place = EMSG; - return (-1); - } - if (place[1] && *++place == '-') { /* found "--" */ - ++optind; - place = EMSG; - return (-1); - } - } /* option letter okay? */ - if ((optopt = (int)*place++) == (int)':' || - !(oli = strchr(ostr, optopt))) { - /* - * if the user didn't specify '-' as an option, - * assume it means -1. - */ - if (optopt == (int)'-') - return (-1); - if (!*place) - ++optind; - if (opterr && *ostr != ':' && optopt != BADCH) - (void)fprintf(stderr, "%s: illegal option -- %c\n", - "progname", optopt); - return (BADCH); - } - if (*++oli != ':') { /* don't need argument */ - optarg = NULL; - if (!*place) - ++optind; - } - else { /* need an argument */ - if (*place) /* no white space */ - optarg = place; - else if (nargc <= ++optind) { /* no arg */ - place = EMSG; - if (*ostr == ':') - return (BADARG); - if (opterr) - (void)fprintf(stderr, - "%s: option requires an argument -- %c\n", - "progname", optopt); - return (BADCH); - } - else /* white space */ - optarg = nargv[optind]; - place = EMSG; - ++optind; - } - return (optopt); /* dump back option letter */ -} - diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/getopt.h b/3rdparty/openpgm-svn-r1085/pgm/examples/getopt.h deleted file mode 100644 index f04387b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/getopt.h +++ /dev/null @@ -1,62 +0,0 @@ -/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ -/* $FreeBSD: src/include/getopt.h,v 1.1 2002/09/29 04:14:30 eric Exp $ */ - -/*- - * Copyright (c) 2000 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Dieter Baron and Thomas Klausner. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _GETOPT_H_ -#define _GETOPT_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* These are global getopt variables */ -extern int opterr, /* if error message should be printed */ - optind, /* index into parent argv vector */ - optopt, /* character checked for validity */ - optreset; /* reset getopt */ -extern char* optarg; /* argument associated with option */ - -/* Original getopt */ -int getopt (int, char*const*, const char*); - -#ifdef __cplusplus -} -#endif - -#endif /* !_GETOPT_H_ */ - diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/pgmdump.c b/3rdparty/openpgm-svn-r1085/pgm/examples/pgmdump.c deleted file mode 100644 index b91b804..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/pgmdump.c +++ /dev/null @@ -1,279 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Dump PGM packets to the console. - * - * Copyright (c) 2006-2007 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef G_OS_UNIX -# include -# include -# include -# include -#endif - -#include - -/* PGM internals */ -#include - -/* example dependencies */ -#include -#include - - -/* globals */ - -static const char* g_network = "239.192.0.1"; - -static GIOChannel* g_io_channel = NULL; -static GMainLoop* g_loop = NULL; - - -static void on_signal (int); -static gboolean on_startup (gpointer); -static gboolean on_mark (gpointer); - -static gboolean on_io_data (GIOChannel*, GIOCondition, gpointer); - - -int -main ( - G_GNUC_UNUSED int argc, - G_GNUC_UNUSED char *argv[] - ) -{ - GError* err = NULL; - - setlocale (LC_ALL, ""); - - log_init (); - g_message ("pgmdump"); - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); - signal (SIGINT, on_signal); - signal (SIGTERM, on_signal); -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif - -/* delayed startup */ - g_message ("scheduling startup."); - g_timeout_add (0, (GSourceFunc)on_startup, NULL); - -/* dispatch loop */ - g_loop = g_main_loop_new (NULL, FALSE); - - g_message ("entering main event loop ... "); - g_main_loop_run (g_loop); - - g_message ("event loop terminated, cleaning up."); - -/* cleanup */ - g_main_loop_unref (g_loop); - g_loop = NULL; - - if (g_io_channel) { - g_message ("closing socket."); - g_io_channel_shutdown (g_io_channel, FALSE, &err); - g_io_channel = NULL; - } - - g_message ("finished."); - return EXIT_SUCCESS; -} - -static void -on_signal ( - G_GNUC_UNUSED int signum - ) -{ - puts ("on_signal"); - - g_main_loop_quit(g_loop); -} - -static -gboolean -on_startup ( - G_GNUC_UNUSED gpointer data - ) -{ - int e; - - g_message ("startup."); - -/* find PGM protocol id */ -// TODO: fix valgrind errors - int ipproto_pgm = IPPROTO_PGM; -#if HAVE_GETPROTOBYNAME_R - char b[1024]; - struct protoent protobuf, *proto; - e = getprotobyname_r ("pgm", &protobuf, b, sizeof(b), &proto); - if (e != -1 && proto != NULL) { - if (proto->p_proto != ipproto_pgm) { - g_message ("Setting PGM protocol number to %i from /etc/protocols.\n"); - ipproto_pgm = proto->p_proto; - } - } -#else - struct protoent *proto = getprotobyname ("pgm"); - if (proto != NULL) { - if (proto->p_proto != ipproto_pgm) { - g_message ("Setting PGM protocol number to %i from /etc/protocols.\n", proto -->p_proto); - ipproto_pgm = proto->p_proto; - } - } -#endif - -/* open socket for snooping */ - g_message ("opening raw socket."); - int sock = socket (PF_INET, SOCK_RAW, ipproto_pgm); - if (sock < 0) { - perror("on_startup() failed"); -#ifdef G_OS_UNIX - if (EPERM == errno && 0 != getuid()) { - g_message ("PGM protocol requires this program to run as superuser."); - } -#endif - g_main_loop_quit (g_loop); - return FALSE; - } - -#ifdef G_OS_UNIX -/* drop out of setuid 0 */ - if (0 == getuid ()) { - g_message ("dropping superuser privileges."); - setuid ((gid_t)65534); - setgid ((uid_t)65534); - } -#endif - - char _t = 1; - e = setsockopt (sock, IPPROTO_IP, IP_HDRINCL, &_t, sizeof(_t)); - if (e < 0) { - perror ("on_startup() failed"); - close (sock); - g_main_loop_quit (g_loop); - return FALSE; - } - -/* buffers */ - int buffer_size = 0; - socklen_t len = 0; - e = getsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char*)&buffer_size, &len); - if (e == 0) { - g_message ("receive buffer set at %i bytes.\n", buffer_size); - } - e = getsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char*)&buffer_size, &len); - if (e == 0) { - g_message ("send buffer set at %i bytes.\n", buffer_size); - } - -/* bind */ - struct sockaddr_in addr; - memset (&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - e = bind (sock, (struct sockaddr*)&addr, sizeof(addr)); - if (e < 0) { - perror ("on_startup() failed"); - close (sock); - g_main_loop_quit (g_loop); - return FALSE; - } - -/* multicast */ - struct ip_mreq mreq; - memset (&mreq, 0, sizeof(mreq)); - mreq.imr_interface.s_addr = htonl (INADDR_ANY); - g_message ("listening on interface %s.\n", inet_ntoa (mreq.imr_interface)); - mreq.imr_multiaddr.s_addr = inet_addr (g_network); - g_message ("subscription on multicast address %s.\n", inet_ntoa (mreq.imr_multiaddr)); - e = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)); - if (e < 0) { - perror ("on_startup() failed"); - close (sock); - g_main_loop_quit (g_loop); - return FALSE; - } - -/* multicast loopback */ -/* multicast ttl */ - -/* add socket to event manager */ - g_io_channel = g_io_channel_unix_new (sock); - g_message ("socket opened with encoding %s.\n", g_io_channel_get_encoding (g_io_channel)); - - /* guint event = */ g_io_add_watch (g_io_channel, G_IO_IN | G_IO_PRI, on_io_data, NULL); - -/* period timer to indicate some form of life */ -// TODO: Gnome 2.14: replace with g_timeout_add_seconds() - g_timeout_add (10 * 1000, (GSourceFunc)on_mark, NULL); - - g_message ("startup complete."); - return FALSE; -} - -static gboolean -on_mark ( - G_GNUC_UNUSED gpointer data - ) -{ - g_message ("-- MARK --"); - return TRUE; -} - -static gboolean -on_io_data ( - GIOChannel* source, - G_GNUC_UNUSED GIOCondition condition, - G_GNUC_UNUSED gpointer data - ) -{ - char buffer[4096]; - - int fd = g_io_channel_unix_get_fd (source); - struct sockaddr_in addr; - socklen_t addr_len = sizeof(addr); - int len = recvfrom (fd, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len); - - g_message ("%i bytes received from %s.\n", len, inet_ntoa (addr.sin_addr)); - - if (!pgm_print_packet (buffer, len)) { - g_message ("invalid packet :("); - } - - fflush (stdout); - - return TRUE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/pgmping.cc b/3rdparty/openpgm-svn-r1085/pgm/examples/pgmping.cc deleted file mode 100644 index 38ac560..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/pgmping.cc +++ /dev/null @@ -1,1059 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Simple send/reply ping tool using the PGM transport. - * - * With no arguments, one message is sent per second. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* c99 compatibility for c++ */ -#define __STDC_LIMIT_MACROS - -/* Must be first for Sun */ -#include "ping.pb.h" - -/* c99 compatibility for c++ */ -#define __STDC_FORMAT_MACROS -#define restrict - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#ifdef CONFIG_HAVE_EPOLL -# include -#endif -#include -#ifndef _WIN32 -# include -# include -# include -# include -# include -#endif -#include -#include -#ifdef CONFIG_WITH_HTTP -# include -#endif -#ifdef CONFIG_WITH_SNMP -# include -#endif - -/* PGM internal time keeper */ -typedef pgm_time_t (*pgm_time_update_func)(void); -extern pgm_time_update_func pgm_time_update_now; -extern "C" { - size_t pgm_pkt_offset (bool, sa_family_t); -} - -/* example dependencies */ -#include -#include -#include - - -using namespace std; - - -/* globals */ - -static int g_port = 0; -static const char* g_network = ""; -static int g_udp_encap_port = 0; - -static int g_odata_rate = 0; -static int g_odata_interval = 0; -static guint32 g_payload = 0; -static int g_max_tpdu = 1500; -static int g_max_rte = 16*1000*1000; -static int g_sqns = 200; - -static gboolean g_use_pgmcc = FALSE; -static sa_family_t g_pgmcc_family = 0; /* 0 = disabled */ - -static gboolean g_use_fec = FALSE; -static int g_rs_k = 8; -static int g_rs_n = 255; - -static enum { - PGMPING_MODE_SOURCE, - PGMPING_MODE_RECEIVER, - PGMPING_MODE_INITIATOR, - PGMPING_MODE_REFLECTOR -} g_mode = PGMPING_MODE_INITIATOR; - -static pgm_sock_t* g_sock = NULL; - -/* stats */ -static guint64 g_msg_sent = 0; -static guint64 g_msg_received = 0; -static pgm_time_t g_interval_start = 0; -static pgm_time_t g_latency_current = 0; -static guint64 g_latency_seqno = 0; -static guint64 g_last_seqno = 0; -static double g_latency_total = 0.0; -static double g_latency_square_total = 0.0; -static guint64 g_latency_count = 0; -static double g_latency_max = 0.0; -#ifdef INFINITY -static double g_latency_min = INFINITY; -#else -static double g_latency_min = INT64_MAX; -#endif -static double g_latency_running_average = 0.0; -static guint64 g_out_total = 0; -static guint64 g_in_total = 0; - -static GMainLoop* g_loop = NULL; -static GThread* g_sender_thread = NULL; -static GThread* g_receiver_thread = NULL; -static gboolean g_quit; -#ifdef G_OS_UNIX -static int g_quit_pipe[2]; -static void on_signal (int, gpointer); -#else -static HANDLE g_quit_event; -static BOOL on_console_ctrl (DWORD); -#endif - -static gboolean on_startup (gpointer); -static gboolean on_shutdown (gpointer); -static gboolean on_mark (gpointer); - -static void send_odata (void); -static int on_msgv (struct pgm_msgv_t*, size_t); - -static gpointer sender_thread (gpointer); -static gpointer receiver_thread (gpointer); - - -G_GNUC_NORETURN static void -usage (const char* bin) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -d : Terminate transport after duration.\n"); - fprintf (stderr, " -m : Number of message to send per second\n"); - fprintf (stderr, " -o : Send-only mode (default send & receive mode)\n"); - fprintf (stderr, " -l : Listen-only mode\n"); - fprintf (stderr, " -e : Relect mode\n"); - fprintf (stderr, " -r : Regulate to rate bytes per second\n"); - fprintf (stderr, " -c : Enable PGMCC\n"); - fprintf (stderr, " -f : Enable FEC with either proactive or ondemand parity\n"); - fprintf (stderr, " -K : Configure Reed-Solomon code (n, k)\n"); - fprintf (stderr, " -N \n"); - fprintf (stderr, " -H : Enable HTTP administrative interface\n"); - fprintf (stderr, " -S : Enable SNMP interface\n"); - exit (1); -} - -int -main ( - int argc, - char *argv[] - ) -{ - GError* err = NULL; - pgm_error_t* pgm_err = NULL; - gboolean enable_http = FALSE; - gboolean enable_snmpx = FALSE; - int timeout = 0; - - GOOGLE_PROTOBUF_VERIFY_VERSION; - - setlocale (LC_ALL, ""); - setenv ("PGM_TIMER", "GTOD", 1); - setenv ("PGM_SLEEP", "USLEEP", 1); - - log_init (); - g_message ("pgmping"); - - g_thread_init (NULL); - - if (!pgm_init (&pgm_err)) { - g_error ("Unable to start PGM engine: %s", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = g_get_prgname(); - int c; - while ((c = getopt (argc, argv, "s:n:p:m:old:r:cfeK:N:HSh")) != -1) - { - switch (c) { - case 'n': g_network = optarg; break; - case 's': g_port = atoi (optarg); break; - case 'p': g_udp_encap_port = atoi (optarg); break; - case 'r': g_max_rte = atoi (optarg); break; - - case 'c': g_use_pgmcc = TRUE; break; - - case 'f': g_use_fec = TRUE; break; - case 'K': g_rs_k = atoi (optarg); break; - case 'N': g_rs_n = atoi (optarg); break; - - case 'H': enable_http = TRUE; break; - case 'S': enable_snmpx = TRUE; break; - - case 'm': g_odata_rate = atoi (optarg); - g_odata_interval = (1000 * 1000) / g_odata_rate; break; - case 'd': timeout = 1000 * atoi (optarg); break; - - case 'o': g_mode = PGMPING_MODE_SOURCE; break; - case 'l': g_mode = PGMPING_MODE_RECEIVER; break; - case 'e': g_mode = PGMPING_MODE_REFLECTOR; break; - - case 'h': - case '?': usage (binary_name); - } - } - - if (g_use_fec && ( !g_rs_k || !g_rs_n )) { - g_error ("Invalid Reed-Solomon parameters."); - usage (binary_name); - } - -#ifdef CONFIG_WITH_HTTP - if (enable_http) { - if (!pgm_http_init (PGM_HTTP_DEFAULT_SERVER_PORT, &pgm_err)) { - g_error ("Unable to start HTTP interface: %s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_shutdown (); - return EXIT_FAILURE; - } - } -#endif -#ifdef CONFIG_WITH_SNMP - if (enable_snmpx) { - if (!pgm_snmp_init (&pgm_err)) { - g_error ("Unable to start SNMP interface: %s", pgm_err->message); - pgm_error_free (pgm_err); -#ifdef CONFIG_WITH_HTTP - if (enable_http) - pgm_http_shutdown (); -#endif - pgm_shutdown (); - return EXIT_FAILURE; - } - } -#endif - - g_loop = g_main_loop_new (NULL, FALSE); - - g_quit = FALSE; - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif -#ifdef G_OS_UNIX - pipe (g_quit_pipe); - pgm_signal_install (SIGINT, on_signal, g_loop); - pgm_signal_install (SIGTERM, on_signal, g_loop); -#else - g_quit_event = CreateEvent (NULL, TRUE, FALSE, TEXT("QuitEvent")); - SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); -#endif /* !G_OS_UNIX */ - -/* delayed startup */ - g_message ("scheduling startup."); - g_timeout_add (0, (GSourceFunc)on_startup, g_loop); - - if (timeout) { - g_message ("scheduling shutdown."); - g_timeout_add (timeout, (GSourceFunc)on_shutdown, g_loop); - } - -/* dispatch loop */ - g_message ("entering main event loop ... "); - g_main_loop_run (g_loop); - - g_message ("event loop terminated, cleaning up."); - -/* cleanup */ - g_quit = TRUE; -#ifdef G_OS_UNIX - const char one = '1'; - write (g_quit_pipe[1], &one, sizeof(one)); - if (PGMPING_MODE_SOURCE == g_mode || PGMPING_MODE_INITIATOR == g_mode) - g_thread_join (g_sender_thread); - g_thread_join (g_receiver_thread); - close (g_quit_pipe[0]); - close (g_quit_pipe[1]); -#else - SetEvent (g_quit_event); - if (PGMPING_MODE_SOURCE == g_mode || PGMPING_MODE_INITIATOR == g_mode) - g_thread_join (g_sender_thread); - g_thread_join (g_receiver_thread); - CloseHandle (g_quit_event); -#endif - - g_main_loop_unref (g_loop); - g_loop = NULL; - - if (g_sock) { - g_message ("closing PGM socket."); - pgm_close (g_sock, TRUE); - g_sock = NULL; - } - -#ifdef CONFIG_WITH_HTTP - if (enable_http) - pgm_http_shutdown(); -#endif -#ifdef CONFIG_WITH_SNMP - if (enable_snmpx) - pgm_snmp_shutdown(); -#endif - - google::protobuf::ShutdownProtobufLibrary(); - - g_message ("PGM engine shutdown."); - pgm_shutdown (); - g_message ("finished."); - return EXIT_SUCCESS; -} - -#ifdef G_OS_UNIX -static -void -on_signal ( - int signum, - gpointer user_data - ) -{ - GMainLoop* loop = (GMainLoop*)user_data; - g_message ("on_signal (signum:%d user-data:%p)", - signum, user_data); - g_main_loop_quit (loop); -} -#else -static -BOOL -on_console_ctrl ( - DWORD dwCtrlType - ) -{ - g_message ("on_console_ctrl (dwCtrlType:%lu)", (unsigned long)dwCtrlType); - g_main_loop_quit (g_loop); - return TRUE; -} -#endif /* !G_OS_UNIX */ - -static -gboolean -on_shutdown ( - gpointer user_data - ) -{ - GMainLoop* loop = (GMainLoop*)user_data; - g_message ("on_shutdown (user-data:%p)", user_data); - g_main_loop_quit (loop); - return FALSE; -} - -static -gboolean -on_startup ( - gpointer user_data - ) -{ - GMainLoop* loop = (GMainLoop*)user_data; - struct pgm_addrinfo_t* res = NULL; - GError* err = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - - g_message ("startup."); - -/* parse network parameter into transport address structure */ - if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { - g_error ("parsing network parameter: %s", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - if (g_use_pgmcc) - g_pgmcc_family = sa_family; - - if (g_udp_encap_port) { - g_message ("create PGM/UDP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - } else { - g_message ("create PGM/IP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - { - const int no_router_assist = 0; - pgm_setsockopt (g_sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - } - - pgm_drop_superuser(); - -/* set PGM parameters */ - if (PGMPING_MODE_SOURCE == g_mode || - PGMPING_MODE_INITIATOR == g_mode || - PGMPING_MODE_REFLECTOR == g_mode) - { - const int send_only = PGMPING_MODE_SOURCE == g_mode ? 1 : 0, - ambient_spm = pgm_secs (30), - heartbeat_spm[] = { pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (1300), - pgm_secs (7), - pgm_secs (16), - pgm_secs (25), - pgm_secs (30) }; - - pgm_setsockopt (g_sock, PGM_SEND_ONLY, &send_only, sizeof(send_only)); - pgm_setsockopt (g_sock, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); - pgm_setsockopt (g_sock, PGM_TXW_SQNS, &g_sqns, sizeof(g_sqns)); - pgm_setsockopt (g_sock, PGM_TXW_MAX_RTE, &g_max_rte, sizeof(g_max_rte)); - pgm_setsockopt (g_sock, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm)); - pgm_setsockopt (g_sock, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm)); - } - if (PGMPING_MODE_RECEIVER == g_mode || - PGMPING_MODE_INITIATOR == g_mode || - PGMPING_MODE_REFLECTOR == g_mode) - { - const int recv_only = PGMPING_MODE_RECEIVER == g_mode ? 1 : 0, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (50), - nak_rpt_ivl = pgm_msecs (200), //pgm_secs (2), - nak_rdata_ivl = pgm_msecs (200), //pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50; - - pgm_setsockopt (g_sock, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - pgm_setsockopt (g_sock, PGM_PASSIVE, &passive, sizeof(passive)); - pgm_setsockopt (g_sock, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); - pgm_setsockopt (g_sock, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); - pgm_setsockopt (g_sock, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - pgm_setsockopt (g_sock, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - pgm_setsockopt (g_sock, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - pgm_setsockopt (g_sock, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - } - -#ifdef I_UNDERSTAND_PGMCC_AND_FEC_ARE_NOT_SUPPORTED -/* PGMCC congestion control */ - if (g_use_pgmcc) { - struct pgm_pgmccinfo_t pgmccinfo; - pgmccinfo.ack_bo_ivl = pgm_msecs (50); - pgmccinfo.ack_c = 75; - pgmccinfo.ack_c_p = 500; - pgm_setsockopt (g_sock, PGM_USE_PGMCC, &pgmccinfo, sizeof(pgmccinfo)); - } - -/* Reed Solomon forward error correction */ - if (g_use_fec) { - struct pgm_fecinfo_t fecinfo; - fecinfo.block_size = g_rs_n; - fecinfo.proactive_packets = 0; - fecinfo.group_size = g_rs_k; - fecinfo.ondemand_parity_enabled = TRUE; - fecinfo.var_pktlen_enabled = TRUE; - pgm_setsockopt (g_sock, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); - } -#endif - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - g_error ("creating GSI: %s", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (g_sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - g_error ("binding PGM socket: %s", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (g_sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (g_sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - { - const int nonblocking = 1, - multicast_loop = 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (g_sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (g_sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (g_sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (g_sock, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); - } - - if (!pgm_connect (g_sock, &pgm_err)) { - g_error ("connecting PGM socket: %s", pgm_err->message); - goto err_abort; - } - -/* period timer to indicate some form of life */ -// TODO: Gnome 2.14: replace with g_timeout_add_seconds() - g_timeout_add (2 * 1000, (GSourceFunc)on_mark, NULL); - - if (PGMPING_MODE_SOURCE == g_mode || PGMPING_MODE_INITIATOR == g_mode) - { - g_sender_thread = g_thread_create_full (sender_thread, - g_sock, - 0, - TRUE, - TRUE, - G_THREAD_PRIORITY_NORMAL, - &err); - if (!g_sender_thread) { - g_critical ("g_thread_create_full failed errno %i: \"%s\"", err->code, err->message); - goto err_abort; - } - } - - { - g_receiver_thread = g_thread_create_full (receiver_thread, - g_sock, - 0, - TRUE, - TRUE, - G_THREAD_PRIORITY_HIGH, - &err); - if (!g_receiver_thread) { - g_critical ("g_thread_create_full failed errno %i: \"%s\"", err->code, err->message); - goto err_abort; - } - } - - g_message ("startup complete."); - return FALSE; - -err_abort: - if (NULL != g_sock) { - pgm_close (g_sock, FALSE); - g_sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -static -gpointer -sender_thread ( - gpointer user_data - ) -{ - pgm_sock_t* tx_sock = (pgm_sock_t*)user_data; - example::Ping ping; - string subject("PING.PGM.TEST."); - char hostname[NI_MAXHOST + 1]; - const long payload_len = 1000; - char payload[payload_len]; - gpointer buffer = NULL; - guint64 latency, now, last; - -#ifdef CONFIG_HAVE_EPOLL - const long ev_len = 1; - struct epoll_event events[ev_len]; - - int efd_again = epoll_create (IP_MAX_MEMBERSHIPS); - if (efd_again < 0) { - g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); - g_main_loop_quit (g_loop); - return NULL; - } -/* Add write event to epoll domain in order to re-enable as required by return - * value. We use one-shot flag to disable ASAP, as we don't want such events - * until triggered. - */ - if (pgm_epoll_ctl (tx_sock, efd_again, EPOLL_CTL_ADD, EPOLLOUT | EPOLLONESHOT) < 0) { - g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); - g_main_loop_quit (g_loop); - return NULL; - } - struct epoll_event event; - memset (&event, 0, sizeof(event)); - event.events = EPOLLIN; - event.data.fd = g_quit_pipe[0]; - if (epoll_ctl (efd_again, EPOLL_CTL_ADD, g_quit_pipe[0], &event) < 0) { - g_error ("epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); - g_main_loop_quit (g_loop); - return NULL; - } -#elif defined(CONFIG_HAVE_POLL) - int n_fds = 2; - struct pollfd fds[ 2 + 1 ]; -#endif /* !CONFIG_HAVE_EPOLL */ - - gethostname (hostname, sizeof(hostname)); - subject.append(hostname); - memset (payload, 0, sizeof(payload)); - - ping.mutable_subscription_header()->set_subject (subject); - ping.mutable_market_data_header()->set_msg_type (example::MarketDataHeader::MSG_VERIFY); - ping.mutable_market_data_header()->set_rec_type (example::MarketDataHeader::PING); - ping.mutable_market_data_header()->set_rec_status (example::MarketDataHeader::STATUS_OK); - ping.set_time (last); - - last = now = pgm_time_update_now(); - do { - if (g_msg_sent && g_latency_seqno + 1 == g_msg_sent) - latency = g_latency_current; - else - latency = g_odata_interval; - - ping.set_seqno (g_msg_sent); - ping.set_latency (latency); - ping.set_payload (payload, sizeof(payload)); - - const size_t header_size = pgm_pkt_offset (FALSE, g_pgmcc_family); - const size_t apdu_size = ping.ByteSize(); - struct pgm_sk_buff_t* skb = pgm_alloc_skb (g_max_tpdu); - pgm_skb_reserve (skb, header_size); - pgm_skb_put (skb, apdu_size); - -/* wait on packet rate limit */ - if ((last + g_odata_interval) > now) { -#ifndef _WIN32 - const unsigned int usec = g_odata_interval - (now - last); - usleep (usec); -#else - const DWORD msec = usecs_to_msecs (g_odata_interval - (now - last)); - Sleep (msec); -#endif - now = pgm_time_update_now(); - } - last += g_odata_interval; - ping.set_time (now); - ping.SerializeToArray (skb->data, skb->len); - - struct timeval tv; - int timeout; - size_t bytes_written; - int status; -again: - status = pgm_send_skbv (tx_sock, &skb, 1, TRUE, &bytes_written); - switch (status) { -/* rate control */ - case PGM_IO_STATUS_RATE_LIMITED: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (tx_sock, PGM_RATE_REMAIN, &tv, &optlen); - timeout = (tv.tv_sec * 1000) + ((tv.tv_usec + 500) / 1000); -/* busy wait under 2ms */ - if (timeout < 2) timeout = 0; -#ifdef CONFIG_HAVE_EPOLL - const int ready = epoll_wait (efd_again, events, G_N_ELEMENTS(events), timeout /* ms */); -#elif defined(CONFIG_HAVE_POLL) - memset (fds, 0, sizeof(fds)); - fds[0].fd = g_quit_pipe[0]; - fds[0].events = POLLIN; - pgm_poll_info (tx_sock, &fds[1], &n_fds, POLLIN); - poll (fds, 1 + n_fds, timeout /* ms */); -#endif /* !CONFIG_HAVE_EPOLL */ - if (G_UNLIKELY(g_quit)) - break; - goto again; - } -/* congestion control */ - case PGM_IO_STATUS_CONGESTION: -/* kernel feedback */ - case PGM_IO_STATUS_WOULD_BLOCK: - { -#ifdef CONFIG_HAVE_EPOLL -/* re-enable write event for one-shot */ - if (pgm_epoll_ctl (tx_sock, efd_again, EPOLL_CTL_MOD, EPOLLOUT | EPOLLONESHOT) < 0) - { - g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); - g_main_loop_quit (g_loop); - return NULL; - } - const int ready = epoll_wait (efd_again, events, G_N_ELEMENTS(events), -1 /* ms */); - if (G_UNLIKELY(g_quit)) - break; -#elif defined(CONFIG_HAVE_POLL) - memset (fds, 0, sizeof(fds)); - fds[0].fd = g_quit_pipe[0]; - fds[0].events = POLLIN; - pgm_poll_info (g_sock, &fds[1], &n_fds, POLLOUT); - poll (fds, 1 + n_fds, -1 /* ms */); -#endif /* !CONFIG_HAVE_EPOLL */ - goto again; - } -/* successful delivery */ - case PGM_IO_STATUS_NORMAL: -// g_message ("sent payload: %s", ping.DebugString().c_str()); -// g_message ("sent %u bytes", (unsigned)bytes_written); - break; - default: - g_warning ("pgm_send_skbv failed, status:%i", status); - g_main_loop_quit (g_loop); - return NULL; - } - g_out_total += bytes_written; - g_msg_sent++; - } while (!g_quit); - -#ifdef CONFIG_HAVE_EPOLL - close (efd_again); -#endif - return NULL; -} - -static -gpointer -receiver_thread ( - gpointer data - ) -{ - pgm_sock_t* rx_sock = (pgm_sock_t*)data; - const long iov_len = 20; - struct pgm_msgv_t msgv[iov_len]; - pgm_time_t lost_tstamp = 0; - pgm_tsi_t lost_tsi; - guint32 lost_count = 0; - -#ifdef CONFIG_HAVE_EPOLL - const long ev_len = 1; - struct epoll_event events[ev_len]; - - int efd = epoll_create (IP_MAX_MEMBERSHIPS); - if (efd < 0) { - g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); - g_main_loop_quit (g_loop); - return NULL; - } - if (pgm_epoll_ctl (rx_sock, efd, EPOLL_CTL_ADD, EPOLLIN) < 0) { - g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); - g_main_loop_quit (g_loop); - return NULL; - } - struct epoll_event event; - memset (&event, 0, sizeof(event)); - event.events = EPOLLIN; - if (epoll_ctl (efd, EPOLL_CTL_ADD, g_quit_pipe[0], &event) < 0) { - g_error ("epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); - g_main_loop_quit (g_loop); - return NULL; - } -#elif defined(CONFIG_HAVE_POLL) - int n_fds = 3; - struct pollfd fds[ 3 + 1 ]; -#endif /* !CONFIG_HAVE_EPOLL */ - - memset (&lost_tsi, 0, sizeof(lost_tsi)); - - do { - struct timeval tv; - int timeout; - size_t len; - pgm_error_t* pgm_err = NULL; - const int status = pgm_recvmsgv (rx_sock, - msgv, - G_N_ELEMENTS(msgv), - MSG_ERRQUEUE, - &len, - &pgm_err); - if (lost_count) { - pgm_time_t elapsed = pgm_time_update_now() - lost_tstamp; - if (elapsed >= pgm_secs(1)) { - g_warning ("pgm data lost %" G_GUINT32_FORMAT " packets detected from %s", - lost_count, pgm_tsi_print (&lost_tsi)); - lost_count = 0; - } - } - - switch (status) { - case PGM_IO_STATUS_NORMAL: -// g_message ("recv %u bytes", (unsigned)len); - on_msgv (msgv, len); - break; - case PGM_IO_STATUS_TIMER_PENDING: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_TIME_REMAIN, &tv, &optlen); - } - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_RATE_REMAIN, &tv, &optlen); - } -/* fall through */ - case PGM_IO_STATUS_WOULD_BLOCK: -block: - timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); -/* busy wait under 2ms */ - if (timeout > 0 && timeout < 2) timeout = 0; -#ifdef CONFIG_HAVE_EPOLL - epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); -#elif defined(CONFIG_HAVE_POLL) - memset (fds, 0, sizeof(fds)); - fds[0].fd = g_quit_pipe[0]; - fds[0].events = POLLIN; - pgm_transport_poll_info (g_transport, &fds[1], &n_fds, POLLIN); - poll (fds, 1 + n_fds, timeout /* ms */); -#endif /* !CONFIG_HAVE_EPOLL */ - break; - case PGM_IO_STATUS_RESET: - { - struct pgm_sk_buff_t* skb = msgv[0].msgv_skb[0]; - lost_tstamp = skb->tstamp; - if (pgm_tsi_equal (&skb->tsi, &lost_tsi)) - lost_count += skb->sequence; - else { - lost_count = skb->sequence; - memcpy (&lost_tsi, &skb->tsi, sizeof(pgm_tsi_t)); - } - pgm_free_skb (skb); - break; - } - default: - if (pgm_err) { - g_warning ("%s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_err = NULL; - } - break; - } - } while (!g_quit); - -#ifdef CONFIG_HAVE_EPOLL - close (efd); -#endif - return NULL; -} - -static -int -on_msgv ( - struct pgm_msgv_t* msgv, /* an array of msgvs */ - size_t len - ) -{ - example::Ping ping; - guint i = 0; - static pgm_time_t last_time = pgm_time_update_now(); - - while (len) - { - const struct pgm_sk_buff_t* pskb = msgv[i].msgv_skb[0]; - gsize apdu_len = 0; - for (unsigned j = 0; j < msgv[i].msgv_len; j++) - apdu_len += msgv[i].msgv_skb[j]->len; - - if (PGMPING_MODE_REFLECTOR == g_mode) - { - int status; -again: - status = pgm_send (g_sock, pskb->data, pskb->len, NULL); - switch (status) { - case PGM_IO_STATUS_RATE_LIMITED: - case PGM_IO_STATUS_CONGESTION: - case PGM_IO_STATUS_WOULD_BLOCK: -/* busy wait always as reflector */ - goto again; - - case PGM_IO_STATUS_NORMAL: - break; - - default: - g_warning ("pgm_send_skbv failed"); - g_main_loop_quit (g_loop); - return 0; - } - goto next_msg; - } - -/* only parse first fragment of each apdu */ - if (!ping.ParseFromArray (pskb->data, pskb->len)) - goto next_msg; -// g_message ("payload: %s", ping.DebugString().c_str()); - - { - const pgm_time_t send_time = ping.time(); - const pgm_time_t recv_time = pskb->tstamp; - const guint64 seqno = ping.seqno(); - const guint64 latency = ping.latency(); - - if (seqno < g_latency_seqno) { - g_message ("seqno replay?"); - goto next_msg; - } - - g_in_total += pskb->len; - g_msg_received++; - -/* handle ping */ - const pgm_time_t now = pgm_time_update_now(); - if (send_time > now) - g_warning ("send time %" PGM_TIME_FORMAT " newer than now %" PGM_TIME_FORMAT, - send_time, now); - if (recv_time > now) - g_warning ("recv time %" PGM_TIME_FORMAT " newer than now %" PGM_TIME_FORMAT, - recv_time, now); - if (send_time >= recv_time){ - g_message ("timer mismatch, send time = recv time + %.3f ms (last time + %.3f ms)", - pgm_to_msecsf(send_time - recv_time), - pgm_to_msecsf(last_time - send_time)); - goto next_msg; - } - g_latency_current = pgm_to_secs(recv_time - send_time); - g_latency_seqno = seqno; - - const double elapsed = pgm_to_usecsf (recv_time - send_time); - g_latency_total += elapsed; - g_latency_square_total += elapsed * elapsed; - - if (elapsed > g_latency_max) - g_latency_max = elapsed; - if (elapsed < g_latency_min) - g_latency_min = elapsed; - - g_latency_running_average += elapsed; - g_latency_count++; - last_time = recv_time; - } - -/* move onto next apdu */ -next_msg: - i++; - len -= apdu_len; - } - - return 0; -} - -/* idle log notification - */ - -static -gboolean -on_mark ( - G_GNUC_UNUSED gpointer data - ) -{ - const pgm_time_t now = pgm_time_update_now (); - const double interval = pgm_to_secsf(now - g_interval_start); - g_interval_start = now; - -/* receiving a ping */ - if (g_latency_count) - { - const double average = g_latency_total / g_latency_count; - const double variance = g_latency_square_total / g_latency_count - - average * average; - const double standard_deviation = sqrt (variance); - - if (g_latency_count < 10) - { - if (average < 1000.0) - g_message ("seqno=%" G_GUINT64_FORMAT " time=%.01f us", - g_latency_seqno, average); - else - g_message ("seqno=%" G_GUINT64_FORMAT " time=%.01f ms", - g_latency_seqno, average / 1000); - } - else - { - double seq_rate = (g_latency_seqno - g_last_seqno) / interval; - double out_rate = g_out_total * 8.0 / 1000000.0 / interval; - double in_rate = g_in_total * 8.0 / 1000000.0 / interval; - if (g_latency_min < 1000.0) - g_message ("s=%.01f avg=%.01f min=%.01f max=%.01f stddev=%0.1f us o=%.2f i=%.2f mbit", - seq_rate, average, g_latency_min, g_latency_max, standard_deviation, out_rate, in_rate); - else - g_message ("s=%.01f avg=%.01f min=%.01f max=%.01f stddev=%0.1f ms o=%.2f i=%.2f mbit", - seq_rate, average / 1000, g_latency_min / 1000, g_latency_max / 1000, standard_deviation / 1000, out_rate, in_rate); - } - -/* reset interval counters */ - g_latency_total = 0.0; - g_latency_square_total = 0.0; - g_latency_count = 0; - g_last_seqno = g_latency_seqno; -#ifdef INFINITY - g_latency_min = INFINITY; -#else - g_latency_min = INT64_MAX; -#endif - g_latency_max = 0.0; - g_out_total = 0; - g_in_total = 0; - } - - return TRUE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/pgmrecv.c b/3rdparty/openpgm-svn-r1085/pgm/examples/pgmrecv.c deleted file mode 100644 index 035ccc4..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/pgmrecv.c +++ /dev/null @@ -1,649 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Simple receiver using the PGM transport, based on enonblocksyncrecvmsgv :/ - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_HAVE_EPOLL -# include -#endif -#include -#include -#ifdef G_OS_UNIX -# include -# include -# include -# include -# include -# include -# include -#else -# include "getopt.h" -#endif -#include -#ifdef CONFIG_WITH_HTTP -# include -#endif -#ifdef CONFIG_WITH_SNMP -# include -#endif - -/* example dependencies */ -#include -#include -#include - - -/* globals */ - -static int g_port = 0; -static const char* g_network = ""; -static const char* g_source = ""; -static gboolean g_multicast_loop = FALSE; -static int g_udp_encap_port = 0; - -static int g_max_tpdu = 1500; -static int g_sqns = 100; - -static pgm_sock_t* g_sock = NULL; -static GThread* g_thread = NULL; -static GMainLoop* g_loop = NULL; -static gboolean g_quit; -#ifdef G_OS_UNIX -static int g_quit_pipe[2]; -static void on_signal (int, gpointer); -#else -static HANDLE g_quit_event; -static BOOL on_console_ctrl (DWORD); -#endif - -static gboolean on_startup (gpointer); -static gboolean on_mark (gpointer); - -static gpointer receiver_thread (gpointer); -static int on_msgv (struct pgm_msgv_t*, size_t); - - -G_GNUC_NORETURN static void -usage ( - const char* bin - ) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -a : Source unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); -#ifdef CONFIG_WITH_HTTP - fprintf (stderr, " -H : Enable HTTP administrative interface\n"); -#endif -#ifdef CONFIG_WITH_SNMP - fprintf (stderr, " -S : Enable SNMP interface\n"); -#endif - fprintf (stderr, " -i : List available interfaces\n"); - exit (1); -} - -int -main ( - int argc, - char* argv[] - ) -{ - int e; - pgm_error_t* pgm_err = NULL; -#ifdef CONFIG_WITH_HTTP - gboolean enable_http = FALSE; -#endif -#ifdef CONFIG_WITH_SNMP - gboolean enable_snmpx = FALSE; -#endif - - setlocale (LC_ALL, ""); - -/* pre-initialise PGM messages module to add hook for GLib logging */ - pgm_messages_init(); - log_init (); - g_message ("pgmrecv"); - - if (!pgm_init (&pgm_err)) { - g_error ("Unable to start PGM engine: %s", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); - pgm_error_free (pgm_err); - pgm_messages_shutdown(); - return EXIT_FAILURE; - } - - g_thread_init (NULL); - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "a:s:n:p:lih" -#ifdef CONFIG_WITH_HTTP - "H" -#endif -#ifdef CONFIG_WITH_SNMP - "S" -#endif - )) != -1) - { - switch (c) { - case 'n': g_network = optarg; break; - case 'a': g_source = optarg; break; - case 's': g_port = atoi (optarg); break; - case 'p': g_udp_encap_port = atoi (optarg); break; - - case 'l': g_multicast_loop = TRUE; break; -#ifdef CONFIG_WITH_HTTP - case 'H': enable_http = TRUE; break; -#endif -#ifdef CONFIG_WITH_SNMP - case 'S': enable_snmpx = TRUE; break; -#endif - - case 'i': - pgm_if_print_all(); - pgm_messages_shutdown(); - return EXIT_SUCCESS; - - case 'h': - case '?': - pgm_messages_shutdown(); - usage (binary_name); - } - } - -#ifdef CONFIG_WITH_HTTP - if (enable_http) { - if (!pgm_http_init (PGM_HTTP_DEFAULT_SERVER_PORT, &pgm_err)) { - g_error ("Unable to start HTTP interface: %s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_shutdown(); - pgm_messages_shutdown(); - return EXIT_FAILURE; - } - } -#endif -#ifdef CONFIG_WITH_SNMP - if (enable_snmpx) { - if (!pgm_snmp_init (&pgm_err)) { - g_error ("Unable to start SNMP interface: %s", pgm_err->message); - pgm_error_free (pgm_err); -#ifdef CONFIG_WITH_HTTP - if (enable_http) - pgm_http_shutdown (); -#endif - pgm_shutdown (); - pgm_messages_shutdown(); - return EXIT_FAILURE; - } - } -#endif - - g_loop = g_main_loop_new (NULL, FALSE); - - g_quit = FALSE; - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif -#ifdef G_OS_UNIX - e = pipe (g_quit_pipe); - g_assert (0 == e); - pgm_signal_install (SIGINT, on_signal, g_loop); - pgm_signal_install (SIGTERM, on_signal, g_loop); -#else - g_quit_event = CreateEvent (NULL, TRUE, FALSE, TEXT("QuitEvent")); - SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); -#endif - -/* delayed startup */ - g_message ("scheduling startup."); - g_timeout_add (0, (GSourceFunc)on_startup, NULL); - -/* dispatch loop */ - g_message ("entering main event loop ... "); - g_main_loop_run (g_loop); - - g_message ("event loop terminated, cleaning up."); - -/* cleanup */ - g_quit = TRUE; -#ifdef G_OS_UNIX - const char one = '1'; - const size_t writelen = write (g_quit_pipe[1], &one, sizeof(one)); - g_assert (sizeof(one) == writelen); - g_thread_join (g_thread); - close (g_quit_pipe[0]); - close (g_quit_pipe[1]); -#else - SetEvent (g_quit_event); - g_thread_join (g_thread); - CloseHandle (g_quit_event); -#endif - - g_main_loop_unref (g_loop); - g_loop = NULL; - - if (g_sock) { - g_message ("closing PGM socket."); - - pgm_close (g_sock, TRUE); - g_sock = NULL; - } - -#ifdef CONFIG_WITH_HTTP - if (enable_http) - pgm_http_shutdown(); -#endif -#ifdef CONFIG_WITH_SNMP - if (enable_snmpx) - pgm_snmp_shutdown(); -#endif - - g_message ("PGM engine shutdown."); - pgm_shutdown(); - g_message ("finished."); - pgm_messages_shutdown(); - return EXIT_SUCCESS; -} - -#ifdef G_OS_UNIX -static -void -on_signal ( - int signum, - gpointer user_data - ) -{ - GMainLoop* loop = (GMainLoop*)user_data; - g_message ("on_signal (signum:%d user_data:%p)", - signum, user_data); - g_main_loop_quit (loop); -} -#else -static -BOOL -on_console_ctrl ( - DWORD dwCtrlType - ) -{ - g_message ("on_console_ctrl (dwCtrlType:%lu)", (unsigned long)dwCtrlType); - g_main_loop_quit (g_loop); - return TRUE; -} -#endif /* !G_OS_UNIX */ - -static -gboolean -on_startup ( - G_GNUC_UNUSED gpointer data - ) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - - g_message ("startup."); - -/* parse network parameter into transport address structure */ - if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { - g_error ("parsing network parameter: %s", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - if (g_udp_encap_port) { - g_message ("create PGM/UDP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - } else { - g_message ("create PGM/IP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (g_sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int recv_only = 1, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (50), - nak_rpt_ivl = pgm_secs (2), - nak_rdata_ivl = pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50; - - pgm_setsockopt (g_sock, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - pgm_setsockopt (g_sock, PGM_PASSIVE, &passive, sizeof(passive)); - pgm_setsockopt (g_sock, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); - pgm_setsockopt (g_sock, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); - pgm_setsockopt (g_sock, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - pgm_setsockopt (g_sock, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - pgm_setsockopt (g_sock, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - pgm_setsockopt (g_sock, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - g_error ("creating GSI: %s", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (g_sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - g_error ("binding PGM socket: %s", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (g_sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (g_sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int nonblocking = 1, - multicast_loop = g_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (g_sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (g_sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (g_sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (g_sock, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); - - if (!pgm_connect (g_sock, &pgm_err)) { - g_error ("connecting PGM socket: %s", pgm_err->message); - goto err_abort; - } - -/* create receiver thread */ - GError* glib_err = NULL; - g_thread = g_thread_create_full (receiver_thread, - g_sock, - 0, - TRUE, - TRUE, - G_THREAD_PRIORITY_HIGH, - &glib_err); - if (!g_thread) { - g_error ("g_thread_create_full failed errno %i: \"%s\"", glib_err->code, glib_err->message); - g_error_free (glib_err); - goto err_abort; - } - -/* period timer to indicate some form of life */ -// TODO: Gnome 2.14: replace with g_timeout_add_seconds() - g_timeout_add(10 * 1000, (GSourceFunc)on_mark, NULL); - - g_message ("startup complete."); - return FALSE; - -err_abort: - if (NULL != g_sock) { - pgm_close (g_sock, FALSE); - g_sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - g_main_loop_quit (g_loop); - return FALSE; -} - -/* idle log notification - */ - -static -gboolean -on_mark ( - G_GNUC_UNUSED gpointer data - ) -{ - g_message ("-- MARK --"); - return TRUE; -} - -static -gpointer -receiver_thread ( - gpointer data - ) -{ - pgm_sock_t* rx_sock = (pgm_sock_t*)data; - const long iov_len = 20; - const long ev_len = 1; - struct pgm_msgv_t msgv[iov_len]; - -#ifdef CONFIG_HAVE_EPOLL - struct epoll_event events[ev_len]; /* wait for maximum 1 event */ - int timeout; - const int efd = epoll_create (IP_MAX_MEMBERSHIPS); - if (efd < 0) { - g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); - g_main_loop_quit (g_loop); - return NULL; - } - - if (pgm_epoll_ctl (rx_sock, efd, EPOLL_CTL_ADD, EPOLLIN) < 0) - { - g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); - g_main_loop_quit (g_loop); - return NULL; - } - struct epoll_event event; - event.events = EPOLLIN; - event.data.fd = g_quit_pipe[0]; - if (epoll_ctl (efd, EPOLL_CTL_ADD, g_quit_pipe[0], &event) < 0) - { - g_error ("epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); - g_main_loop_quit (g_loop); - return NULL; - } -#elif defined(CONFIG_HAVE_POLL) - int timeout; - int n_fds = 2; - struct pollfd fds[ 1 + n_fds ]; -#elif defined(G_OS_UNIX) /* HAVE_SELECT */ - int n_fds; - fd_set readfds; -#else /* G_OS_WIN32 */ - int n_handles = 3; -# if (__STDC_VERSION__ >= 199901L) - HANDLE waitHandles[n_handles]; -# else - HANDLE* waitHandles = (HANDLE*)g_malloc (n_handles * sizeof(HANDLE));; -# endif - DWORD timeout, dwEvents; - WSAEVENT recvEvent, pendingEvent; - - recvEvent = WSACreateEvent (); - WSAEventSelect (pgm_transport_get_recv_fd (g_transport), recvEvent, FD_READ); - pendingEvent = WSACreateEvent (); - WSAEventSelect (pgm_transport_get_pending_fd (g_transport), pendingEvent, FD_READ); - - waitHandles[0] = g_quit_event; - waitHandles[1] = recvEvent; - waitHandles[2] = pendingEvent; -#endif /* !CONFIG_HAVE_EPOLL */ - - do { - struct timeval tv; - size_t len; - pgm_error_t* pgm_err = NULL; - const int status = pgm_recvmsgv (rx_sock, - msgv, - G_N_ELEMENTS(msgv), - 0, - &len, - &pgm_err); - switch (status) { - case PGM_IO_STATUS_NORMAL: - on_msgv (msgv, len); - break; - case PGM_IO_STATUS_TIMER_PENDING: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (rx_sock, PGM_TIME_REMAIN, &tv, &optlen); - } - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (rx_sock, PGM_RATE_REMAIN, &tv, &optlen); - } -/* fall through */ - case PGM_IO_STATUS_WOULD_BLOCK: -block: -#ifdef CONFIG_HAVE_EPOLL - timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); -#elif defined(CONFIG_HAVE_POLL) - timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - memset (fds, 0, sizeof(fds)); - fds[0].fd = g_quit_pipe[0]; - fds[0].events = POLLIN; - pgm_poll_info (rx_sock, &fds[1], &n_fds, POLLIN); - poll (fds, 1 + n_fds, timeout /* ms */); -#elif defined(G_OS_UNIX) /* HAVE_SELECT */ - FD_ZERO(&readfds); - FD_SET(g_quit_pipe[0], &readfds); - n_fds = g_quit_pipe[0] + 1; - pgm_select_info (rx_sock, &readfds, NULL, &n_fds); - select (n_fds, &readfds, NULL, NULL, PGM_IO_STATUS_RATE_LIMITED == status ? &tv : NULL); -#else /* G_OS_WIN32 */ - timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, timeout); - switch (dwEvents) { - case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; - case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break; - default: break; - } -#endif /* !CONFIG_HAVE_EPOLL */ - break; - - default: - if (pgm_err) { - g_warning ("%s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_err = NULL; - } - if (PGM_IO_STATUS_ERROR == status) - break; - } - } while (!g_quit); - -#ifdef CONFIG_HAVE_EPOLL - close (efd); -#elif defined(G_OS_WIN32) - WSACloseEvent (recvEvent); - WSACloseEvent (pendingEvent); -# if (__STDC_VERSION__ < 199901L) - g_free (waitHandles); -# endif -#endif - return NULL; -} - -static -int -on_msgv ( - struct pgm_msgv_t* msgv, /* an array of msgvs */ - size_t len - ) -{ - g_message ("(%u bytes)", - (unsigned)len); - - guint i = 0; -/* for each apdu */ - do { - const struct pgm_sk_buff_t* pskb = msgv[i].msgv_skb[0]; - gsize apdu_len = 0; - for (unsigned j = 0; j < msgv[i].msgv_len; j++) - apdu_len += msgv[i].msgv_skb[j]->len; -/* truncate to first fragment to make GLib printing happy */ - char buf[2048], tsi[PGM_TSISTRLEN]; - const gsize buflen = MIN(sizeof(buf) - 1, pskb->len); - strncpy (buf, (const char*)pskb->data, buflen); - buf[buflen] = '\0'; - pgm_tsi_print_r (&pskb->tsi, tsi, sizeof(tsi)); - if (msgv[i].msgv_len > 1) - g_message ("\t%u: \"%s\" ... (%" G_GSIZE_FORMAT " bytes from %s)", - i, buf, apdu_len, tsi); - else - g_message ("\t%u: \"%s\" (%" G_GSIZE_FORMAT " bytes from %s)", - i, buf, apdu_len, tsi); - i++; - len -= apdu_len; - } while (len); - - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/pgmsend.c b/3rdparty/openpgm-svn-r1085/pgm/examples/pgmsend.c deleted file mode 100644 index d8d3539..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/pgmsend.c +++ /dev/null @@ -1,305 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Simple sender using the PGM transport. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef G_OS_UNIX -# include -# include -# include -# include -# include -# include -#else -# include "getopt.h" -#endif -#include - -/* example dependencies */ -#include -#include - - -/* typedefs */ - -/* globals */ - -static int g_port = 0; -static const char* g_network = ""; -static gboolean g_multicast_loop = FALSE; -static int g_udp_encap_port = 0; - -static int g_max_tpdu = 1500; -static int g_max_rte = 400*1000; -static int g_sqns = 100; - -static gboolean g_fec = FALSE; -static int g_k = 8; -static int g_n = 255; - -static pgm_sock_t* g_sock = NULL; - -static gboolean create_pgm_socket (void); - - -G_GNUC_NORETURN static -void -usage (const char* bin) -{ - fprintf (stderr, "Usage: %s [options] message\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -r : Regulate to rate bytes per second\n"); - fprintf (stderr, " -f : Enable FEC with either proactive or ondemand parity\n"); - fprintf (stderr, " -K : Configure Reed-Solomon code (n, k)\n"); - fprintf (stderr, " -N \n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); - fprintf (stderr, " -i : List available interfaces\n"); - exit (1); -} - -int -main ( - int argc, - char *argv[] - ) -{ - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - -/* pre-initialise PGM messages module to add hook for GLib logging */ - pgm_messages_init(); - log_init(); - if (!pgm_init (&pgm_err)) { - g_error ("Unable to start PGM engine: %s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_messages_shutdown(); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:r:f:K:N:lih")) != -1) - { - switch (c) { - case 'n': g_network = optarg; break; - case 's': g_port = atoi (optarg); break; - case 'p': g_udp_encap_port = atoi (optarg); break; - case 'r': g_max_rte = atoi (optarg); break; - - case 'f': g_fec = TRUE; break; - case 'K': g_k = atoi (optarg); break; - case 'N': g_n = atoi (optarg); break; - - case 'l': g_multicast_loop = TRUE; break; - - case 'i': - pgm_if_print_all(); - pgm_messages_shutdown(); - return EXIT_SUCCESS; - - case 'h': - case '?': - pgm_messages_shutdown(); - usage (binary_name); - } - } - - if (g_fec && ( !g_k || !g_n )) { - pgm_messages_shutdown(); - g_error ("Invalid Reed-Solomon parameters RS(%d, %d).", g_n, g_k); - usage (binary_name); - } - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif - - if (create_pgm_socket()) - { - while (optind < argc) { - const int status = pgm_send (g_sock, argv[optind], strlen(argv[optind]) + 1, NULL); - if (PGM_IO_STATUS_NORMAL != status) { - g_warning ("pgm_send failed."); - } - optind++; - } - } - -/* cleanup */ - if (g_sock) { - pgm_close (g_sock, TRUE); - g_sock = NULL; - } - pgm_shutdown(); - pgm_messages_shutdown(); - return EXIT_SUCCESS; -} - -static -gboolean -create_pgm_socket (void) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - -/* parse network parameter into PGM socket address structure */ - if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { - g_error ("Parsing network parameter: %s", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - if (g_udp_encap_port) { - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - g_error ("Creating PGM/UDP socket: %s", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - } else { - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - g_error ("Creating PGM/IP socket: %s", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (g_sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int send_only = 1, - ambient_spm = pgm_secs (30), - heartbeat_spm[] = { pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (1300), - pgm_secs (7), - pgm_secs (16), - pgm_secs (25), - pgm_secs (30) }; - - pgm_setsockopt (g_sock, PGM_SEND_ONLY, &send_only, sizeof(send_only)); - pgm_setsockopt (g_sock, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); - pgm_setsockopt (g_sock, PGM_TXW_SQNS, &g_sqns, sizeof(g_sqns)); - pgm_setsockopt (g_sock, PGM_TXW_MAX_RTE, &g_max_rte, sizeof(g_max_rte)); - pgm_setsockopt (g_sock, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm)); - pgm_setsockopt (g_sock, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm)); - if (g_fec) { - struct pgm_fecinfo_t fecinfo; - fecinfo.block_size = g_n; - fecinfo.proactive_packets = 0; - fecinfo.group_size = g_k; - fecinfo.ondemand_parity_enabled = TRUE; - fecinfo.var_pktlen_enabled = TRUE; - pgm_setsockopt (g_sock, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); - } - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - g_error ("Creating GSI: %s", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (g_sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - g_error ("Binding PGM socket: %s", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (g_sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (g_sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int blocking = 0, - multicast_loop = g_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (g_sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (g_sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (g_sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (g_sock, PGM_NOBLOCK, &blocking, sizeof(blocking)); - - if (!pgm_connect (g_sock, &pgm_err)) { - g_error ("Connecting PGM socket: %s", pgm_err->message); - goto err_abort; - } - - return TRUE; - -err_abort: - if (NULL != g_sock) { - pgm_close (g_sock, FALSE); - g_sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/pgmtop.c b/3rdparty/openpgm-svn-r1085/pgm/examples/pgmtop.c deleted file mode 100644 index 9b18310..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/pgmtop.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM packet monitor. - * - * Copyright (c) 2006-2007 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* PGM internals */ -#include - -/* example dependencies */ -#include -#include - - -struct ncurses_window; - -typedef void (*paint_func)(struct ncurses_window*); -typedef void (*resize_func)(struct ncurses_window*, int, int); - -struct ncurses_window { - WINDOW* window; - PANEL* panel; - char* title; - paint_func paint; - resize_func resize; -}; - -struct pgm_stat { - gulong count, snap_count; - gulong bytes, snap_bytes; - gulong tsdu; - - gulong duplicate; - gulong invalid; - - struct timeval last; - struct timeval last_valid; - struct timeval last_invalid; -}; - -struct pgm_netstat { - struct in_addr addr; - gulong corrupt; -}; - -struct pgm_hoststat { - pgm_tsi_t tsi; - - struct in_addr last_addr; - struct in_addr nla; - - gulong txw_secs; - gulong txw_trail; - gulong txw_lead; - gulong txw_sqns; - - gulong rxw_trail; - gulong rxw_lead; - - gulong rxw_trail_init; - gboolean window_defined; - gboolean rxw_constrained; - - gulong spm_sqn; - - struct pgm_stat spm, - poll, - polr, - odata, - rdata, - nak, - nnak, - ncf, - spmr, - - general; - - struct timeval session_start; -}; - - -/* globals */ - -static int g_port = 7500; -static const char* g_network = "239.192.0.1"; -static struct in_addr g_filter = { 0 }; - -static GIOChannel* g_io_channel = NULL; -static GIOChannel* g_stdin_channel = NULL; - -static GMainLoop* g_loop = NULL; - -static guint g_status_height = 6; -static guint g_info_width = 10; -static time_t start_time; - -static struct ncurses_window *g_peer, *g_info, *g_status, *g_active; -static GList* g_window_list = NULL; -static guint g_paint_interval = ( 1 * 1000 ) / 15; -static guint g_snap_interval = 10 * 1000; -static struct timeval g_last_snap, g_now; - -static GList* g_status_list = NULL; - -static guint32 g_packets = 0; -static GHashTable *g_hosts = NULL; -static GHashTable *g_nets = NULL; - -static void init_ncurses (void); -static void paint_ncurses (void); -static void resize_ncurses (int, int); - -static void paint_peer (struct ncurses_window*); -static gboolean tsi_row (gpointer, gpointer, gpointer); - -static void paint_info (struct ncurses_window*); -static void paint_status (struct ncurses_window*); -static void resize_peer (struct ncurses_window*, int, int); -static void resize_info (struct ncurses_window*, int, int); -static void resize_status (struct ncurses_window*, int, int); - -static void write_status (const gchar*, ...) G_GNUC_PRINTF (1, 2); -static void write_statusv (const gchar*, va_list); - -static void on_signal (int, gpointer); -static void on_winch (int); -static gboolean on_startup (gpointer); -static gboolean on_snap (gpointer); -static gboolean on_paint (gpointer); - -static gboolean on_io_data (GIOChannel*, GIOCondition, gpointer); -static gboolean on_io_error (GIOChannel*, GIOCondition, gpointer); - -static gboolean on_stdin_data (GIOChannel*, GIOCondition, gpointer); - -int -main ( - G_GNUC_UNUSED int argc, - G_GNUC_UNUSED char *argv[] - ) -{ - GError* err = NULL; - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - - log_init (); - g_message ("pgmtop"); - - if (!pgm_init (&pgm_err)) { - g_error ("Unable to start PGM engine: %s", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - - g_loop = g_main_loop_new (NULL, FALSE); - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); - signal (SIGHUP, SIG_IGN); - pgm_signal_install (SIGINT, on_signal, g_loop); - pgm_signal_install (SIGTERM, on_signal, g_loop); - -/* delayed startup */ - g_message ("scheduling startup.n"); - g_timeout_add(0, (GSourceFunc)on_startup, g_loop); - -/* dispatch loop */ - g_message ("entering main event loop ..."); - g_main_loop_run (g_loop); - - endwin(); - g_message ("event loop terminated, cleaning up."); - -/* cleanup */ - g_main_loop_unref (g_loop); - g_loop = NULL; - if (g_io_channel) { - g_message ("closing socket."); - g_io_channel_shutdown (g_io_channel, FALSE, &err); - g_io_channel = NULL; - } - - if (g_stdin_channel) { - g_message ("unbinding stdin."); - g_io_channel_unref (g_stdin_channel); - g_stdin_channel = NULL; - } - - g_message ("PGM engine shutdown."); - pgm_shutdown (); - g_message ("finished."); - return EXIT_SUCCESS; -} - -static struct ncurses_window* -create_window ( - char* name, - paint_func paint, - resize_func resize - ) -{ - struct ncurses_window* nw = g_malloc0 (sizeof(struct ncurses_window)); - nw->window = newwin (0, 0, 0, 0); - nw->panel = new_panel (nw->window); - nw->title = name; - - nw->paint = paint; - nw->resize = resize; - - g_window_list = g_list_append (g_window_list, nw); - return nw; -} - -/* +-Peer list --------------++-Info-+ - * | || | - * | < peer window > || < info window > - * | || | - * +-------------------------++------+ - * +-Status--------------------------+ - * | < status window > | - * +---------------------------------+ - */ - -static void -init_ncurses (void) -{ -/* setup ncurses terminal display */ - initscr(); /* init ncurses library */ - -// signal_install (SIGWINCH, on_winch); - - noecho(); /* hide entered keys */ - cbreak(); - -/* setup ncurses windows */ - g_peer = create_window ("Peers", paint_peer, resize_peer); - - g_info = create_window ("Info", paint_info, resize_info); - start_time = time (0); - - g_status = create_window ("Status", paint_status, resize_status); - scrollok (g_status->window, 1); - - g_active = g_peer; - top_panel (g_active->panel); - - paint_ncurses(); -} - -static void -resize_ncurses ( - int hsize, - int vsize - ) -{ - GList* nw_list = g_window_list; - while (nw_list) - { - struct ncurses_window* nw = (struct ncurses_window*)nw_list->data; - - nw->resize (nw, hsize, vsize); - - nw_list = nw_list->next; - } -} - -static void -paint_ncurses (void) -{ - static int hsize = 0, vsize = 0; - - if (hsize != COLS || vsize != LINES) - { - hsize = COLS; vsize = LINES; - resize_ncurses(hsize, vsize); - } - - GList* nw_list = g_window_list; - while (nw_list) - { - struct ncurses_window* nw = (struct ncurses_window*)nw_list->data; - werase (nw->window); - - box (nw->window, ACS_VLINE, ACS_HLINE); - mvwaddstr (nw->window, 0, 2, nw->title); - - nw->paint (nw); - - nw_list = nw_list->next; - } - -/* have cursor stay at top left of active window */ - wmove (g_active->window, 0, 0); - - update_panels(); /* update virtual screen */ - doupdate(); /* update real screen */ -} - -/* peer window */ - -static void -paint_peer ( - struct ncurses_window* nw - ) -{ - -/* 1 2 3 4 5 6 7 8 - * 012345678901234567890123456789012345678901234567890123456789012345678901234567890 - * TSI Packets Bytes Packet/s Bit/s Data Inv Dupe - * 100.200.300.400.500.600.70000 1,000K 1,000MB 1,000 1,000 100% 100% 100% - */ - mvwaddstr (nw->window, 1, 1, "TSI"); - mvwaddstr (nw->window, 1, 32, "Packets"); - mvwaddstr (nw->window, 1, 40, "Bytes"); - mvwaddstr (nw->window, 1, 48, "Packet/s"); - mvwaddstr (nw->window, 1, 58, "Bit/s"); - mvwaddstr (nw->window, 1, 68, "Data"); - mvwaddstr (nw->window, 1, 73, "Inv"); - mvwaddstr (nw->window, 1, 78, "Dupe"); - - if (g_hosts) - { - int row = 2; - gettimeofday(&g_now, NULL); - g_hash_table_foreach (g_hosts, (GHFunc)tsi_row, &row); - } -} - -static char* -print_si ( - float* v - ) -{ - static char prefix[5] = ""; - - if (*v > 100 * 1000 * 1000) { - strcpy (prefix, "G"); - *v /= 1000.0 * 1000.0 * 1000.0; - } else if (*v > 100 * 1000) { - strcpy (prefix, "M"); - *v /= 1000.0 * 1000.0; - } else if (*v > 100) { - strcpy (prefix, "K"); - *v /= 1000.0; - } else { - *prefix = 0; - } - - return prefix; -} - -static gboolean -tsi_row ( - G_GNUC_UNUSED gpointer key, - gpointer value, - gpointer user_data - ) -{ - struct pgm_hoststat* hoststat = value; - int* row = user_data; - - float secs = (g_now.tv_sec - g_last_snap.tv_sec) + - ( (g_now.tv_usec - g_last_snap.tv_usec) / 1000.0 / 1000.0 ); - -/* TSI */ - char* tsi_string = pgm_tsi_print (&hoststat->tsi); - mvwaddstr (g_peer->window, *row, 1, tsi_string); - -/* Packets */ - char buffer[100]; - float v = hoststat->general.count; - char* prefix = print_si (&v); - snprintf (buffer, sizeof(buffer), "%lu%s", (gulong)v, prefix); - mvwaddstr (g_peer->window, *row, 32, buffer); - -/* Bytes */ - v = hoststat->general.bytes; - prefix = print_si (&v); - snprintf (buffer, sizeof(buffer), "%lu%s", (gulong)v, prefix); - mvwaddstr (g_peer->window, *row, 40, buffer); - -/* Packet/s */ - v = ( hoststat->general.count - hoststat->general.snap_count ) / secs; - prefix = print_si (&v); - snprintf (buffer, sizeof(buffer), "%.1f%s", v, prefix); - mvwaddstr (g_peer->window, *row, 48, buffer); - -/* Bit/s */ - float bitrate = ((float)( hoststat->general.bytes - hoststat->general.snap_bytes ) * 8.0 / secs); - char* bitprefix = print_si (&bitrate); - snprintf (buffer, sizeof(buffer), "%.1f%s", bitrate, bitprefix); - mvwaddstr (g_peer->window, *row, 58, buffer); - -/* % Data */ - snprintf (buffer, sizeof(buffer), "%d%%", (int)((100.0 * hoststat->odata.tsdu) / hoststat->general.bytes)); - mvwaddstr (g_peer->window, *row, 68, buffer); - -/* % Invalid */ - snprintf (buffer, sizeof(buffer), "%d%%", (int)(hoststat->general.invalid ? (100.0 * hoststat->general.invalid) / hoststat->general.count : 0.0)); - mvwaddstr (g_peer->window, *row, 73, buffer); - -/* % Duplicate */ - snprintf (buffer, sizeof(buffer), "%d%%", (int)(hoststat->general.duplicate ? (100.0 * hoststat->general.duplicate) / hoststat->general.count : 0.0)); - mvwaddstr (g_peer->window, *row, 78, buffer); - - *row = *row + 1; - - return FALSE; -} - -static void -resize_peer ( - struct ncurses_window* nw, - int hsize, /* COLS */ - int vsize /* LINES */ - ) -{ - wresize (nw->window, vsize - g_status_height, hsize - g_info_width); - replace_panel (nw->panel, nw->window); - move_panel (nw->panel, 0, 0); -} - -/* info window */ - -static void -paint_info ( - struct ncurses_window* nw - ) -{ - char buffer[20]; - - mvwaddstr (nw->window, 1, 2, "Peers"); - snprintf (buffer, sizeof(buffer), "%d", g_hosts ? g_hash_table_size (g_hosts) : 0); - mvwaddstr (nw->window, 2, 2, buffer); - - mvwaddstr (nw->window, 3, 2, "Packets"); - snprintf (buffer, sizeof(buffer), "%d", g_packets); - mvwaddstr (nw->window, 4, 2, buffer); - - mvwaddstr (nw->window, LINES - g_status_height - 2, 2, "Elapsed"); - time_t elapsed = time(0) - start_time; - snprintf (buffer, sizeof(buffer), "%02d:%02d:%02d", - (int) (elapsed / 60) / 60, (int) (elapsed / 60) % 60, - (int) elapsed % 60); - mvwaddstr (nw->window, LINES - g_status_height - 1, 1, buffer); -} - -static void -resize_info ( - struct ncurses_window* nw, - int hsize, /* COLS */ - int vsize /* LINES */ - ) -{ - wresize (nw->window, vsize - g_status_height, g_info_width); - replace_panel (nw->panel, nw->window); - move_panel (nw->panel, 0, hsize - g_info_width); -} - -/* status window */ - -static void -paint_status ( - G_GNUC_UNUSED struct ncurses_window* nw - ) -{ - if (!g_status_list) return; - - guint len = g_list_length (g_status_list); - while (len > g_status_height) { - g_free (g_status_list->data); - g_status_list = g_list_delete_link (g_status_list, g_status_list); - len--; - } - guint y = 1; - GList* list = g_status_list; - while (list) { - mvwaddstr (g_status->window, y++, 3, (char*)list->data); - list = list->next; - } -} - -static void -resize_status ( - struct ncurses_window* nw, - int hsize, /* COLS */ - int vsize /* LINES */ - ) -{ - wresize (nw->window, g_status_height, hsize); - replace_panel (nw->panel, nw->window); - move_panel (nw->panel, vsize - g_status_height, 0); -} - -static void -write_status ( - const gchar* format, - ... - ) -{ - va_list args; - - va_start (args, format); - write_statusv (format, args); - va_end (args); -} - -static void -write_statusv ( - const gchar* format, - va_list args1 - ) -{ - char buffer[1024]; - vsnprintf (buffer, sizeof(buffer), format, args1); - - g_status_list = g_list_append (g_status_list, g_memdup (buffer, strlen(buffer)+1)); -} - -static -void -on_signal ( - int signum, - gpointer user_data - ) -{ - GMainLoop* loop = (GMainLoop*)user_data; - puts ("on_signal"); - g_main_loop_quit (loop); -} - -/* terminal resize signal - */ - -static void -on_winch ( - G_GNUC_UNUSED int signum - ) -{ - paint_ncurses (); -} - -static gboolean -on_startup ( - gpointer user_data - ) -{ - GMainLoop* loop = (GMainLoop*)user_data; - int e; - - puts ("startup."); - -/* find PGM protocol id */ -// TODO: fix valgrind errors - int ipproto_pgm = IPPROTO_PGM; -#if HAVE_GETPROTOBYNAME_R - char b[1024]; - struct protoent protobuf, *proto; - e = getprotobyname_r ("pgm", &protobuf, b, sizeof(b), &proto); - if (e != -1 && proto != NULL) { - if (proto->p_proto != ipproto_pgm) { - print f("Setting PGM protocol number to %i from /etc/protocols.\n", proto->p_proto); - ipproto_pgm = proto->p_proto; - } - } -#else - struct protoent *proto = getprotobyname ("pgm"); - if (proto != NULL) { - if (proto->p_proto != ipproto_pgm) { - printf("Setting PGM protocol number to %i from /etc/protocols.\n", proto->p_proto); - ipproto_pgm = proto->p_proto; - } - } -#endif - -/* open socket for snooping */ - puts ("opening raw socket."); - int sock = socket (PF_INET, SOCK_RAW, ipproto_pgm); - if (sock < 0) { - int _e = errno; - puts ("on_startup() failed"); - - if (_e == EPERM && 0 != getuid()) { - puts ("PGM protocol requires this program to run as superuser."); - } - g_main_loop_quit (loop); - return FALSE; - } - -/* drop out of setuid 0 */ - if (0 == getuid ()) { - puts ("dropping superuser privileges."); - setuid ((gid_t)65534); - setgid ((uid_t)65534); - } - - char _t = 1; - e = setsockopt (sock, IPPROTO_IP, IP_HDRINCL, &_t, sizeof(_t)); - if (e < 0) { - printw ("on_startup() failed\n"); - close (sock); - g_main_loop_quit (loop); - return FALSE; - } - -/* buffers */ - int buffer_size = 0; - socklen_t len = 0; - e = getsockopt (sock, SOL_SOCKET, SO_RCVBUF, &buffer_size, &len); - if (e == 0) { - printf ("receive buffer set at %i bytes.\n", buffer_size); - } - e = getsockopt (sock, SOL_SOCKET, SO_SNDBUF, &buffer_size, &len); - if (e == 0) { - printf ("send buffer set at %i bytes.\n", buffer_size); - } - -/* bind */ - struct sockaddr_in addr; - memset (&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - e = bind (sock, (struct sockaddr*)&addr, sizeof(addr)); - if (e < 0) { - printw ("on_startup() failed\n"); - close (sock); - g_main_loop_quit (loop); - return FALSE; - } - -/* multicast */ - struct ip_mreq mreq; - memset (&mreq, 0, sizeof(mreq)); - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - printf ("listening on interface %s.\n", inet_ntoa(mreq.imr_interface)); - mreq.imr_multiaddr.s_addr = inet_addr(g_network); - printf ("subscription on multicast address %s.\n", inet_ntoa(mreq.imr_multiaddr)); - e = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); - if (e < 0) { - printw ("on_startup() failed\n"); - close (sock); - g_main_loop_quit (loop); - return FALSE; - } - -/* multicast loopback */ -/* multicast ttl */ - -/* add socket to event manager */ - g_io_channel = g_io_channel_unix_new (sock); - printf ("socket opened with encoding %s.\n", g_io_channel_get_encoding(g_io_channel)); - - /* guint event = */ g_io_add_watch (g_io_channel, G_IO_IN | G_IO_PRI, on_io_data, NULL); - /* guint event = */ g_io_add_watch (g_io_channel, G_IO_ERR | G_IO_HUP | G_IO_NVAL, on_io_error, NULL); - -/* add stdin to event manager */ - g_stdin_channel = g_io_channel_unix_new (fileno(stdin)); - printf ("binding stdin with encoding %s.\n", g_io_channel_get_encoding(g_stdin_channel)); - - g_io_add_watch (g_stdin_channel, G_IO_IN | G_IO_PRI, on_stdin_data, NULL); - -/* periodic timer to snapshot statistics */ - g_timeout_add (g_snap_interval, (GSourceFunc)on_snap, NULL); - -/* period timer to update screen */ - g_timeout_add (g_paint_interval, (GSourceFunc)on_paint, NULL); - - puts ("READY"); - - init_ncurses(); - return FALSE; -} - -static gboolean -on_paint ( - G_GNUC_UNUSED gpointer data - ) -{ - paint_ncurses(); - - return TRUE; -} - -static guint -tsi_hash ( - gconstpointer v - ) -{ - return g_str_hash(pgm_tsi_print(v)); -} - -static gint -tsi_equal ( - gconstpointer v, - gconstpointer v2 - ) -{ - return memcmp (v, v2, (6 * sizeof(guint8)) + sizeof(guint16)) == 0; -} - -static gboolean -on_io_data ( - GIOChannel* source, - G_GNUC_UNUSED GIOCondition condition, - G_GNUC_UNUSED gpointer user_data - ) -{ - struct timeval now; - struct pgm_sk_buff_t* skb = pgm_alloc_skb (4096); - struct sockaddr_storage src, dst; - struct sockaddr_in* sin = (struct sockaddr_in*)&src; - socklen_t src_addr_len = sizeof(src); - int fd = g_io_channel_unix_get_fd(source); - - skb->len = recvfrom(fd, skb->head, 4096, MSG_DONTWAIT, (struct sockaddr*)&src, &src_addr_len); - - gettimeofday (&now, NULL); - g_packets++; - - GError* err = NULL; - gboolean is_valid = pgm_parse_raw (skb, (struct sockaddr*)&dst, &err); - if (!is_valid && err && PGM_PACKET_ERROR_CKSUM == err->code) - { -/* corrupt packet */ - if (!g_nets) { - g_nets = g_hash_table_new (g_int_hash, g_int_equal); - } - - struct pgm_netstat* netstat = g_hash_table_lookup (g_nets, &sin->sin_addr); - if (netstat == NULL) { - write_status ("new host publishing corrupt data, local nla %s", inet_ntoa(sin->sin_addr)); - netstat = g_malloc0(sizeof(struct pgm_netstat)); - netstat->addr = sin->sin_addr; - g_hash_table_insert (g_nets, (gpointer)&netstat->addr, (gpointer)netstat); - } - - netstat->corrupt++; - pgm_free_skb (skb); - return TRUE; - } - else if (!is_valid) - { -/* general error */ - pgm_free_skb (skb); - return TRUE; - } - -/* search for existing session */ - if (!g_hosts) { - g_hosts = g_hash_table_new (tsi_hash, tsi_equal); - } - - struct pgm_hoststat* hoststat = g_hash_table_lookup (g_hosts, &skb->tsi); - if (hoststat == NULL) { - write_status ("new tsi %s with local nla %s", pgm_tsi_print (&skb->tsi), inet_ntoa(sin->sin_addr)); - - hoststat = g_malloc0(sizeof(struct pgm_hoststat)); - memcpy (&hoststat->tsi, &skb->tsi, sizeof(pgm_tsi_t)); - hoststat->session_start = now; - - g_hash_table_insert (g_hosts, (gpointer)&hoststat->tsi, (gpointer)hoststat); - } - -/* increment statistics */ - memcpy (&hoststat->last_addr, &sin->sin_addr, sizeof(sin->sin_addr)); - hoststat->general.count++; - hoststat->general.bytes += skb->len; - hoststat->general.last = now; - - skb->data = (guint8*)skb->data + sizeof(struct pgm_header); - skb->len -= sizeof(struct pgm_header); - -/* repurpose is_valid for PGM subtype */ - is_valid = FALSE; - switch (skb->pgm_header->pgm_type) { - case PGM_SPM: - hoststat->spm.count++; - hoststat->spm.bytes += skb->len; - hoststat->spm.last = now; - - is_valid = pgm_verify_spm (skb); - if (!is_valid) { - hoststat->spm.invalid++; - hoststat->spm.last_invalid = now; - } else { - const struct pgm_spm* spm = (struct pgm_spm*)skb->data; - - hoststat->nla.s_addr = spm->spm_nla.s_addr; - if (pgm_uint32_lte (g_ntohl( spm->spm_sqn ), hoststat->spm_sqn)) { - hoststat->general.duplicate++; - break; - } - hoststat->spm_sqn = g_ntohl( spm->spm_sqn ); - hoststat->txw_trail = g_ntohl( spm->spm_trail ); - hoststat->txw_lead = g_ntohl( spm->spm_lead ); - hoststat->rxw_trail = hoststat->txw_trail; - hoststat->window_defined = TRUE; - } - break; - - case PGM_ODATA: - hoststat->odata.count++; - hoststat->odata.bytes += skb->len; - hoststat->odata.last = now; - - const struct pgm_data* data = (struct pgm_data*)skb->data; - - if (!hoststat->window_defined) { - hoststat->rxw_lead = g_ntohl (data->data_sqn) - 1; - hoststat->rxw_trail = hoststat->rxw_trail_init = hoststat->rxw_lead + 1; - hoststat->rxw_constrained = TRUE; - hoststat->window_defined = TRUE; - } else { - if (! pgm_uint32_gte( g_ntohl (data->data_sqn) , hoststat->rxw_trail ) ) - { - hoststat->odata.invalid++; - hoststat->odata.last_invalid = now; - break; - } - hoststat->rxw_trail = g_ntohl (data->data_trail); - } - - if (hoststat->rxw_constrained && hoststat->txw_trail > hoststat->rxw_trail_init) { - hoststat->rxw_constrained = FALSE; - } - - if ( pgm_uint32_lte ( g_ntohl (data->data_sqn), hoststat->rxw_lead ) ) { - hoststat->general.duplicate++; - break; - } else { - hoststat->rxw_lead = g_ntohl (data->data_sqn); - - hoststat->odata.tsdu += g_ntohs (skb->pgm_header->pgm_tsdu_length); - } - break; - - case PGM_RDATA: - hoststat->rdata.count++; - hoststat->rdata.bytes += skb->len; - hoststat->rdata.last = now; - break; - - case PGM_POLL: - hoststat->poll.count++; - hoststat->poll.bytes += skb->len; - hoststat->poll.last = now; - break; - - case PGM_POLR: - hoststat->polr.count++; - hoststat->polr.bytes += skb->len; - hoststat->polr.last = now; - break; - - case PGM_NAK: - hoststat->nak.count++; - hoststat->nak.bytes += skb->len; - hoststat->nak.last = now; - - is_valid = pgm_verify_nak (skb); - if (!is_valid) { - hoststat->nak.invalid++; - hoststat->nak.last_invalid = now; - } - break; - - case PGM_NNAK: - hoststat->nnak.count++; - hoststat->nnak.bytes += skb->len; - hoststat->nnak.last = now; - break; - - case PGM_NCF: - hoststat->ncf.count++; - hoststat->ncf.bytes += skb->len; - hoststat->ncf.last = now; - break; - - case PGM_SPMR: - hoststat->spmr.count++; - hoststat->spmr.bytes += skb->len; - hoststat->spmr.last = now; - - is_valid = pgm_verify_spmr (skb); - if (!is_valid) { - hoststat->spmr.invalid++; - hoststat->spmr.last_invalid = now; - } - break; - - default: - break; - } - - if (!is_valid) { - hoststat->general.invalid++; - hoststat->general.last_invalid = now; - } else { - hoststat->general.last_valid = now; - } - - pgm_free_skb (skb); - return TRUE; -} - -static gboolean -on_io_error ( - GIOChannel* source, - G_GNUC_UNUSED GIOCondition condition, - G_GNUC_UNUSED gpointer data - ) -{ - puts ("on_error."); - - GError *err; - g_io_channel_shutdown (source, FALSE, &err); - -/* remove event */ - return FALSE; -} - -/* process input commands from stdin/fd - */ - -static gboolean -on_stdin_data ( - G_GNUC_UNUSED GIOChannel* source, - G_GNUC_UNUSED GIOCondition condition, - G_GNUC_UNUSED gpointer data - ) -{ - int ch = wgetch (g_active->window); - if (ch == ERR) { - goto out; - } - -/* force redraw */ - if (ch == 12) { - clearok (curscr, TRUE); - paint_ncurses (); - goto out; - } - - if (ch == 'q') { - g_main_loop_quit(g_loop); - } - -out: - return TRUE; -} - -static gboolean -snap_stat ( - G_GNUC_UNUSED gpointer key, - gpointer value, - G_GNUC_UNUSED gpointer user_data - ) -{ - struct pgm_hoststat* hoststat = value; - -#define SNAP_STAT(name) \ - { \ - hoststat->name.snap_count = hoststat->name.count; \ - hoststat->name.snap_bytes = hoststat->name.bytes; \ - } - - SNAP_STAT(spm); - SNAP_STAT(poll); - SNAP_STAT(polr); - SNAP_STAT(odata); - SNAP_STAT(rdata); - SNAP_STAT(nak); - SNAP_STAT(nnak); - SNAP_STAT(ncf); - SNAP_STAT(spmr); - - SNAP_STAT(general); - - return FALSE; -} - -static gboolean -on_snap ( - gpointer data - ) -{ - if (!g_hosts) return TRUE; - - gettimeofday (&g_last_snap, NULL); - g_hash_table_foreach (g_hosts, (GHFunc)snap_stat, NULL); - - return TRUE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/ping.proto b/3rdparty/openpgm-svn-r1085/pgm/examples/ping.proto deleted file mode 100644 index 8c6dfd1..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/ping.proto +++ /dev/null @@ -1,47 +0,0 @@ -package example; - -message SubscriptionHeader { - required string subject = 1; -} - -message MarketDataHeader { - enum MsgType { - MSG_VERIFY = 0; - MSG_UPDATE = 1; - MSG_CORRECT = 2; - MSG_CLOSING = 3; - MSG_DROP = 4; - MSG_AGGREGATE = 5; - MSG_STATUS = 6; - MSG_CANCEL = 7; - MSG_INITIAL = 8; - } - required MsgType msg_type = 1; - enum RecType { - PING = 1; - } - required RecType rec_type = 2; - enum RecStatus { - STATUS_OK = 0; - STATUS_BAD_NAME = 1; - STATUS_BAD_LINE = 2; - STATUS_CACHE_FULL = 3; - STATUS_PERMISSION_DENIED = 4; - STATUS_PREEMPTED = 5; - STATUS_BAD_ACCESS = 6; - STATUS_TEMP_UNAVAIL = 7; - STATUS_REASSIGN = 8; - STATUS_NOSUBSCRIBERS = 9; - STATUS_EXPIRED = 10; - } - required RecStatus rec_status = 3; -} - -message Ping { - required SubscriptionHeader subscription_header = 1; - required MarketDataHeader market_data_header = 2; - required fixed64 time = 3; - required fixed64 seqno = 4; - required fixed64 latency = 5; - required bytes payload = 6; -} diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/pnonblocksyncrecv.c b/3rdparty/openpgm-svn-r1085/pgm/examples/pnonblocksyncrecv.c deleted file mode 100644 index f66454f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/pnonblocksyncrecv.c +++ /dev/null @@ -1,385 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Simple PGM receiver: poll based non-blocking synchronous receiver. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef G_OS_UNIX -# include -# include -# include -# include -#endif -#include - -/* example dependencies */ -#include -#include - - -/* typedefs */ - -/* globals */ - -static int g_port = 0; -static const char* g_network = ""; -static gboolean g_multicast_loop = FALSE; -static int g_udp_encap_port = 0; - -static int g_max_tpdu = 1500; -static int g_sqns = 100; - -static pgm_sock_t* g_sock = NULL; -static gboolean g_quit; -static int g_quit_pipe[2]; - -static void on_signal (int); -static gboolean on_startup (void); - -static int on_data (gconstpointer, size_t, struct pgm_sockaddr_t*); - - -G_GNUC_NORETURN static -void -usage ( - const char* bin - ) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); - exit (1); -} - -int -main ( - int argc, - char* argv[] - ) -{ - int e; - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - - log_init (); - g_message ("pnonblocksyncrecv"); - - if (!pgm_init (&pgm_err)) { - g_error ("Unable to start PGM engine: %s", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) - { - switch (c) { - case 'n': g_network = optarg; break; - case 's': g_port = atoi (optarg); break; - case 'p': g_udp_encap_port = atoi (optarg); break; - case 'l': g_multicast_loop = TRUE; break; - - case 'h': - case '?': usage (binary_name); - } - } - - g_quit = FALSE; -#ifdef G_OS_UNIX - e = pipe (g_quit_pipe); -#else - e = _pipe (g_quit_pipe, 4096, _O_BINARY | _O_NOINHERIT); -#endif - g_assert (0 == e); - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); - signal (SIGINT, on_signal); - signal (SIGTERM, on_signal); -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif - - if (!on_startup()) { - g_error ("startup failed"); - exit(1); - } - -/* dispatch loop */ - g_message ("entering PGM message loop ... "); - do { - struct timeval tv; - int timeout; - int n_fds = 2; - struct pollfd fds[ 1 + n_fds ]; - char buffer[4096]; - size_t len; - struct pgm_sockaddr_t from; - socklen_t fromlen = sizeof(from); - const int status = pgm_recvfrom (g_sock, - buffer, - sizeof(buffer), - 0, - &len, - &from, - &fromlen, - &pgm_err); - switch (status) { - case PGM_IO_STATUS_NORMAL: - on_data (buffer, len, &from); - break; - case PGM_IO_STATUS_TIMER_PENDING: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_TIME_REMAIN, &tv, &optlen); - } - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_RATE_REMAIN, &tv, &optlen); - } -/* fall through */ - case PGM_IO_STATUS_WOULD_BLOCK: -/* poll for next event */ -block: - timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - memset (fds, 0, sizeof(fds)); - fds[0].fd = g_quit_pipe[0]; - fds[0].events = POLLIN; - pgm_poll_info (g_sock, &fds[1], &n_fds, POLLIN); - poll (fds, 1 + n_fds, timeout /* ms */); - break; - default: - if (pgm_err) { - g_warning ("%s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_err = NULL; - } - if (PGM_IO_STATUS_ERROR == status) - break; - } - } while (!g_quit); - - g_message ("message loop terminated, cleaning up."); - -/* cleanup */ - close (g_quit_pipe[0]); - close (g_quit_pipe[1]); - - if (g_sock) { - g_message ("closing PGM socket."); - pgm_close (g_sock, TRUE); - g_sock = NULL; - } - - g_message ("PGM engine shutdown."); - pgm_shutdown (); - g_message ("finished."); - return EXIT_SUCCESS; -} - -static -void -on_signal ( - int signum - ) -{ - g_message ("on_signal (signum:%d)", signum); - g_quit = TRUE; - const char one = '1'; - const size_t writelen = write (g_quit_pipe[1], &one, sizeof(one)); - g_assert (sizeof(one) == writelen); -} - -static -gboolean -on_startup (void) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - - g_message ("startup."); - -/* parse network parameter into transport address structure */ - if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { - g_error ("parsing network parameter: %s", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - if (g_udp_encap_port) { - g_message ("create PGM/UDP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - } else { - g_message ("create PGM/IP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (g_sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int recv_only = 1, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (50), - nak_rpt_ivl = pgm_secs (2), - nak_rdata_ivl = pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50; - - pgm_setsockopt (g_sock, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - pgm_setsockopt (g_sock, PGM_PASSIVE, &passive, sizeof(passive)); - pgm_setsockopt (g_sock, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); - pgm_setsockopt (g_sock, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); - pgm_setsockopt (g_sock, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - pgm_setsockopt (g_sock, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - pgm_setsockopt (g_sock, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - pgm_setsockopt (g_sock, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - g_error ("creating GSI: %s", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (g_sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - g_error ("binding PGM socket: %s", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (g_sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (g_sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int nonblocking = 1, - multicast_loop = g_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (g_sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (g_sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (g_sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (g_sock, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); - - if (!pgm_connect (g_sock, &pgm_err)) { - g_error ("connecting PGM socket: %s", pgm_err->message); - goto err_abort; - } - - g_message ("startup complete."); - return TRUE; - -err_abort: - if (NULL != g_sock) { - pgm_close (g_sock, FALSE); - g_sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -static -int -on_data ( - gconstpointer data, - size_t len, - struct pgm_sockaddr_t* from - ) -{ -/* protect against non-null terminated strings */ - char buf[1024], tsi[PGM_TSISTRLEN]; - const size_t buflen = MIN(sizeof(buf) - 1, len); - strncpy (buf, (const char*)data, buflen); - buf[buflen] = '\0'; - pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); - - g_message ("\"%s\" (%u bytes from %s)", - buf, - (unsigned)len, - tsi); - - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/purinrecv.c b/3rdparty/openpgm-svn-r1085/pgm/examples/purinrecv.c deleted file mode 100644 index c5e4bd3..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/purinrecv.c +++ /dev/null @@ -1,474 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * プリン PGM receiver - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#ifndef _WIN32 -# include -#else -# include "getopt.h" -# define snprintf _snprintf -#endif -#include - - -/* globals */ - -static int port = 0; -static const char* network = ""; -static bool use_multicast_loop = FALSE; -static int udp_encap_port = 0; - -static int max_tpdu = 1500; -static int sqns = 100; - -static bool use_pgmcc = FALSE; -static bool use_fec = FALSE; -static int rs_k = 8; -static int rs_n = 255; - -static pgm_sock_t* sock = NULL; -static bool is_terminated = FALSE; - -#ifndef _WIN32 -static int terminate_pipe[2]; -static void on_signal (int); -#else -static HANDLE terminate_event; -static BOOL on_console_ctrl (DWORD); -#endif -#ifndef _MSC_VER -static void usage (const char*) __attribute__((__noreturn__)); -#else -static void usage (const char*); -#endif - -static bool on_startup (void); -static int on_data (const void*restrict, const size_t, const struct pgm_sockaddr_t*restrict); - - -static void -usage ( - const char* bin - ) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -c : Enable PGMCC\n"); - fprintf (stderr, " -f : Enable FEC with either proactive or ondemand parity\n"); - fprintf (stderr, " -K : Configure Reed-Solomon code (n, k)\n"); - fprintf (stderr, " -N \n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); - fprintf (stderr, " -i : List available interfaces\n"); - exit (EXIT_SUCCESS); -} - -int -main ( - int argc, - char* argv[] - ) -{ - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - -#if !defined(_WIN32) || defined(CONFIG_TARGET_WINE) - puts ("プリン プリン"); -#else - _putws (L"プリン プリン"); -#endif - - if (!pgm_init (&pgm_err)) { - fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:cf:K:N:lih")) != -1) - { - switch (c) { - case 'n': network = optarg; break; - case 's': port = atoi (optarg); break; - case 'p': udp_encap_port = atoi (optarg); break; - case 'c': use_pgmcc = TRUE; break; - case 'f': use_fec = TRUE; break; - case 'K': rs_k = atoi (optarg); break; - case 'N': rs_n = atoi (optarg); break; - case 'l': use_multicast_loop = TRUE; break; - - case 'i': - pgm_if_print_all(); - return EXIT_SUCCESS; - - case 'h': - case '?': usage (binary_name); - } - } - - if (use_fec && ( !rs_n || !rs_k )) { - fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); - usage (binary_name); - } - -/* setup signal handlers */ -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif -#ifndef _WIN32 - int e = pipe (terminate_pipe); - assert (0 == e); - signal (SIGINT, on_signal); - signal (SIGTERM, on_signal); -#else - terminate_event = CreateEvent (NULL, TRUE, FALSE, TEXT("TerminateEvent")); - SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); -#endif /* !_WIN32 */ - - if (!on_startup()) { - fprintf (stderr, "Startup failed\n"); - return EXIT_FAILURE; - } - -/* dispatch loop */ -#ifndef _WIN32 - int fds; - fd_set readfds; -#else - int n_handles = 3, recv_sock, pending_sock; - HANDLE waitHandles[ 3 ]; - DWORD dwTimeout, dwEvents; - WSAEVENT recvEvent, pendingEvent; - socklen_t socklen = sizeof(int); - - recvEvent = WSACreateEvent (); - pgm_getsockopt (sock, PGM_RECV_SOCK, &recv_sock, &socklen); - WSAEventSelect (recv_sock, recvEvent, FD_READ); - pendingEvent = WSACreateEvent (); - pgm_getsockopt (sock, PGM_PENDING_SOCK, &pending_sock, &socklen); - WSAEventSelect (pending_sock, pendingEvent, FD_READ); - - waitHandles[0] = terminate_event; - waitHandles[1] = recvEvent; - waitHandles[2] = pendingEvent; -#endif /* !_WIN32 */ - puts ("Entering PGM message loop ... "); - do { - struct timeval tv; - char buffer[4096]; - size_t len; - struct pgm_sockaddr_t from; - socklen_t fromlen = sizeof (from); - const int status = pgm_recvfrom (sock, - buffer, - sizeof(buffer), - 0, - &len, - &from, - &fromlen, - &pgm_err); - switch (status) { - case PGM_IO_STATUS_NORMAL: - on_data (buffer, len, &from); - break; - case PGM_IO_STATUS_TIMER_PENDING: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (sock, PGM_TIME_REMAIN, &tv, &optlen); - } - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (sock, PGM_RATE_REMAIN, &tv, &optlen); - } - case PGM_IO_STATUS_WOULD_BLOCK: -/* select for next event */ -block: -#ifndef _WIN32 - fds = terminate_pipe[0] + 1; - FD_ZERO(&readfds); - FD_SET(terminate_pipe[0], &readfds); - pgm_select_info (sock, &readfds, NULL, &fds); - fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); -#else - dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout); - switch (dwEvents) { - case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; - case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break; - default: break; - } -#endif /* !_WIN32 */ - break; - - default: - if (pgm_err) { - fprintf (stderr, "%s\n", pgm_err->message); - pgm_error_free (pgm_err); - pgm_err = NULL; - } - if (PGM_IO_STATUS_ERROR == status) - break; - } - } while (!is_terminated); - - puts ("Message loop terminated, cleaning up."); - -/* cleanup */ -#ifndef _WIN32 - close (terminate_pipe[0]); - close (terminate_pipe[1]); -#else - WSACloseEvent (recvEvent); - WSACloseEvent (pendingEvent); - CloseHandle (terminate_event); -#endif /* !_WIN32 */ - - if (sock) { - puts ("Destroying PGM socket."); - pgm_close (sock, TRUE); - sock = NULL; - } - - puts ("PGM engine shutdown."); - pgm_shutdown (); - puts ("finished."); - return EXIT_SUCCESS; -} - -#ifndef _WIN32 -static -void -on_signal ( - int signum - ) -{ - printf ("on_signal (signum:%d)\n", signum); - is_terminated = TRUE; - const char one = '1'; - const size_t writelen = write (terminate_pipe[1], &one, sizeof(one)); - assert (sizeof(one) == writelen); -} -#else -static -BOOL -on_console_ctrl ( - DWORD dwCtrlType - ) -{ - printf ("on_console_ctrl (dwCtrlType:%lu)\n", (unsigned long)dwCtrlType); - is_terminated = TRUE; - SetEvent (terminate_event); - return TRUE; -} -#endif /* !_WIN32 */ - -static -bool -on_startup (void) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - -/* parse network parameter into PGM socket address structure */ - if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { - fprintf (stderr, "Parsing network parameter: %s\n", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - if (udp_encap_port) { - puts ("Create PGM/UDP socket."); - if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - fprintf (stderr, "Creating PGM/UDP socket: %s\n", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (sock, PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - pgm_setsockopt (sock, PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - } else { - puts ("Create PGM/IP socket."); - if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - fprintf (stderr, "Creating PGM/IP socket: %s\n", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int recv_only = 1, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (50), - nak_rpt_ivl = pgm_secs (2), - nak_rdata_ivl = pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50; - - pgm_setsockopt (sock, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - pgm_setsockopt (sock, PGM_PASSIVE, &passive, sizeof(passive)); - pgm_setsockopt (sock, PGM_MTU, &max_tpdu, sizeof(max_tpdu)); - pgm_setsockopt (sock, PGM_RXW_SQNS, &sqns, sizeof(sqns)); - pgm_setsockopt (sock, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - pgm_setsockopt (sock, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - pgm_setsockopt (sock, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - pgm_setsockopt (sock, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - pgm_setsockopt (sock, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - pgm_setsockopt (sock, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - pgm_setsockopt (sock, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - -#ifdef I_UNDERSTAND_PGMCC_AND_FEC_ARE_NOT_SUPPORTED - if (use_pgmcc) { - struct pgm_pgmccinfo_t pgmccinfo; - pgmccinfo.ack_bo_ivl = pgm_msecs (50); - pgmccinfo.ack_c = 75; - pgmccinfo.ack_c_p = 500; - pgm_setsockopt (sock, PGM_USE_PGMCC, &pgmccinfo, sizeof(pgmccinfo)); - } - if (use_fec) { - struct pgm_fecinfo_t fecinfo; - fecinfo.block_size = rs_n; - fecinfo.proactive_packets = 0; - fecinfo.group_size = rs_k; - fecinfo.ondemand_parity_enabled = TRUE; - fecinfo.var_pktlen_enabled = FALSE; - pgm_setsockopt (sock, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); - } -#endif - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = port ? port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - fprintf (stderr, "Creating GSI: %s\n", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - fprintf (stderr, "Binding PGM socket: %s\n", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int nonblocking = 1, - multicast_loop = use_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (sock, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); - - if (!pgm_connect (sock, &pgm_err)) { - fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message); - goto err_abort; - } - - puts ("Startup complete."); - return TRUE; - -err_abort: - if (NULL != sock) { - pgm_close (sock, FALSE); - sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - if (NULL != sock) { - pgm_close (sock, FALSE); - sock = NULL; - } - return FALSE; -} - -static -int -on_data ( - const void* restrict data, - const size_t len, - const struct pgm_sockaddr_t* restrict from - ) -{ -/* protect against non-null terminated strings */ - char buf[1024], tsi[PGM_TSISTRLEN]; - const size_t buflen = MIN(sizeof(buf) - 1, len); - strncpy (buf, (const char*)data, buflen); - buf[buflen] = '\0'; - pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); -#ifndef _MSC_VER - printf ("\"%s\" (%zu bytes from %s)\n", - buf, len, tsi); -#else -/* Microsoft CRT will crash on %zu */ - printf ("\"%s\" (%u bytes from %s)\n", - buf, (unsigned)len, tsi); -#endif - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/purinrecvcc.cc b/3rdparty/openpgm-svn-r1085/pgm/examples/purinrecvcc.cc deleted file mode 100644 index 72c1d23..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/purinrecvcc.cc +++ /dev/null @@ -1,434 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * プリン PGM receiver - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#ifndef _WIN32 -# include -# include -# include -#else -# include "getopt.h" -#endif -#include - - -/* globals */ - -static int port = 0; -static const char* network = ""; -static bool use_multicast_loop = FALSE; -static int udp_encap_port = 0; - -static int max_tpdu = 1500; -static int sqns = 100; - -static bool use_fec = FALSE; -static int rs_k = 8; -static int rs_n = 255; - -static ip::pgm::endpoint* endpoint = NULL; -static ip::pgm::socket* sock = NULL; -static bool is_terminated = FALSE; - -#ifndef _WIN32 -static int terminate_pipe[2]; -static void on_signal (int); -#else -static HANDLE terminate_event; -static BOOL on_console_ctrl (DWORD); -#endif -#ifndef _MSC_VER -static void usage (const char*) __attribute__((__noreturn__)); -#else -static void usage (const char*); -#endif - -static bool on_startup (void); -static int on_data (const void*, size_t, const ip::pgm::endpoint&); - - -static void -usage ( - const char* bin - ) -{ - std::cerr << "Usage: " << bin << " [options]" << std::endl; - std::cerr << " -n : Multicast group or unicast IP address" << std::endl; - std::cerr << " -s : IP port" << std::endl; - std::cerr << " -p : Encapsulate PGM in UDP on IP port" << std::endl; - std::cerr << " -f : Enable FEC with either proactive or ondemand parity" << std::endl; - std::cerr << " -K : Configure Reed-Solomon code (n, k)" << std::endl; - std::cerr << " -N " << std::endl; - std::cerr << " -l : Enable multicast loopback and address sharing" << std::endl; - std::cerr << " -i : List available interfaces" << std::endl; - exit (EXIT_SUCCESS); -} - -int -main ( - int argc, - char* argv[] - ) -{ - cpgm::pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - -#if !defined(_WIN32) || defined(CONFIG_TARGET_WINE) - std::cout << "プリン プリン" << std::endl; -#else - std::wcout << L"プリン プリン" << std::endl; -#endif - - if (!cpgm::pgm_init (&pgm_err)) { - std::cerr << "Unable to start PGM engine: " << pgm_err->message << std::endl; - cpgm::pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = std::strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:f:K:N:lih")) != -1) - { - switch (c) { - case 'n': network = optarg; break; - case 's': port = atoi (optarg); break; - case 'p': udp_encap_port = atoi (optarg); break; - case 'f': use_fec = TRUE; break; - case 'K': rs_k = atoi (optarg); break; - case 'N': rs_n = atoi (optarg); break; - case 'l': use_multicast_loop = TRUE; break; - - case 'i': - cpgm::pgm_if_print_all(); - return EXIT_SUCCESS; - - case 'h': - case '?': usage (binary_name); - } - } - - if (use_fec && ( !rs_n || !rs_k )) { - std::cerr << "Invalid Reed-Solomon parameters RS(" << rs_n << "," << rs_k << ")." << std::endl; - usage (binary_name); - } - -/* setup signal handlers */ -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif -#ifndef _WIN32 - int e = pipe (terminate_pipe); - assert (0 == e); - signal (SIGINT, on_signal); - signal (SIGTERM, on_signal); -#else - terminate_event = CreateEvent (NULL, TRUE, FALSE, TEXT("TerminateEvent")); - SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); -#endif /* !_WIN32 */ - - if (!on_startup()) { - std::cerr << "Startup failed" << std::endl; - return EXIT_FAILURE; - } - -/* dispatch loop */ -#ifndef _WIN32 - int fds; - fd_set readfds; -#else - int n_handles = 3, recv_sock, pending_sock; - HANDLE waitHandles[ 3 ]; - DWORD dwTimeout, dwEvents; - WSAEVENT recvEvent, pendingEvent; - socklen_t socklen = sizeof(int); - - recvEvent = WSACreateEvent (); - sock->get_option (cpgm::PGM_RECV_SOCK, &recv_sock, &socklen); - WSAEventSelect (recv_sock, recvEvent, FD_READ); - pendingEvent = WSACreateEvent (); - sock->get_option (cpgm::PGM_PENDING_SOCK, &pending_sock, &socklen); - WSAEventSelect (pending_sock, pendingEvent, FD_READ); - - waitHandles[0] = terminate_event; - waitHandles[1] = recvEvent; - waitHandles[2] = pendingEvent; -#endif /* !_WIN32 */ - std::cout << "Entering PGM message loop ... " << std::endl; - do { - socklen_t optlen; - struct timeval tv; - char buffer[4096]; - size_t len; - ip::pgm::endpoint from; - const int status = sock->receive_from (buffer, - sizeof(buffer), - 0, - &len, - &from, - &pgm_err); - switch (status) { - case cpgm::PGM_IO_STATUS_NORMAL: - on_data (buffer, len, from); - break; - case cpgm::PGM_IO_STATUS_TIMER_PENDING: - optlen = sizeof (tv); - sock->get_option (cpgm::PGM_TIME_REMAIN, &tv, &optlen); - goto block; - case cpgm::PGM_IO_STATUS_RATE_LIMITED: - optlen = sizeof (tv); - sock->get_option (cpgm::PGM_RATE_REMAIN, &tv, &optlen); - case cpgm::PGM_IO_STATUS_WOULD_BLOCK: -/* select for next event */ -block: -#ifndef _WIN32 - fds = terminate_pipe[0] + 1; - FD_ZERO(&readfds); - FD_SET(terminate_pipe[0], &readfds); - pgm_select_info (sock->native(), &readfds, NULL, &fds); - fds = select (fds, &readfds, NULL, NULL, cpgm::PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); -#else - dwTimeout = cpgm::PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout); - switch (dwEvents) { - case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; - case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break; - default: break; - } -#endif /* !_WIN32 */ - break; - - default: - if (pgm_err) { - std::cerr << pgm_err->message << std::endl; - cpgm::pgm_error_free (pgm_err); - pgm_err = NULL; - } - if (cpgm::PGM_IO_STATUS_ERROR == status) - break; - } - } while (!is_terminated); - - std::cout << "Message loop terminated, cleaning up." << std::endl; - -/* cleanup */ -#ifndef _WIN32 - close (terminate_pipe[0]); - close (terminate_pipe[1]); -#else - WSACloseEvent (recvEvent); - WSACloseEvent (pendingEvent); - CloseHandle (terminate_event); -#endif /* !_WIN32 */ - - if (sock) { - std::cout << "Closing PGM socket." << std::endl; - sock->close (TRUE); - sock = NULL; - } - - std::cout << "PGM engine shutdown." << std::endl; - cpgm::pgm_shutdown (); - std::cout << "finished." << std::endl; - return EXIT_SUCCESS; -} - -#ifndef _WIN32 -static -void -on_signal ( - int signum - ) -{ - std::cout << "on_signal (signum:" << signum << ")" << std::endl; - is_terminated = TRUE; - const char one = '1'; - const size_t writelen = write (terminate_pipe[1], &one, sizeof(one)); - assert (sizeof(one) == writelen); -} -#else -static -BOOL -on_console_ctrl ( - DWORD dwCtrlType - ) -{ - std::cout << "on_console_ctrl (dwCtrlType:" << dwCtrlType << ")" << std::endl; - is_terminated = TRUE; - SetEvent (terminate_event); - return TRUE; -} -#endif /* !_WIN32 */ - -static -bool -on_startup (void) -{ - struct cpgm::pgm_addrinfo_t* res = NULL; - cpgm::pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - -/* parse network parameter into PGM socket address structure */ - if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { - std::cerr << "Parsing network parameter: " << pgm_err->message << std::endl; - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - sock = new ip::pgm::socket(); - - if (udp_encap_port) { - std::cout << "Create PGM/UDP socket." << std::endl; - if (!sock->open (sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - std::cerr << "Creating PGM/UDP socket: " << pgm_err->message << std::endl; - goto err_abort; - } - sock->set_option (cpgm::PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - sock->set_option (cpgm::PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - } else { - std::cout << "Create PGM/IP socket." << std::endl; - if (!sock->open (sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - std::cerr << "Creating PGM/IP socket: " << pgm_err->message << std::endl; - goto err_abort; - } - } - - { -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - sock->set_option (cpgm::PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - } - - cpgm::pgm_drop_superuser(); - - { -/* set PGM parameters */ - const int recv_only = 1, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (50), - nak_rpt_ivl = pgm_secs (2), - nak_rdata_ivl = pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50; - - sock->set_option (cpgm::PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - sock->set_option (cpgm::PGM_PASSIVE, &passive, sizeof(passive)); - sock->set_option (cpgm::PGM_MTU, &max_tpdu, sizeof(max_tpdu)); - sock->set_option (cpgm::PGM_RXW_SQNS, &sqns, sizeof(sqns)); - sock->set_option (cpgm::PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - sock->set_option (cpgm::PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - sock->set_option (cpgm::PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - sock->set_option (cpgm::PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - sock->set_option (cpgm::PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - sock->set_option (cpgm::PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - sock->set_option (cpgm::PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - } - if (use_fec) { - struct cpgm::pgm_fecinfo_t fecinfo; - fecinfo.block_size = rs_n; - fecinfo.proactive_packets = 0; - fecinfo.group_size = rs_k; - fecinfo.ondemand_parity_enabled = TRUE; - fecinfo.var_pktlen_enabled = FALSE; - sock->set_option (cpgm::PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); - } - -/* create global session identifier */ - endpoint = new ip::pgm::endpoint (DEFAULT_DATA_DESTINATION_PORT); - -/* assign socket to specified address */ - if (!sock->bind (*endpoint, &pgm_err)) { - std::cerr << "Binding PGM socket: " << pgm_err->message << std::endl; - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - sock->set_option (cpgm::PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - sock->set_option (cpgm::PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - - { -/* set IP parameters */ - const int nonblocking = 1, - multicast_loop = use_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - sock->set_option (cpgm::PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - sock->set_option (cpgm::PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - sock->set_option (cpgm::PGM_TOS, &dscp, sizeof(dscp)); - sock->set_option (cpgm::PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); - } - - if (!sock->connect (&pgm_err)) { - std::cerr << "Connecting PGM socket: " << pgm_err->message << std::endl; - goto err_abort; - } - - std::cout << "Startup complete." << std::endl; - return TRUE; - -err_abort: - if (NULL != sock) { - sock->close (FALSE); - sock = NULL; - } - if (NULL != res) { - cpgm::pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - cpgm::pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -static -int -on_data ( - const void* data, - size_t len, - const ip::pgm::endpoint& from - ) -{ -/* protect against non-null terminated strings */ - char buf[1024], tsi[PGM_TSISTRLEN]; - const size_t buflen = MIN(sizeof(buf) - 1, len); - strncpy (buf, (char*)data, buflen); - buf[buflen] = '\0'; - cpgm::pgm_tsi_print_r (from.address(), tsi, sizeof(tsi)); - std::cout << "\"" << buf << "\" (" << len << " bytes from " << tsi << ")" << std::endl; - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/purinsend.c b/3rdparty/openpgm-svn-r1085/pgm/examples/purinsend.c deleted file mode 100644 index 811c14c..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/purinsend.c +++ /dev/null @@ -1,280 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * プリン PGM sender - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#ifndef _WIN32 -# include -#else -# include "getopt.h" -# define snprintf _snprintf -#endif -#include - - -/* globals */ - -static int port = 0; -static const char* network = ""; -static bool use_multicast_loop = FALSE; -static int udp_encap_port = 0; - -static int max_tpdu = 1500; -static int max_rte = 400*1000; /* very conservative rate, 2.5mb/s */ -static int sqns = 100; - -static bool use_fec = FALSE; -static int rs_k = 8; -static int rs_n = 255; - -static pgm_sock_t* sock = NULL; - -#ifndef _MSC_VER -static void usage (const char*) __attribute__((__noreturn__)); -#else -static void usage (const char*); -#endif -static bool create_sock (void); - - -static void -usage ( - const char* bin - ) -{ - fprintf (stderr, "Usage: %s [options] message\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -r : Regulate to rate bytes per second\n"); - fprintf (stderr, " -f : Enable FEC with either proactive or ondemand parity\n"); - fprintf (stderr, " -K : Configure Reed-Solomon code (n, k)\n"); - fprintf (stderr, " -N \n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); - fprintf (stderr, " -i : List available interfaces\n"); - exit (EXIT_SUCCESS); -} - -int -main ( - int argc, - char *argv[] - ) -{ - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - - if (!pgm_init (&pgm_err)) { - fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:r:f:K:N:lih")) != -1) - { - switch (c) { - case 'n': network = optarg; break; - case 's': port = atoi (optarg); break; - case 'p': udp_encap_port = atoi (optarg); break; - case 'r': max_rte = atoi (optarg); break; - case 'f': use_fec = TRUE; break; - case 'K': rs_k = atoi (optarg); break; - case 'N': rs_n = atoi (optarg); break; - - case 'l': use_multicast_loop = TRUE; break; - - case 'i': - pgm_if_print_all(); - return EXIT_SUCCESS; - - case 'h': - case '?': - usage (binary_name); - } - } - - if (use_fec && ( !rs_n || !rs_k )) { - fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); - usage (binary_name); - } - - if (create_sock()) - { - while (optind < argc) { - const int status = pgm_send (sock, argv[optind], strlen (argv[optind]) + 1, NULL); - if (PGM_IO_STATUS_NORMAL != status) { - fprintf (stderr, "pgm_send() failed.\n"); - } - optind++; - } - } - -/* cleanup */ - if (sock) { - pgm_close (sock, TRUE); - sock = NULL; - } - pgm_shutdown(); - return EXIT_SUCCESS; -} - -static -bool -create_sock (void) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - -/* parse network parameter into PGM socket address structure */ - if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { - fprintf (stderr, "Parsing network parameter: %s\n", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - if (udp_encap_port) { - if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - fprintf (stderr, "Creating PGM/UDP socket: %s\n", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (sock, PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - pgm_setsockopt (sock, PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - } else { - if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - fprintf (stderr, "Creating PGM/IP socket: %s\n", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int send_only = 1, - ambient_spm = pgm_secs (30), - heartbeat_spm[] = { pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (1300), - pgm_secs (7), - pgm_secs (16), - pgm_secs (25), - pgm_secs (30) }; - - pgm_setsockopt (sock, PGM_SEND_ONLY, &send_only, sizeof(send_only)); - pgm_setsockopt (sock, PGM_MTU, &max_tpdu, sizeof(max_tpdu)); - pgm_setsockopt (sock, PGM_TXW_SQNS, &sqns, sizeof(sqns)); - pgm_setsockopt (sock, PGM_TXW_MAX_RTE, &max_rte, sizeof(max_rte)); - pgm_setsockopt (sock, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm)); - pgm_setsockopt (sock, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm)); - if (use_fec) { - struct pgm_fecinfo_t fecinfo; - fecinfo.block_size = rs_n; - fecinfo.proactive_packets = 0; - fecinfo.group_size = rs_k; - fecinfo.ondemand_parity_enabled = TRUE; - fecinfo.var_pktlen_enabled = TRUE; - pgm_setsockopt (sock, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); - } - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = port ? port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - fprintf (stderr, "Creating GSI: %s\n", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - fprintf (stderr, "Binding PGM socket: %s\n", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int blocking = 0, - multicast_loop = use_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (sock, PGM_NOBLOCK, &blocking, sizeof(blocking)); - - if (!pgm_connect (sock, &pgm_err)) { - fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message); - goto err_abort; - } - - return TRUE; - -err_abort: - if (NULL != sock) { - pgm_close (sock, FALSE); - sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/purinsendcc.cc b/3rdparty/openpgm-svn-r1085/pgm/examples/purinsendcc.cc deleted file mode 100644 index fe3c430..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/purinsendcc.cc +++ /dev/null @@ -1,269 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * プリン PGM sender - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#ifndef _WIN32 -# include -# include -#else -# include "getopt.h" -#endif -#include - - -/* globals */ - -static int port = 0; -static const char* network = ""; -static bool use_multicast_loop = FALSE; -static int udp_encap_port = 0; - -static int max_tpdu = 1500; -static int max_rte = 400*1000; /* very conservative rate, 2.5mb/s */ -static int sqns = 100; - -static bool use_fec = FALSE; -static int rs_k = 8; -static int rs_n = 255; - -static ip::pgm::endpoint* endpoint = NULL; -static ip::pgm::socket* sock = NULL; - -#ifndef _MSC_VER -static void usage (const char*) __attribute__((__noreturn__)); -#else -static void usage (const char*); -#endif -static bool create_sock (void); - - -static void -usage ( - const char* bin - ) -{ - std::cerr << "Usage: " << bin << " [options] message" << std::endl; - std::cerr << " -n : Multicast group or unicast IP address" << std::endl; - std::cerr << " -s : IP port" << std::endl; - std::cerr << " -p : Encapsulate PGM in UDP on IP port" << std::endl; - std::cerr << " -r : Regulate to rate bytes per second" << std::endl; - std::cerr << " -f : Enable FEC with either proactive or ondemand parity" << std::endl; - std::cerr << " -K : Configure Reed-Solomon code (n, k)" << std::endl; - std::cerr << " -N " << std::endl; - std::cerr << " -l : Enable multicast loopback and address sharing" << std::endl; - std::cerr << " -i : List available interfaces" << std::endl; - exit (EXIT_SUCCESS); -} - -int -main ( - int argc, - char *argv[] - ) -{ - cpgm::pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - - if (!cpgm::pgm_init (&pgm_err)) { - std::cerr << "Unable to start PGM engine: " << pgm_err->message << std::endl; - cpgm::pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:r:f:K:N:lih")) != -1) - { - switch (c) { - case 'n': network = optarg; break; - case 's': port = atoi (optarg); break; - case 'p': udp_encap_port = atoi (optarg); break; - case 'r': max_rte = atoi (optarg); break; - case 'f': use_fec = TRUE; break; - case 'K': rs_k = atoi (optarg); break; - case 'N': rs_n = atoi (optarg); break; - - case 'l': use_multicast_loop = TRUE; break; - - case 'i': - cpgm::pgm_if_print_all(); - return EXIT_SUCCESS; - - case 'h': - case '?': - usage (binary_name); - } - } - - if (use_fec && ( !rs_n || !rs_k )) { - std::cerr << "Invalid Reed-Solomon parameters RS(" << rs_n << "," << rs_k << ")." << std::endl; - usage (binary_name); - } - - if (create_sock()) - { - while (optind < argc) { - const int status = sock->send (argv[optind], strlen (argv[optind]) + 1, NULL); - if (cpgm::PGM_IO_STATUS_NORMAL != status) { - std::cerr << "pgm_send() failed.." << std::endl; - } - optind++; - } - } - -/* cleanup */ - if (sock) { - sock->close (TRUE); - sock = NULL; - } - cpgm::pgm_shutdown(); - return EXIT_SUCCESS; -} - -static -bool -create_sock (void) -{ - struct cpgm::pgm_addrinfo_t* res = NULL; - cpgm::pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - -/* parse network parameter into PGM socket address structure */ - if (!cpgm::pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { - std::cerr << "Parsing network parameter: " << pgm_err->message << std::endl; - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - sock = new ip::pgm::socket(); - - if (udp_encap_port) { - if (!sock->open (sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - std::cerr << "Creating PGM/UDP socket: " << pgm_err->message << std::endl; - goto err_abort; - } - sock->set_option (cpgm::PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - sock->set_option (cpgm::PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - } else { - if (!sock->open (sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - std::cerr << "Creating PGM/IP socket: " << pgm_err->message << std::endl; - goto err_abort; - } - } - - { -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - sock->set_option (cpgm::PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - } - - cpgm::pgm_drop_superuser(); - - { -/* set PGM parameters */ - const int send_only = 1, - ambient_spm = pgm_secs (30), - heartbeat_spm[] = { pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (100), - pgm_msecs (1300), - pgm_secs (7), - pgm_secs (16), - pgm_secs (25), - pgm_secs (30) }; - - sock->set_option (cpgm::PGM_SEND_ONLY, &send_only, sizeof(send_only)); - sock->set_option (cpgm::PGM_MTU, &max_tpdu, sizeof(max_tpdu)); - sock->set_option (cpgm::PGM_TXW_SQNS, &sqns, sizeof(sqns)); - sock->set_option (cpgm::PGM_TXW_MAX_RTE, &max_rte, sizeof(max_rte)); - sock->set_option (cpgm::PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm)); - sock->set_option (cpgm::PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm)); - } - if (use_fec) { - struct cpgm::pgm_fecinfo_t fecinfo; - fecinfo.block_size = rs_n; - fecinfo.proactive_packets = 0; - fecinfo.group_size = rs_k; - fecinfo.ondemand_parity_enabled = TRUE; - fecinfo.var_pktlen_enabled = TRUE; - sock->set_option (cpgm::PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); - } - -/* create global session identifier */ - endpoint = new ip::pgm::endpoint (DEFAULT_DATA_DESTINATION_PORT); - -/* assign socket to specified address */ - if (!sock->bind (*endpoint, &pgm_err)) { - std::cerr << "Binding PGM socket: " << pgm_err->message << std::endl; - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - sock->set_option (cpgm::PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - sock->set_option (cpgm::PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - cpgm::pgm_freeaddrinfo (res); - - { -/* set IP parameters */ - const int blocking = 0, - multicast_loop = use_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - sock->set_option (cpgm::PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - sock->set_option (cpgm::PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - sock->set_option (cpgm::PGM_TOS, &dscp, sizeof(dscp)); - sock->set_option (cpgm::PGM_NOBLOCK, &blocking, sizeof(blocking)); - } - - if (!sock->connect (&pgm_err)) { - fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message); - goto err_abort; - } - - return TRUE; - -err_abort: - if (NULL != sock) { - sock->close (FALSE); - sock = NULL; - } - if (NULL != res) { - cpgm::pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - cpgm::pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/shortcakerecv.c b/3rdparty/openpgm-svn-r1085/pgm/examples/shortcakerecv.c deleted file mode 100644 index 87ce8dc..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/shortcakerecv.c +++ /dev/null @@ -1,430 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * ショートケーキ PGM receiver - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#ifndef _WIN32 -# include -#else -# include "getopt.h" -# define snprintf _snprintf -#endif -#include - -#include "async.h" - - -/* globals */ - -static int port = 0; -static const char* network = ""; -static bool use_multicast_loop = FALSE; -static int udp_encap_port = 0; - -static int max_tpdu = 1500; -static int sqns = 100; - -static bool use_fec = FALSE; -static int rs_k = 8; -static int rs_n = 255; - -static pgm_sock_t* sock = NULL; -static async_t* async = NULL; -static bool is_terminated = FALSE; - -#ifndef _WIN32 -static int terminate_pipe[2]; -static void on_signal (int); -#else -static HANDLE terminate_event; -static BOOL on_console_ctrl (DWORD); -#endif -#ifndef _MSC_VER -static void usage (const char*) __attribute__((__noreturn__)); -#else -static void usage (const char*); -#endif - -static bool on_startup (void); -static int on_data (const void*restrict, const size_t, const struct pgm_sockaddr_t*restrict); - - -static void -usage ( - const char* bin - ) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -f : Enable FEC with either proactive or ondemand parity\n"); - fprintf (stderr, " -K : Configure Reed-Solomon code (n, k)\n"); - fprintf (stderr, " -N \n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); - fprintf (stderr, " -i : List available interfaces\n"); - exit (EXIT_SUCCESS); -} - -int -main ( - int argc, - char* argv[] - ) -{ - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - -#if !defined(_WIN32) || defined(CONFIG_TARGET_WINE) - puts ("いちごのショートケーキ"); -#else - _putws (L"いちごのショートケーキ"); -#endif - - if (!pgm_init (&pgm_err)) { - fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:f:K:N:lih")) != -1) - { - switch (c) { - case 'n': network = optarg; break; - case 's': port = atoi (optarg); break; - case 'p': udp_encap_port = atoi (optarg); break; - case 'f': use_fec = TRUE; break; - case 'K': rs_k = atoi (optarg); break; - case 'N': rs_n = atoi (optarg); break; - case 'l': use_multicast_loop = TRUE; break; - - case 'i': - pgm_if_print_all(); - return EXIT_SUCCESS; - - case 'h': - case '?': usage (binary_name); - } - } - - if (use_fec && ( !rs_n || !rs_k )) { - fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); - usage (binary_name); - } - -/* setup signal handlers */ -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif -#ifndef _WIN32 - int e = pipe (terminate_pipe); - assert (0 == e); - signal (SIGINT, on_signal); - signal (SIGTERM, on_signal); -#else - terminate_event = CreateEvent (NULL, TRUE, FALSE, TEXT("TerminateEvent")); - SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); -#endif /* !_WIN32 */ - - if (!on_startup()) { - fprintf (stderr, "Startup failed\n"); - return EXIT_FAILURE; - } - -/* dispatch loop */ -#ifndef _WIN32 - int fds, read_fd = async_get_fd (async); - fd_set readfds; -#else - int n_handles = 2; - HANDLE waitHandles[ 2 ]; - DWORD dwEvents; - WSAEVENT recvEvent; - - recvEvent = async_get_event (async); - - waitHandles[0] = terminate_event; - waitHandles[1] = recvEvent; -#endif /* !_WIN32 */ - puts ("Entering PGM message loop ... "); - do { - char buffer[4096]; - struct pgm_sockaddr_t from; - socklen_t fromlen = sizeof (from); - const ssize_t len = async_recvfrom (async, - buffer, - sizeof(buffer), - &from, - &fromlen); - if (len >= 0) { - on_data (buffer, len, &from); - } else { -#ifndef _WIN32 - fds = MAX(terminate_pipe[0], read_fd) + 1; - FD_ZERO(&readfds); - FD_SET(terminate_pipe[0], &readfds); - FD_SET(read_fd, &readfds); - fds = select (fds, &readfds, NULL, NULL, NULL); -#else - dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, INFINITE); - switch (dwEvents) { - case WAIT_OBJECT_0+1: ResetEvent (recvEvent); break; - default: break; - } -#endif /* _WIN32 */ - } - } while (!is_terminated); - - puts ("Message loop terminated, cleaning up."); - -/* cleanup */ -#ifndef _WIN32 - close (terminate_pipe[0]); - close (terminate_pipe[1]); -#else - CloseHandle (terminate_event); -#endif /* !_WIN32 */ - - if (async) { - puts ("Destroying asynchronous queue."); - async_destroy (async); - async = NULL; - } - - if (sock) { - puts ("Closing PGM socket."); - pgm_close (sock, TRUE); - sock = NULL; - } - - puts ("PGM engine shutdown."); - pgm_shutdown (); - puts ("finished."); - return EXIT_SUCCESS; -} - -#ifndef _WIN32 -static -void -on_signal ( - int signum - ) -{ - printf ("on_signal (signum:%d)\n", signum); - is_terminated = TRUE; - const char one = '1'; - const size_t writelen = write (terminate_pipe[1], &one, sizeof(one)); - assert (sizeof(one) == writelen); -} -#else -static -BOOL -on_console_ctrl ( - DWORD dwCtrlType - ) -{ - printf ("on_console_ctrl (dwCtrlType:%lu)\n", (unsigned long)dwCtrlType); - is_terminated = TRUE; - SetEvent (terminate_event); - return TRUE; -} -#endif /* !_WIN32 */ - -static -bool -on_startup (void) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - -/* parse network parameter into PGM socket address structure */ - if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { - fprintf (stderr, "Parsing network parameter: %s\n", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - puts ("Create PGM socket."); - if (udp_encap_port) { - if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - fprintf (stderr, "Creating PGM/UDP socket: %s\n", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (sock, PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - pgm_setsockopt (sock, PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); - } else { - if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - fprintf (stderr, "Creating PGM/IP socket: %s\n", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int recv_only = 1, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (50), - nak_rpt_ivl = pgm_secs (2), - nak_rdata_ivl = pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50; - - pgm_setsockopt (sock, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - pgm_setsockopt (sock, PGM_PASSIVE, &passive, sizeof(passive)); - pgm_setsockopt (sock, PGM_MTU, &max_tpdu, sizeof(max_tpdu)); - pgm_setsockopt (sock, PGM_RXW_SQNS, &sqns, sizeof(sqns)); - pgm_setsockopt (sock, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - pgm_setsockopt (sock, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - pgm_setsockopt (sock, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - pgm_setsockopt (sock, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - pgm_setsockopt (sock, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - pgm_setsockopt (sock, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - pgm_setsockopt (sock, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - if (use_fec) { - struct pgm_fecinfo_t fecinfo; - fecinfo.block_size = rs_n; - fecinfo.proactive_packets = 0; - fecinfo.group_size = rs_k; - fecinfo.ondemand_parity_enabled = TRUE; - fecinfo.var_pktlen_enabled = TRUE; - pgm_setsockopt (sock, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); - } - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = port ? port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - fprintf (stderr, "Creating GSI: %s\n", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - fprintf (stderr, "Binding PGM socket: %s\n", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int nonblocking = 1, - multicast_loop = use_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (sock, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); - - if (!pgm_connect (sock, &pgm_err)) { - fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message); - goto err_abort; - } - -/* wrap bound socket in asynchronous queue */ - if (0 != async_create (&async, sock)) { - fprintf (stderr, "Creating asynchronous queue failed: %s\n", strerror(errno)); - goto err_abort; - } - - puts ("Startup complete."); - return TRUE; - -err_abort: - if (NULL != sock) { - pgm_close (sock, FALSE); - sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -static -int -on_data ( - const void* restrict data, - const size_t len, - const struct pgm_sockaddr_t* restrict from - ) -{ -/* protect against non-null terminated strings */ - char buf[1024], tsi[PGM_TSISTRLEN]; - const size_t buflen = MIN(sizeof(buf) - 1, len); - strncpy (buf, (const char*)data, buflen); - buf[buflen] = '\0'; - pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); -#ifndef _MSC_VER - printf ("\"%s\" (%zu bytes from %s)\n", - buf, len, tsi); -#else -/* Microsoft CRT will crash on %zu */ - printf ("\"%s\" (%u bytes from %s)\n", - buf, (unsigned)len, tsi); -#endif - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/examples/snonblocksyncrecv.c b/3rdparty/openpgm-svn-r1085/pgm/examples/snonblocksyncrecv.c deleted file mode 100644 index 434f72d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/examples/snonblocksyncrecv.c +++ /dev/null @@ -1,435 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Simple PGM receiver: select based non-blocking synchronous receiver. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef G_OS_UNIX -# include -# include -# include -# include -#endif -#include - -/* example dependencies */ -#include -#include - - -/* typedefs */ - -/* globals */ - -static int g_port = 0; -static const char* g_network = ""; -static gboolean g_multicast_loop = FALSE; -static int g_udp_encap_port = 0; - -static int g_max_tpdu = 1500; -static int g_sqns = 100; - -static pgm_sock_t* g_sock = NULL; -static gboolean g_quit; - -#ifdef G_OS_UNIX -static int g_quit_pipe[2]; -static void on_signal (int); -#else -static HANDLE g_quit_event; -static BOOL on_console_ctrl (DWORD); -#endif - -static gboolean on_startup (void); - -static int on_data (gconstpointer, size_t, struct pgm_sockaddr_t*); - - -G_GNUC_NORETURN static -void -usage ( - const char* bin - ) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); - fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); - exit (1); -} - -int -main ( - int argc, - char* argv[] - ) -{ - int e; - pgm_error_t* pgm_err = NULL; - - setlocale (LC_ALL, ""); - - log_init (); - g_message ("snonblocksyncrecv"); - - if (!pgm_init (&pgm_err)) { - g_error ("Unable to start PGM engine: %s", pgm_err->message); - pgm_error_free (pgm_err); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) - { - switch (c) { - case 'n': g_network = optarg; break; - case 's': g_port = atoi (optarg); break; - case 'p': g_udp_encap_port = atoi (optarg); break; - case 'l': g_multicast_loop = TRUE; break; - - case 'h': - case '?': usage (binary_name); - } - } - - g_quit = FALSE; - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); -#ifdef SIGHUP - signal (SIGHUP, SIG_IGN); -#endif -#ifdef G_OS_UNIX - e = pipe (g_quit_pipe); - g_assert (0 == e); - signal (SIGINT, on_signal); - signal (SIGTERM, on_signal); -#else - g_quit_event = CreateEvent (NULL, TRUE, FALSE, TEXT("QuitEvent")); - SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); -#endif /* !G_OS_UNIX */ - - if (!on_startup()) { - g_error ("startup failed"); - exit(1); - } - -/* dispatch loop */ -#ifdef G_OS_UNIX - int fds; - fd_set readfds; -#else - int n_handles = 3; - HANDLE waitHandles[ n_handles ]; - DWORD dwTimeout, dwEvents; - WSAEVENT recvEvent, pendingEvent; - - recvEvent = WSACreateEvent (); - WSAEventSelect (pgm_transport_get_recv_fd (g_transport), recvEvent, FD_READ); - pendingEvent = WSACreateEvent (); - WSAEventSelect (pgm_transport_get_pending_fd (g_transport), pendingEvent, FD_READ); - - waitHandles[0] = g_quit_event; - waitHandles[1] = recvEvent; - waitHandles[2] = pendingEvent; -#endif /* !G_OS_UNIX */ - g_message ("entering PGM message loop ... "); - do { - struct timeval tv; - char buffer[4096]; - size_t len; - struct pgm_sockaddr_t from; - socklen_t fromlen = sizeof(from); - const int status = pgm_recvfrom (g_sock, - buffer, - sizeof(buffer), - 0, - &len, - &from, - &fromlen, - &pgm_err); - switch (status) { - case PGM_IO_STATUS_NORMAL: - on_data (buffer, len, &from); - break; - case PGM_IO_STATUS_TIMER_PENDING: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_TIME_REMAIN, &tv, &optlen); - } - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - { - socklen_t optlen = sizeof (tv); - pgm_getsockopt (g_sock, PGM_RATE_REMAIN, &tv, &optlen); - } -/* fall through */ - case PGM_IO_STATUS_WOULD_BLOCK: -/* select for next event */ -block: -#ifdef G_OS_UNIX - fds = g_quit_pipe[0] + 1; - FD_ZERO(&readfds); - FD_SET(g_quit_pipe[0], &readfds); - pgm_select_info (g_sock, &readfds, NULL, &fds); - fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); -#else - dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout); - switch (dwEvents) { - case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; - case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break; - default: break; - } -#endif /* !G_OS_UNIX */ - break; - - default: - if (pgm_err) { - g_warning ("%s", pgm_err->message); - pgm_error_free (pgm_err); - pgm_err = NULL; - } - if (PGM_IO_STATUS_ERROR == status) - break; - } - } while (!g_quit); - - g_message ("message loop terminated, cleaning up."); - -/* cleanup */ -#ifdef G_OS_UNIX - close (g_quit_pipe[0]); - close (g_quit_pipe[1]); -#else - WSACloseEvent (recvEvent); - WSACloseEvent (pendingEvent); - CloseHandle (g_quit_event); -#endif /* !G_OS_UNIX */ - - if (g_sock) { - g_message ("closing PGM socket."); - pgm_close (g_sock, TRUE); - g_sock = NULL; - } - - g_message ("PGM engine shutdown."); - pgm_shutdown (); - g_message ("finished."); - return EXIT_SUCCESS; -} - -#ifdef G_OS_UNIX -static -void -on_signal ( - int signum - ) -{ - g_message ("on_signal (signum:%d)", signum); - g_quit = TRUE; - const char one = '1'; - const size_t writelen = write (g_quit_pipe[1], &one, sizeof(one)); - g_assert (sizeof(one) == writelen); -} -#else -static -BOOL -on_console_ctrl ( - DWORD dwCtrlType - ) -{ - g_message ("on_console_ctrl (dwCtrlType:%lu)", (unsigned long)dwCtrlType); - SetEvent (g_quit_event); - return TRUE; -} -#endif /* !G_OS_UNIX */ - -static -gboolean -on_startup (void) -{ - struct pgm_addrinfo_t* res = NULL; - pgm_error_t* pgm_err = NULL; - sa_family_t sa_family = AF_UNSPEC; - - g_message ("startup."); - -/* parse network parameter into transport address structure */ - if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { - g_error ("parsing network parameter: %s", pgm_err->message); - goto err_abort; - } - - sa_family = res->ai_send_addrs[0].gsr_group.ss_family; - - if (g_udp_encap_port) { - g_message ("create PGM/UDP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - pgm_setsockopt (g_sock, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); - } else { - g_message ("create PGM/IP socket."); - if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { - g_error ("socket: %s", pgm_err->message); - goto err_abort; - } - } - -/* Use RFC 2113 tagging for PGM Router Assist */ - const int no_router_assist = 0; - pgm_setsockopt (g_sock, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); - - pgm_drop_superuser(); - -/* set PGM parameters */ - const int recv_only = 1, - passive = 0, - peer_expiry = pgm_secs (300), - spmr_expiry = pgm_msecs (250), - nak_bo_ivl = pgm_msecs (50), - nak_rpt_ivl = pgm_secs (2), - nak_rdata_ivl = pgm_secs (2), - nak_data_retries = 50, - nak_ncf_retries = 50; - - pgm_setsockopt (g_sock, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); - pgm_setsockopt (g_sock, PGM_PASSIVE, &passive, sizeof(passive)); - pgm_setsockopt (g_sock, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); - pgm_setsockopt (g_sock, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); - pgm_setsockopt (g_sock, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); - pgm_setsockopt (g_sock, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); - pgm_setsockopt (g_sock, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); - pgm_setsockopt (g_sock, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); - pgm_setsockopt (g_sock, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); - -/* create global session identifier */ - struct pgm_sockaddr_t addr; - memset (&addr, 0, sizeof(addr)); - addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; - addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; - if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { - g_error ("creating GSI: %s", pgm_err->message); - goto err_abort; - } - -/* assign socket to specified address */ - struct pgm_interface_req_t if_req; - memset (&if_req, 0, sizeof(if_req)); - if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; - if_req.ir_scope_id = 0; - if (AF_INET6 == sa_family) { - struct sockaddr_in6 sa6; - memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); - if_req.ir_scope_id = sa6.sin6_scope_id; - } - if (!pgm_bind3 (g_sock, - &addr, sizeof(addr), - &if_req, sizeof(if_req), /* tx interface */ - &if_req, sizeof(if_req), /* rx interface */ - &pgm_err)) - { - g_error ("binding PGM socket: %s", pgm_err->message); - goto err_abort; - } - -/* join IP multicast groups */ - for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) - pgm_setsockopt (g_sock, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); - pgm_setsockopt (g_sock, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); - pgm_freeaddrinfo (res); - -/* set IP parameters */ - const int nonblocking = 1, - multicast_loop = g_multicast_loop ? 1 : 0, - multicast_hops = 16, - dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ - - pgm_setsockopt (g_sock, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); - pgm_setsockopt (g_sock, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); - if (AF_INET6 != sa_family) - pgm_setsockopt (g_sock, PGM_TOS, &dscp, sizeof(dscp)); - pgm_setsockopt (g_sock, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); - - if (!pgm_connect (g_sock, &pgm_err)) { - g_error ("connecting PGM socket: %s", pgm_err->message); - goto err_abort; - } - - g_message ("startup complete."); - return TRUE; - -err_abort: - if (NULL != g_sock) { - pgm_close (g_sock, FALSE); - g_sock = NULL; - } - if (NULL != res) { - pgm_freeaddrinfo (res); - res = NULL; - } - if (NULL != pgm_err) { - pgm_error_free (pgm_err); - pgm_err = NULL; - } - return FALSE; -} - -static -int -on_data ( - gconstpointer data, - size_t len, - struct pgm_sockaddr_t* from - ) -{ -/* protect against non-null terminated strings */ - char buf[1024], tsi[PGM_TSISTRLEN]; - const size_t buflen = MIN(sizeof(buf) - 1, len); - strncpy (buf, (const char*)data, buflen); - buf[buflen] = '\0'; - pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); - - g_message ("\"%s\" (%u bytes from %s)", - buf, - (unsigned)len, - tsi); - - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/fec-block.txt b/3rdparty/openpgm-svn-r1085/pgm/fec-block.txt deleted file mode 100644 index 8278fb6..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/fec-block.txt +++ /dev/null @@ -1,66 +0,0 @@ -from rfc5052 ------------- - - -step one: - - Input: - - B -- Maximum Source Block Length, i.e., the maximum number of source - symbols per source block - - L -- Transfer Length in octets - - E -- Encoding Symbol Length in octets - - Output: - - T -- the number of source symbols in the object. - - N -- the number of source blocks into which the object shall be - partitioned. - - Algorithm: - - 1. The number of source symbols in the transport object is computed - as T = ceil[L/E]. - - 2. The transport object shall be partitioned into N = ceil[T/B] - source blocks. - - -B = maximum TPDU - IP header ( - UDP header ) - PGM header -L = APDU length (pgm_transport_send length parameter). -E = 1 (fixed). - -T = ceil( L / E ) = ceil( L / 1 ) = L -N = ceil( T / B ) = ceil( L / B ) - -step two: - - Input: - - T -- the number of source symbols in the object. - - N -- the number of source blocks into which the object is - partitioned. - - Output: - - I -- the number of larger source blocks. - - A_large -- the length of each of the larger source blocks in - symbols. - - A_small -- the length of each of the smaller source blocks in - symbols. - - Algorithm: - - 1. A_large = ceil[T/N] - - 2. A_small = floor[T/N] - - 3. I = T - A_small * N - - diff --git a/3rdparty/openpgm-svn-r1085/pgm/fec.txt b/3rdparty/openpgm-svn-r1085/pgm/fec.txt deleted file mode 100644 index b83590d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/fec.txt +++ /dev/null @@ -1,77 +0,0 @@ -pkt:k=1 - -non-parity - -rs eqn: - -n = 255 -k = 2t -255 = 2k -k = 128 -=> 2t = 128 - --------------------------------------------------------------------------------- - -1456, 1442 - -pkt:k=2 ( 2 data packets ) - -1 packet loss: - -pkt:h=1 -pkt:n=3 - -rs eqn: - -n = 255 -# reed-solomon codes = tsdu / n -k = 2 4 6 ... 254 -=> 2t = 1 2 3 127 (k/2) - -255 = k + (k/2) -510 = 2k + k -510 = 3k -170 = k -=> 2t = 85 - -2 packet loss: - -pkt:h=2 pkts -pkt:n=4 pkts - --------------------------------------------------------------------------------- - -pkt:k=4 ( 4 data packets ) - -1 packet loss: - -255 = k + (k/4) -k = 51 -2t = 13 (rounded up) - --------------------------------------------------------------------------------- - -pkt:k=8 ( 8 data packets ) - -1 packet loss: - -255 = k + (k/8) -k = 29 -2t = 4 (rounded up) - --------------------------------------------------------------------------------- - -pkt:k=16 ( 16 data packets ) - -1 packet loss: - -255 = k + (k/16) -k = 15 -2t = 1 (invalid?) - -2 packet loss: - -255 = k + (2k/16) -k = 29 -2t = 4 - diff --git a/3rdparty/openpgm-svn-r1085/pgm/galois_generator.pl b/3rdparty/openpgm-svn-r1085/pgm/galois_generator.pl deleted file mode 100755 index b3f531d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/galois_generator.pl +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/perl -# -# Galois field table generator. -# -# Copyright (c) 2006-2010 Miru Limited. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -use strict; - -my $GF_ELEMENT_BYTES = 1; -my $GF_ELEMENT_BITS = 8 * $GF_ELEMENT_BYTES; -my $GF_NO_ELEMENTS = 1 << $GF_ELEMENT_BITS; -my $GF_MAX = $GF_NO_ELEMENTS - 1; - -my $GF_GENERATOR = 0x11d; - -my @gflog; -my @gfantilog; - -my $j = 1; - -for (my $i = 0; $i < $GF_MAX; $i++) -{ - $gflog[ $j ] = $i; - $gfantilog[ $i ] = $j; - - $j <<= 1; - if ($j & $GF_NO_ELEMENTS) { - $j ^= $GF_GENERATOR; - } -} - -$gflog[ 0 ] = $GF_MAX; -$gfantilog[ $GF_MAX ] = 0; - -print< - - -/* globals */ - -const pgm_gf8_t pgm_gflog[PGM_GF_NO_ELEMENTS] = -{ -MOO - -# print out y = log₂(x) table -for (my $i = 0; $i < $GF_NO_ELEMENTS; $i++) -{ - print "\t" if ($i % 8 == 0); - print sprintf("0x%2.2x", $gflog[ $i ]); - print ',' unless ($i == $GF_MAX); - print ( (($i % 8) == 7) ? "\n" : ' ' ); -} - -print<= $GF_MAX) ? $gfantilog[ $sum - $GF_MAX ] : $gfantilog[ $sum ]; -} - -# print out multiplication table z = x • y -for (my $i = 0; $i < $GF_NO_ELEMENTS; $i++) -{ - for (my $j = 0; $j < $GF_NO_ELEMENTS; $j++) - { - print "\t" if ($j % 8 == 0); - print sprintf("0x%2.2x", gfmul( $i, $j )); - print ',' unless ($i == $GF_MAX && $j == $GF_MAX); - print ( (($j % 8) == 7) ? "\n" : ' ' ); - } -} - -print<) { - chomp; - if (/^(Function|File) '(.+)'/) { - $type = $1; - $target = $2; - } elsif (/^Lines executed:(\d+\.\d+)% of (\d+)/) { -# print "$type,$target,$1,$2\n"; - if ($type cmp 'File') { - $files{$target} = $1; - } else { - $functions{$target} = $1; - } - } -} - -#@sorted = sort { $files{$a} <=> $files{$b} } keys %files; -#foreach $name (@sorted) -#{ -# print "$name:$files{$name}\n"; -#} -@sorted = sort { $functions{$a} <=> $functions{$b} } keys %functions; -$total = 0; -$count = 0; -foreach $name (@sorted) -{ - next if $name =~ m#^/#; - next if $name =~ m#.+\.h$#; - next if $name =~ m#_unittest\.c$#; - print sprintf("%20s: %3.1f%%\n", $name, $functions{$name}); - $total += $functions{$name}; - $count++; -} -$total /= $count; -print "\n TOTAL: ~" . int($total) . "%\n\n"; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/gcov-seed.sh b/3rdparty/openpgm-svn-r1085/pgm/gcov-seed.sh deleted file mode 100755 index 853fbe6..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/gcov-seed.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -./ref/debug/async_unittest -./ref/debug/checksum_unittest -./ref/debug/getifaddrs_unittest -./ref/debug/getnodeaddr_unittest -./ref/debug/gsi_unittest -./ref/debug/http_unittest -./ref/debug/if_unittest -./ref/debug/indextoaddr_unittest -./ref/debug/inet_network_unittest -./ref/debug/md5_unittest -./ref/debug/net_unittest -./ref/debug/packet_unittest -./ref/debug/pgmMIB_unittest -./ref/debug/pgm_unittest -./ref/debug/rate_control_unittest -./ref/debug/receiver_unittest -./ref/debug/recv_unittest -./ref/debug/reed_solomon_unittest -./ref/debug/rxwi_unittest -./ref/debug/signal_unittest -./ref/debug/snmp_unittest -./ref/debug/source_unittest -./ref/debug/timer_unittest -./ref/debug/time_unittest -user=`id -nu` -group=`id -ng` -sudo execcap 'cap_net_raw=ep' /sbin/sucap $user $group ./ref/debug/transport_unittest -sudo find ref/debug/ -user 0 -exec chown $user:$group {} \; -./ref/debug/tsi_unittest -./ref/debug/txwi_unittest - diff --git a/3rdparty/openpgm-svn-r1085/pgm/gcov.sh b/3rdparty/openpgm-svn-r1085/pgm/gcov.sh deleted file mode 100755 index ca17d62..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/gcov.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -gcov -fno ref/debug async_unittest.c -gcov -fno ref/debug checksum_unittest.c -gcov -fno ref/debug getifaddrs_unittest.c -gcov -fno ref/debug getnodeaddr_unittest.c -gcov -fno ref/debug gsi_unittest.c -gcov -fno ref/debug http_unittest.c -gcov -fno ref/debug if_unittest.c -gcov -fno ref/debug indextoaddr_unittest.c -gcov -fno ref/debug inet_network_unittest.c -gcov -fno ref/debug md5_unittest.c -gcov -fno ref/debug net_unittest.c -gcov -fno ref/debug packet_unittest.c -gcov -fno ref/debug pgmMIB_unittest.c -gcov -fno ref/debug pgm_unittest.c -gcov -fno ref/debug rate_control_unittest.c -gcov -fno ref/debug receiver_unittest.c -gcov -fno ref/debug recv_unittest.c -gcov -fno ref/debug reed_solomon_unittest.c -gcov -fno ref/debug rxwi_unittest.c -gcov -fno ref/debug signal_unittest.c -gcov -fno ref/debug snmp_unittest.c -gcov -fno ref/debug source_unittest.c -gcov -fno ref/debug timer_unittest.c -gcov -fno ref/debug time_unittest.c -gcov -fno ref/debug tsi_unittest.c -gcov -fno ref/debug txwi_unittest.c - diff --git a/3rdparty/openpgm-svn-r1085/pgm/getifaddrs.c b/3rdparty/openpgm-svn-r1085/pgm/getifaddrs.c deleted file mode 100644 index 9db1d86..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/getifaddrs.c +++ /dev/null @@ -1,840 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable getifaddrs implementation. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#ifdef CONFIG_HAVE_GETIFADDRS -# include -# include -#endif -#if defined( sun ) -# include -#endif -#if defined( _WIN32 ) -# include -# include -#endif -#include -#include - - -//#define GETIFADDRS_DEBUG - -/* locals */ -struct _pgm_ifaddrs_t -{ - struct pgm_ifaddrs_t _ifa; - char _name[IF_NAMESIZE]; - struct sockaddr_storage _addr; - struct sockaddr_storage _netmask; -}; - -/* Number of attempts to try enumerating the interface list */ -#define MAX_TRIES 3 -#define DEFAULT_BUFFER_SIZE 4096 - -/* returns TRUE on success setting ifap to a linked list of system interfaces, - * returns FALSE on failure and sets error appropriately. - */ - -#ifdef SIOCGLIFCONF -static -bool -_pgm_getlifaddrs ( - struct pgm_ifaddrs_t** restrict ifap, - pgm_error_t** restrict error - ) -{ - const int sock = socket (AF_INET, SOCK_DGRAM, 0); - if (-1 == sock) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("Opening IPv4 datagram socket: %s"), - strerror (errno)); - return FALSE; - } - -/* process IPv6 interfaces */ - const int sock6 = socket (AF_INET6, SOCK_DGRAM, 0); - if (-1 == sock6) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("Opening IPv6 datagram socket: %s"), - strerror (errno)); - close (sock); - return FALSE; - } - - struct lifnum lifn; -again: - lifn.lifn_family = AF_INET; - lifn.lifn_flags = 0; - if (-1 == ioctl (sock, SIOCGLIFNUM, &lifn)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("SIOCGLIFNUM failed on IPv4 socket: %s"), - strerror (errno)); - close (sock); - close (sock6); - return FALSE; - } - unsigned if_count = lifn.lifn_count; - pgm_debug ("ioctl(AF_INET, SIOCGLIFNUM) = %d", lifn.lifn_count); - -/* nb: Sun and Apple code likes to pad the interface count here in case interfaces - * are coming up between calls, - */ - lifn.lifn_count += 4; - -/* process all interfaces with family-agnostic ioctl, unfortunately it still - * must be called on each family socket despite what if_tcp(7P) says. - */ - struct lifconf lifc, lifc6; - lifc.lifc_family = AF_INET; - lifc.lifc_flags = 0; - lifc.lifc_len = lifn.lifn_count * sizeof(struct lifreq); - lifc.lifc_buf = alloca (lifc.lifc_len); - if (-1 == ioctl (sock, SIOCGLIFCONF, &lifc)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("SIOCGLIFCONF failed on IPv4 socket: %s"), - strerror (errno)); - close (sock); - close (sock6); - return FALSE; - } - pgm_debug ("ioctl(AF_INET, SIOCGLIFCONF) = %d (%d)", lifc.lifc_len, (int)(lifc.lifc_len / sizeof(struct lifreq))); - -/* repeat everything for IPv6 */ - lifn.lifn_family = AF_INET6; - lifn.lifn_flags = 0; - if (-1 == ioctl (sock6, SIOCGLIFNUM, &lifn)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("SIOCGLIFNUM failed on IPv6 socket: %s"), - strerror (errno)); - close (sock); - close (sock6); - return FALSE; - } - if_count += lifn.lifn_count; - pgm_debug ("ioctl(AF_INET6, SIOCGLIFNUM) = %d", lifn.lifn_count); - - lifn.lifn_count += 4; - - lifc6.lifc_family = AF_INET6; - lifc6.lifc_flags = 0; - lifc6.lifc_len = lifn.lifn_count * sizeof(struct lifreq); - lifc6.lifc_buf = alloca (lifc6.lifc_len); - if (-1 == ioctl (sock6, SIOCGLIFCONF, &lifc6)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("SIOCGLIFCONF failed on IPv6 socket: %s"), - strerror (errno)); - close (sock); - close (sock6); - return FALSE; - } - pgm_debug ("ioctl(AF_INET6, SIOCGLIFCONF) = %d (%d)", lifc6.lifc_len, (int)(lifc6.lifc_len / sizeof(struct lifreq))); - - unsigned nlifr = (lifc.lifc_len + lifc6.lifc_len) / sizeof(struct lifreq); - if (nlifr > if_count) - goto again; - -/* alloc a contiguous block for entire list */ - struct _pgm_ifaddrs_t* ifa = calloc (nlifr, sizeof (struct _pgm_ifaddrs_t)); - pgm_assert (NULL != ifa); - - struct _pgm_ifaddrs_t* ift = ifa; - struct lifreq* lifr = lifc.lifc_req; - struct lifreq* lifr_end = (struct lifreq *)&lifc.lifc_buf[lifc.lifc_len]; - - pgm_assert (IF_NAMESIZE >= LIFNAMSIZ); - - while (lifr < lifr_end) - { -/* name */ - pgm_debug ("AF_INET/name: %s", lifr->lifr_name ? lifr->lifr_name : "(null)"); - ift->_ifa.ifa_name = ift->_name; - strncpy (ift->_ifa.ifa_name, lifr->lifr_name, LIFNAMSIZ); - ift->_ifa.ifa_name[LIFNAMSIZ - 1] = 0; - -/* flags */ - if (-1 != ioctl (sock, SIOCGLIFFLAGS, lifr)) { - ift->_ifa.ifa_flags = lifr->lifr_flags; - } else { - pgm_warn (_("SIOCGLIFFLAGS failed on interface %s%s%s"), - lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); - } - -/* address */ - if (-1 != ioctl (sock, SIOCGLIFADDR, lifr)) { - ift->_ifa.ifa_addr = (void*)&ift->_addr; - memcpy (ift->_ifa.ifa_addr, &lifr->lifr_addr, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_addr)); - } else { - pgm_warn (_("SIOCGLIFADDR failed on interface %s%s%s"), - lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); - } - -/* netmask */ - if (-1 != ioctl (sock, SIOCGLIFNETMASK, lifr)) { - ift->_ifa.ifa_netmask = (void*)&ift->_netmask; -# ifdef CONFIG_HAVE_IFR_NETMASK - memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_netmask, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_netmask)); -# else - memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_addr, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_addr)); -# endif - } else { - pgm_warn (_("SIOCGLIFNETMASK failed on interface %s%s%s"), - lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); - } - - ++lifr; - if (lifr < lifr_end) { - ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); - ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); - } - } - -/* repeat everything for IPv6 */ - lifr = lifc6.lifc_req; - lifr_end = (struct lifreq *)&lifc6.lifc_buf[lifc6.lifc_len]; - - while (lifr < lifr_end) - { - if (ift != ifa) { - ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); - ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); - } - -/* name */ - pgm_debug ("AF_INET6/name: %s", lifr->lifr_name ? lifr->lifr_name : "(null)"); - ift->_ifa.ifa_name = ift->_name; - strncpy (ift->_ifa.ifa_name, lifr->lifr_name, sizeof(lifr->lifr_name)); - ift->_ifa.ifa_name[sizeof(lifr->lifr_name) - 1] = 0; - -/* flags */ - if (-1 != ioctl (sock6, SIOCGLIFFLAGS, lifr)) { - ift->_ifa.ifa_flags = lifr->lifr_flags; - } else { - pgm_warn (_("SIOCGLIFFLAGS failed on interface %s%s%s"), - lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); - } - -/* address */ - if (-1 != ioctl (sock6, SIOCGLIFADDR, lifr)) { - ift->_ifa.ifa_addr = (void*)&ift->_addr; - memcpy (ift->_ifa.ifa_addr, &lifr->lifr_addr, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_addr)); - } else { - pgm_warn (_("SIOCGLIFADDR failed on interface %s%s%s"), - lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); - } - -/* netmask */ - if (ioctl (sock6, SIOCGLIFNETMASK, lifr) != -1) { - ift->_ifa.ifa_netmask = (void*)&ift->_netmask; -# ifdef CONFIG_HAVE_IFR_NETMASK - memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_netmask, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_netmask)); -# else - memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_addr, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_addr)); -# endif - } else { - pgm_warn (_("SIOCGLIFNETMASK failed on interface %s%s%s"), - lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); - } - - ++lifr; - } - - if (-1 == close (sock6)) - pgm_warn (_("Closing IPv6 socket failed: %s"), strerror(errno)); - if (-1 == close (sock)) - pgm_warn (_("Closing IPv4 socket failed: %s"), strerror(errno)); - - *ifap = (struct pgm_ifaddrs_t*)ifa; - return TRUE; -} -#endif /* SIOCGLIFCONF */ - -#ifdef SIOCGIFCONF -static -bool -_pgm_getifaddrs ( - struct pgm_ifaddrs_t** restrict ifap, - pgm_error_t** restrict error - ) -{ - const int sock = socket (AF_INET, SOCK_DGRAM, 0); - if (-1 == sock) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("Opening IPv4 datagram socket: %s"), - strerror (errno)); - return FALSE; - } - -/* process IPv4 interfaces */ - char buf[ DEFAULT_BUFFER_SIZE ]; - struct ifconf ifc; - ifc.ifc_buf = buf; - ifc.ifc_len = sizeof(buf); - if (-1 == ioctl (sock, SIOCGIFCONF, &ifc)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("SIOCGIFCONF failed on IPv4 socket: %s"), - strerror (errno)); - close (sock); - return FALSE; - } - int if_count = ifc.ifc_len / sizeof(struct ifreq); - -# ifdef CONFIG_HAVE_IPV6_SIOCGIFADDR -/* process IPv6 interfaces */ - const int sock6 = socket (AF_INET6, SOCK_DGRAM, 0); - if (-1 == sock6) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("Opening IPv6 datagram socket: %s"), - strerror (errno)); - close (sock); - return FALSE; - } - - char buf6[1024]; - struct ifconf ifc6; - ifc6.ifc_buf = buf6; - ifc6.ifc_len = sizeof(buf6); - if (-1 == ioctl (sock6, SIOCGIFCONF, &ifc6)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("SIOCGIFCONF failed on IPv6 socket: %s"), - strerror (errno)); - close (sock); - close (sock6); - return FALSE; - } - if_count += ifc6.ifc_len / sizeof(struct ifreq); -# endif /* CONFIG_HAVE_IPV6_SIOCGIFADDR */ - -/* alloc a contiguous block for entire list */ - struct _pgm_ifaddrs_t* ifa = pgm_new0 (struct _pgm_ifaddrs_t, if_count); - struct _pgm_ifaddrs_t* ift = ifa; - struct ifreq *ifr = ifc.ifc_req; - struct ifreq *ifr_end = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; - - pgm_assert (IF_NAMESIZE >= sizeof(ifr->ifr_name)); - - while (ifr < ifr_end) - { -/* name */ - pgm_debug ("AF_INET/name:%s", ifr->ifr_name ? ifr->ifr_name : "(null)"); - ift->_ifa.ifa_name = ift->_name; - strncpy (ift->_ifa.ifa_name, ifr->ifr_name, sizeof(ifr->ifr_name)); - ift->_ifa.ifa_name[sizeof(ifr->ifr_name) - 1] = 0; - -/* flags */ - if (-1 != ioctl (sock, SIOCGIFFLAGS, ifr)) { - ift->_ifa.ifa_flags = ifr->ifr_flags; - } else { - pgm_warn (_("SIOCGIFFLAGS failed on interface %s%s%s"), - ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); - } - -/* address */ - if (-1 != ioctl (sock, SIOCGIFADDR, ifr)) { - ift->_ifa.ifa_addr = (void*)&ift->_addr; - memcpy (ift->_ifa.ifa_addr, &ifr->ifr_addr, pgm_sockaddr_len(&ifr->ifr_addr)); - } else { - pgm_warn (_("SIOCGIFADDR failed on interface %s%s%s"), - ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); - } - -/* netmask */ - if (-1 != ioctl (sock, SIOCGIFNETMASK, ifr)) { - ift->_ifa.ifa_netmask = (void*)&ift->_netmask; -# ifdef CONFIG_HAVE_IFR_NETMASK - memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_netmask, pgm_sockaddr_len(&ifr->ifr_netmask)); -# else - memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_addr, pgm_sockaddr_len(&ifr->ifr_addr)); -# endif - } else { - pgm_warn (_("SIOCGIFNETMASK failed on interface %s%s%s"), - ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); - } - - ++ifr; - if (ifr < ifr_end) { - ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); - ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); - } - } - -# ifdef CONFIG_HAVE_IPV6_SIOCGIFADDR -/* repeat everything for IPv6 */ - ifr = ifc6.ifc_req; - ifr_end = (struct ifreq *)&ifc6.ifc_buf[ifc6.ifc_len]; - - while (ifr < ifr_end) - { - if (ift != ifa) { - ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); - ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); - } - -/* name */ - pgm_debug ("AF_INET6/name:%s", ifr->ifr_name ? ifr->ifr_name : "(null)"); - ift->_ifa.ifa_name = ift->_name; - strncpy (ift->_ifa.ifa_name, ifr->ifr_name, sizeof(ifr->ifr_name)); - ift->_ifa.ifa_name[sizeof(ifr->ifr_name) - 1] = 0; - -/* flags */ - if (-1 != ioctl (sock6, SIOCGIFFLAGS, ifr)) { - ift->_ifa.ifa_flags = ifr->ifr_flags; - } else { - pgm_warn (_("SIOCGIFFLAGS failed on interface %s%s%s"), - ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); - } - -/* address, note this does not work on Linux as struct ifreq is too small for an IPv6 address */ - if (-1 != ioctl (sock6, SIOCGIFADDR, ifr)) { - ift->_ifa.ifa_addr = (void*)&ift->_addr; - memcpy (ift->_ifa.ifa_addr, &ifr->ifr_addr, pgm_sockaddr_len(&ifr->ifr_addr)); - } else { - pgm_warn (_("SIOCGIFADDR failed on interface %s%s%s"), - ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); - } - -/* netmask */ - if (-1 != ioctl (sock6, SIOCGIFNETMASK, ifr)) { - ift->_ifa.ifa_netmask = (void*)&ift->_netmask; -# ifdef CONFIG_HAVE_IFR_NETMASK - memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_netmask, pgm_sockaddr_len(&ifr->ifr_netmask)); -# else - memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_addr, pgm_sockaddr_len(&ifr->ifr_addr)); -# endif - } else { - pgm_warn (_("SIOCGIFNETMASK failed on interface %s%s%s"), - ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); - } - - ++ifr; - } - - if (-1 == close (sock6)) - pgm_warn (_("Closing IPv6 socket failed: %s"), strerror(errno)); -# endif /* CONFIG_HAVE_IPV6_SIOCGIFADDR */ - - if (-1 == close (sock)) - pgm_warn (_("Closing IPv4 socket failed: %s"), strerror(errno)); - - *ifap = (struct pgm_ifaddrs_t*)ifa; - return TRUE; -} -#endif /* SIOCLIFCONF */ - -#if defined(_WIN32) -static inline -void* -_pgm_heap_alloc ( - const size_t n_bytes - ) -{ -# ifdef CONFIG_USE_HEAPALLOC -/* Does not appear very safe with re-entrant calls on XP */ - return HeapAlloc (GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, n_bytes); -# else - return pgm_malloc (n_bytes); -# endif -} - -static inline -void -_pgm_heap_free ( - void* mem - ) -{ -# ifdef CONFIG_USE_HEAPALLOC - HeapFree (GetProcessHeap(), 0, mem); -# else - pgm_free (mem); -# endif -} - -/* NB: IP_ADAPTER_INFO size varies size due to sizeof (time_t), the API assumes - * 4-byte datatype whilst compiler uses an 8-byte datatype. Size can be forced - * with -D_USE_32BIT_TIME_T with side effects to everything else. - */ - -static -bool -_pgm_getadaptersinfo ( - struct pgm_ifaddrs_t** restrict ifap, - pgm_error_t** restrict error - ) -{ - DWORD dwRet; - ULONG ulOutBufLen = DEFAULT_BUFFER_SIZE; - PIP_ADAPTER_INFO pAdapterInfo = NULL; - PIP_ADAPTER_INFO pAdapter = NULL; - -/* loop to handle interfaces coming online causing a buffer overflow - * between first call to list buffer length and second call to enumerate. - */ - for (unsigned i = MAX_TRIES; i; i--) - { - pgm_debug ("IP_ADAPTER_INFO buffer length %lu bytes.", ulOutBufLen); - pAdapterInfo = (IP_ADAPTER_INFO*)_pgm_heap_alloc (ulOutBufLen); - dwRet = GetAdaptersInfo (pAdapterInfo, &ulOutBufLen); - if (ERROR_BUFFER_OVERFLOW == dwRet) { - _pgm_heap_free (pAdapterInfo); - pAdapterInfo = NULL; - } else { - break; - } - } - - switch (dwRet) { - case ERROR_SUCCESS: /* NO_ERROR */ - break; - case ERROR_BUFFER_OVERFLOW: - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NOBUFS, - _("GetAdaptersInfo repeatedly failed with ERROR_BUFFER_OVERFLOW.")); - if (pAdapterInfo) - _pgm_heap_free (pAdapterInfo); - return FALSE; - default: - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_win_errno (dwRet), - _("GetAdaptersInfo failed: %s"), - pgm_adapter_strerror (dwRet)); - if (pAdapterInfo) - _pgm_heap_free (pAdapterInfo); - return FALSE; - } - -/* count valid adapters */ - int n = 0, k = 0; - for (pAdapter = pAdapterInfo; - pAdapter; - pAdapter = pAdapter->Next) - { - for (IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList; - pIPAddr; - pIPAddr = pIPAddr->Next) - { -/* skip null adapters */ - if (strlen (pIPAddr->IpAddress.String) == 0) - continue; - ++n; - } - } - - pgm_debug ("GetAdaptersInfo() discovered %d interfaces.", n); - -/* contiguous block for adapter list */ - struct _pgm_ifaddrs_t* ifa = pgm_new0 (struct _pgm_ifaddrs_t, n); - struct _pgm_ifaddrs_t* ift = ifa; - -/* now populate list */ - for (pAdapter = pAdapterInfo; - pAdapter; - pAdapter = pAdapter->Next) - { - for (IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList; - pIPAddr; - pIPAddr = pIPAddr->Next) - { -/* skip null adapters */ - if (strlen (pIPAddr->IpAddress.String) == 0) - continue; - -/* address */ - ift->_ifa.ifa_addr = (void*)&ift->_addr; - pgm_assert (pgm_sockaddr_pton (pIPAddr->IpAddress.String, ift->_ifa.ifa_addr)); - -/* name */ - pgm_debug ("name:%s IPv4 index:%lu", - pAdapter->AdapterName, pAdapter->Index); - ift->_ifa.ifa_name = ift->_name; - strncpy (ift->_ifa.ifa_name, pAdapter->AdapterName, IF_NAMESIZE); - ift->_ifa.ifa_name[IF_NAMESIZE - 1] = 0; - -/* flags: assume up, broadcast and multicast */ - ift->_ifa.ifa_flags = IFF_UP | IFF_BROADCAST | IFF_MULTICAST; - if (pAdapter->Type == MIB_IF_TYPE_LOOPBACK) - ift->_ifa.ifa_flags |= IFF_LOOPBACK; - -/* netmask */ - ift->_ifa.ifa_netmask = (void*)&ift->_netmask; - pgm_assert (pgm_sockaddr_pton (pIPAddr->IpMask.String, ift->_ifa.ifa_netmask)); - -/* next */ - if (k++ < (n - 1)) { - ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); - ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); - } - } - } - - if (pAdapterInfo) - free (pAdapterInfo); - *ifap = (struct pgm_ifaddrs_t*)ifa; - return TRUE; -} - -static -bool -_pgm_getadaptersaddresses ( - struct pgm_ifaddrs_t** restrict ifap, - pgm_error_t** restrict error - ) -{ - DWORD dwSize = DEFAULT_BUFFER_SIZE, dwRet; - IP_ADAPTER_ADDRESSES *pAdapterAddresses = NULL, *adapter; - -/* loop to handle interfaces coming online causing a buffer overflow - * between first call to list buffer length and second call to enumerate. - */ - for (unsigned i = MAX_TRIES; i; i--) - { - pgm_debug ("IP_ADAPTER_ADDRESSES buffer length %lu bytes.", dwSize); - pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_pgm_heap_alloc (dwSize); - dwRet = GetAdaptersAddresses (AF_UNSPEC, - GAA_FLAG_INCLUDE_PREFIX | - GAA_FLAG_SKIP_ANYCAST | - GAA_FLAG_SKIP_DNS_SERVER | - GAA_FLAG_SKIP_FRIENDLY_NAME | - GAA_FLAG_SKIP_MULTICAST, - NULL, - pAdapterAddresses, - &dwSize); - if (ERROR_BUFFER_OVERFLOW == dwRet) { - _pgm_heap_free (pAdapterAddresses); - pAdapterAddresses = NULL; - } else { - break; - } - } - - switch (dwRet) { - case ERROR_SUCCESS: - break; - case ERROR_BUFFER_OVERFLOW: - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NOBUFS, - _("GetAdaptersAddresses repeatedly failed with ERROR_BUFFER_OVERFLOW.")); - if (pAdapterAddresses) - free (pAdapterAddresses); - return FALSE; - default: - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_win_errno (dwRet), - _("GetAdaptersAddresses failed: %s"), - pgm_adapter_strerror (dwRet)); - if (pAdapterAddresses) - free (pAdapterAddresses); - return FALSE; - } - -/* count valid adapters */ - int n = 0, k = 0; - for (adapter = pAdapterAddresses; - adapter; - adapter = adapter->Next) - { - for (IP_ADAPTER_UNICAST_ADDRESS *unicast = adapter->FirstUnicastAddress; - unicast; - unicast = unicast->Next) - { -/* ensure IP adapter */ - if (AF_INET != unicast->Address.lpSockaddr->sa_family && - AF_INET6 != unicast->Address.lpSockaddr->sa_family) - { - continue; - } - - ++n; - } - } - -/* contiguous block for adapter list */ - struct _pgm_ifaddrs_t* ifa = pgm_new0 (struct _pgm_ifaddrs_t, n); - struct _pgm_ifaddrs_t* ift = ifa; - -/* now populate list */ - for (adapter = pAdapterAddresses; - adapter; - adapter = adapter->Next) - { - int unicastIndex = 0; - for (IP_ADAPTER_UNICAST_ADDRESS *unicast = adapter->FirstUnicastAddress; - unicast; - unicast = unicast->Next, ++unicastIndex) - { -/* ensure IP adapter */ - if (AF_INET != unicast->Address.lpSockaddr->sa_family && - AF_INET6 != unicast->Address.lpSockaddr->sa_family) - { - continue; - } - -/* address */ - ift->_ifa.ifa_addr = (void*)&ift->_addr; - memcpy (ift->_ifa.ifa_addr, unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength); - -/* name */ - pgm_debug ("name:%s IPv4 index:%lu IPv6 index:%lu", - adapter->AdapterName, adapter->IfIndex, adapter->Ipv6IfIndex); - ift->_ifa.ifa_name = ift->_name; - strncpy (ift->_ifa.ifa_name, adapter->AdapterName, IF_NAMESIZE); - ift->_ifa.ifa_name[IF_NAMESIZE - 1] = 0; - -/* flags */ - ift->_ifa.ifa_flags = 0; - if (IfOperStatusUp == adapter->OperStatus) - ift->_ifa.ifa_flags |= IFF_UP; - if (IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType) - ift->_ifa.ifa_flags |= IFF_LOOPBACK; - if (!(adapter->Flags & IP_ADAPTER_NO_MULTICAST)) - ift->_ifa.ifa_flags |= IFF_MULTICAST; - -/* netmask */ - ift->_ifa.ifa_netmask = (void*)&ift->_netmask; - -/* pre-Vista must hunt for matching prefix in linked list, otherwise use OnLinkPrefixLength */ - int prefixIndex = 0; - ULONG prefixLength = 0; - for (IP_ADAPTER_PREFIX *prefix = adapter->FirstPrefix; - prefix; - prefix = prefix->Next, ++prefixIndex) - { - if (prefixIndex == unicastIndex) { - prefixLength = prefix->PrefixLength; - break; - } - } - -/* map prefix to netmask */ - ift->_ifa.ifa_netmask->sa_family = unicast->Address.lpSockaddr->sa_family; - switch (unicast->Address.lpSockaddr->sa_family) { - case AF_INET: - if (0 == prefixLength) { - pgm_warn (_("IPv4 adapter %s prefix length is 0, overriding to 32."), adapter->AdapterName); - prefixLength = 32; - } - ((struct sockaddr_in*)ift->_ifa.ifa_netmask)->sin_addr.s_addr = htonl( 0xffffffffU << ( 32 - prefixLength ) ); - break; - - case AF_INET6: - if (0 == prefixLength) { - pgm_warn (_("IPv6 adapter %s prefix length is 0, overriding to 128."), adapter->AdapterName); - prefixLength = 128; - } - for (ULONG i = prefixLength, j = 0; i > 0; i -= 8, ++j) - { - ((struct sockaddr_in6*)ift->_ifa.ifa_netmask)->sin6_addr.s6_addr[ j ] = i >= 8 ? 0xff : (ULONG)(( 0xffU << ( 8 - i ) ) & 0xffU ); - } - break; - } - -/* next */ - if (k++ < (n - 1)) { - ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); - ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); - } - } - } - - if (pAdapterAddresses) - free (pAdapterAddresses); - *ifap = (struct pgm_ifaddrs_t*)ifa; - return TRUE; -} -#endif /* _WIN32 */ - -/* returns TRUE on success setting ifap to a linked list of system interfaces, - * returns FALSE on failure and sets error appropriately. - */ - -bool -pgm_getifaddrs ( - struct pgm_ifaddrs_t** restrict ifap, - pgm_error_t** restrict error - ) -{ - pgm_assert (NULL != ifap); - - pgm_debug ("pgm_getifaddrs (ifap:%p error:%p)", - (void*)ifap, (void*)error); - -#ifdef CONFIG_HAVE_GETIFADDRS - const int e = getifaddrs ((struct ifaddrs**)ifap); - if (-1 == e) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("getifaddrs failed: %s"), - strerror (errno)); - return FALSE; - } - return TRUE; -#elif defined(CONFIG_TARGET_WINE) - return _pgm_getadaptersinfo (ifap, error); -#elif defined(_WIN32) - return _pgm_getadaptersaddresses (ifap, error); -#elif defined(SIOCGLIFCONF) - return _pgm_getlifaddrs (ifap, error); -#elif defined(SIOCGIFCONF) - return _pgm_getifaddrs (ifap, error); -#else -# error "Unsupported interface enumeration on this platform." -#endif /* !CONFIG_HAVE_GETIFADDRS */ -} - -void -pgm_freeifaddrs ( - struct pgm_ifaddrs_t* ifa - ) -{ - pgm_return_if_fail (NULL != ifa); - -#ifdef CONFIG_HAVE_GETIFADDRS - freeifaddrs ((struct ifaddrs*)ifa); -#else - pgm_free (ifa); -#endif -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/getifaddrs_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/getifaddrs_unittest.c deleted file mode 100644 index 05063fe..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/getifaddrs_unittest.c +++ /dev/null @@ -1,262 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for portable getifaddrs implementation. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* IFF_UP */ -#define _BSD_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* mock state */ - -/* mock functions for external references */ - -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return 0; -} - - -#define GETIFADDRS_DEBUG -#include "getifaddrs.c" - - -char* -ifflags_string ( - unsigned int flags - ) -{ - static char s[1024]; - - s[0] = '\0'; - if (flags & IFF_UP) - strcat (s, "IFF_UP"); -#define IFF(flag) \ - do { \ - if (flags & flag) { \ - strcat (s, s[0] ? ("|" #flag) : (#flag)); \ - } \ - } while (0) -#ifdef IFF_BROADCAST - IFF(IFF_BROADCAST); -#endif -#ifdef IFF_DEBUG - IFF(IFF_DEBUG); -#endif -#ifdef IFF_LOOPBACK - IFF(IFF_LOOPBACK); -#endif -#ifdef IFF_POINTOPOINT - IFF(IFF_POINTOPOINT); -#endif -#ifdef IFF_RUNNING - IFF(IFF_RUNNING); -#endif -#ifdef IFF_NOARP - IFF(IFF_NOARP); -#endif -#ifdef IFF_PROMISC - IFF(IFF_PROMISC); -#endif -#ifdef IFF_NOTRAILERS - IFF(IFF_NOTRAILERS); -#endif -#ifdef IFF_ALLMULTI - IFF(IFF_ALLMULTI); -#endif -#ifdef IFF_MASTER - IFF(IFF_MASTER); -#endif -#ifdef IFF_SLAVE - IFF(IFF_SLAVE); -#endif -#ifdef IFF_MULTICAST - IFF(IFF_MULTICAST); -#endif -#ifdef IFF_PORTSEL - IFF(IFF_PORTSEL); -#endif -#ifdef IFF_AUTOMEDIA - IFF(IFF_AUTOMEDIA); -#endif -#ifdef IFF_DYNAMIC - IFF(IFF_DYNAMIC); -#endif -#ifdef IFF_LOWER_UP - IFF(IFF_LOWER_UP); -#endif -#ifdef IFF_DORMANT - IFF(IFF_DORMANT); -#endif -#ifdef IFF_ECHO - IFF(IFF_ECHO); -#endif - if (!s[0]) { - if (flags) - sprintf (s, "0x%x", flags); - else - strcpy (s, "(null)"); - } - return s; -} - -/* target: - * bool - * pgm_getifaddrs ( - * struct pgm_ifaddrs_t**restrict ifap, - * pgm_error_t**restrict error - * ) - */ - -START_TEST (test_getifaddrs_pass_001) -{ - char saddr[INET6_ADDRSTRLEN], snetmask[INET6_ADDRSTRLEN]; - struct pgm_ifaddrs_t *ifap = NULL, *ifa; - pgm_error_t* err = NULL; - fail_unless (TRUE == pgm_getifaddrs (&ifap, &err), "getifaddrs failed"); - for (ifa = ifap; ifa; ifa = ifa->ifa_next) - { - fail_unless (NULL != ifa, "invalid address"); - if (ifa->ifa_addr) { - if (AF_INET == ifa->ifa_addr->sa_family || - AF_INET6 == ifa->ifa_addr->sa_family) - pgm_sockaddr_ntop (ifa->ifa_addr, saddr, sizeof(saddr)); -#ifdef AF_PACKET - else if (AF_PACKET == ifa->ifa_addr->sa_family) - strcpy (saddr, "(AF_PACKET)"); -#endif - else - sprintf (saddr, "(AF = %d)", ifa->ifa_addr->sa_family); - } else - strcpy (saddr, "(null)"); - if (ifa->ifa_netmask) { - if (AF_INET == ifa->ifa_addr->sa_family || - AF_INET6 == ifa->ifa_addr->sa_family) - pgm_sockaddr_ntop (ifa->ifa_netmask, snetmask, sizeof(snetmask)); -#ifdef AF_PACKET - else if (AF_PACKET == ifa->ifa_addr->sa_family) - strcpy (snetmask, "(AF_PACKET)"); -#endif - else - sprintf (snetmask, "(AF = %d)", ifa->ifa_addr->sa_family); - } else - strcpy (snetmask, "(null)"); - g_message ("ifa = {" - "ifa_next = %p, " - "ifa_name = %s%s%s, " - "ifa_flags = %s, " - "ifa_addr = %s, " - "ifa_netmask = %s" - "}", - ifa->ifa_next, - ifa->ifa_name ? "\"" : "", ifa->ifa_name ? ifa->ifa_name : "(null)", ifa->ifa_name ? "\"" : "", - ifflags_string (ifa->ifa_flags), - saddr, - snetmask); - } -} -END_TEST - -START_TEST (test_getifaddrs_fail_001) -{ - fail_unless (FALSE == pgm_getifaddrs (NULL, NULL), "getifaddrs failed"); - g_message ("errno:%d", errno); -} -END_TEST - -/* target: - * void - * pgm_freeifaddrs ( - * struct pgm_ifaddrs* ifa - * ) - */ - -START_TEST (test_freeifaddrs_pass_001) -{ - struct pgm_ifaddrs_t* ifap = NULL; - pgm_error_t* err = NULL; - fail_unless (TRUE == pgm_getifaddrs (&ifap, &err), "getifaddrs failed"); - pgm_freeifaddrs (ifap); -} -END_TEST - -/* silent failure */ -START_TEST (test_freeifaddrs_pass_002) -{ - pgm_freeifaddrs (NULL); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_getifaddrs = tcase_create ("getifaddrs"); - suite_add_tcase (s, tc_getifaddrs); - tcase_add_test (tc_getifaddrs, test_getifaddrs_pass_001); - tcase_add_test_raise_signal (tc_getifaddrs, test_getifaddrs_fail_001, SIGABRT); - - TCase* tc_freeifaddrs = tcase_create ("freeifaddrs"); - suite_add_tcase (s, tc_freeifaddrs); - tcase_add_test (tc_freeifaddrs, test_freeifaddrs_pass_001); - tcase_add_test (tc_freeifaddrs, test_freeifaddrs_pass_002); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/getnodeaddr.c b/3rdparty/openpgm-svn-r1085/pgm/getnodeaddr.c deleted file mode 100644 index 0765c9f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/getnodeaddr.c +++ /dev/null @@ -1,196 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable function to return the nodes IP address. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#ifndef _WIN32 -# include -#endif -#include -#include - - -//#define GETNODEADDR_DEBUG - - -/* globals */ - -static const char* pgm_family_string (const sa_family_t); - - -/* return node primary address on multi-address family interfaces. - * - * returns TRUE on success, returns FALSE on failure. - */ - -bool -pgm_if_getnodeaddr ( - const sa_family_t family, /* requested address family, AF_INET, AF_INET6, or AF_UNSPEC */ - struct sockaddr* restrict addr, - const socklen_t cnt, /* size of address pointed to by addr */ - pgm_error_t** restrict error - ) -{ - pgm_return_val_if_fail (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family, FALSE); - pgm_return_val_if_fail (NULL != addr, FALSE); - if (AF_INET == family || AF_UNSPEC == family) - pgm_return_val_if_fail (cnt >= sizeof(struct sockaddr_in), FALSE); - else - pgm_return_val_if_fail (cnt >= sizeof(struct sockaddr_in6), FALSE); - - pgm_debug ("pgm_if_getnodeaddr (family:%s addr:%p cnt:%d error:%p)", - pgm_family_string (family), (const void*)addr, cnt, (const void*)error); - - char hostname[NI_MAXHOST + 1]; - struct hostent* he; - - if (0 != gethostname (hostname, sizeof(hostname))) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("Resolving hostname: %s"), -#ifndef _WIN32 - strerror (errno) -#else - pgm_wsastrerror (WSAGetLastError()) -#endif - ); - return FALSE; - } - - addr->sa_family = family; - struct addrinfo hints = { - .ai_family = family, - .ai_socktype = SOCK_STREAM, /* not really */ - .ai_protocol = IPPROTO_TCP, /* not really */ - .ai_flags = AI_ADDRCONFIG, - }, *res; - - int e = getaddrinfo (hostname, NULL, &hints, &res); - if (0 == e) { - const socklen_t addrlen = res->ai_addrlen; - memcpy (addr, res->ai_addr, addrlen); - freeaddrinfo (res); - return TRUE; - } else if (EAI_NONAME != e) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_eai_errno (e, errno), - _("Resolving hostname address: %s"), - gai_strerror (e)); - return FALSE; - } else if (AF_UNSPEC == family) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NONAME, - _("Resolving hostname address family.")); - return FALSE; - } - -/* Common case a dual stack host has incorrect IPv6 configuration, i.e. - * hostname is only IPv4 and despite one or more IPv6 addresses. Workaround - * for this case is to resolve the IPv4 hostname, find the matching interface - * and from that interface find an active IPv6 address taking global scope as - * preference over link scoped addresses. - */ - he = gethostbyname (hostname); - if (NULL == he) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_h_errno (h_errno), -#ifndef _WIN32 - _("Resolving IPv4 hostname address: %s"), - hstrerror (h_errno) -#else - _("Resolving IPv4 hostname address: %s"), - pgm_wsastrerror (WSAGetLastError()) -#endif - ); - return FALSE; - } - - struct pgm_ifaddrs_t *ifap, *ifa, *ifa6; - if (!pgm_getifaddrs (&ifap, error)) { - pgm_prefix_error (error, - _("Enumerating network interfaces: ")); - return FALSE; - } - -/* hunt for IPv4 interface */ - for (ifa = ifap; ifa; ifa = ifa->ifa_next) - { - if (NULL == ifa->ifa_addr || - AF_INET != ifa->ifa_addr->sa_family) - continue; - if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == ((struct in_addr*)(he->h_addr_list[0]))->s_addr) - { - goto ipv4_found; - } - } - pgm_freeifaddrs (ifap); - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NONET, - _("Discovering primary IPv4 network interface.")); - return FALSE; -ipv4_found: - -/* hunt for IPv6 interface */ - for (ifa6 = ifap; ifa6; ifa6 = ifa6->ifa_next) - { - if (AF_INET6 != ifa6->ifa_addr->sa_family) - continue; - if (0 == strcmp (ifa->ifa_name, ifa6->ifa_name)) - { - goto ipv6_found; - } - } - pgm_freeifaddrs (ifap); - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NONET, - _("Discovering primary IPv6 network interface.")); - return FALSE; -ipv6_found: - - memcpy (addr, ifa6->ifa_addr, pgm_sockaddr_len (ifa6->ifa_addr)); - pgm_freeifaddrs (ifap); - return TRUE; -} - -static -const char* -pgm_family_string ( - const sa_family_t family - ) -{ - const char* c; - - switch (family) { - case AF_UNSPEC: c = "AF_UNSPEC"; break; - case AF_INET: c = "AF_INET"; break; - case AF_INET6: c = "AF_INET6"; break; - default: c = "(unknown)"; break; - } - - return c; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/getnodeaddr_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/getnodeaddr_unittest.c deleted file mode 100644 index 6792d2a..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/getnodeaddr_unittest.c +++ /dev/null @@ -1,573 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for portable function to return the nodes IP address. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* IFF_UP */ -#define _BSD_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -/* mock state */ - -struct addrinfo; - -struct mock_host_t { - struct sockaddr_storage address; - char* canonical_hostname; - char* alias; -}; - -struct mock_interface_t { - unsigned int index; - char* name; - unsigned int flags; - struct sockaddr_storage addr; - struct sockaddr_storage netmask; -}; - -static GList *mock_hosts = NULL, *mock_interfaces = NULL; - -#define MOCK_HOSTNAME "kiku" -static char* mock_kiku = MOCK_HOSTNAME; -static char* mock_localhost = "localhost"; -static char* mock_invalid = "invalid.invalid"; /* RFC 2606 */ -static char* mock_toolong = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij12345"; /* 65 */ -static char* mock_hostname = NULL; - -struct pgm_ifaddrs_t; -struct pgm_error_t; - -static bool mock_pgm_getifaddrs (struct pgm_ifaddrs_t**, struct pgm_error_t**); -static void mock_pgm_freeifaddrs (struct pgm_ifaddrs_t*); -static int mock_getaddrinfo (const char*, const char*, const struct addrinfo*, struct addrinfo**); -static void mock_freeaddrinfo (struct addrinfo*); -static int mock_gethostname (char*, size_t); -static struct hostent* mock_gethostbyname (const char*); - - -#define pgm_getifaddrs mock_pgm_getifaddrs -#define pgm_freeifaddrs mock_pgm_freeifaddrs -#define getaddrinfo mock_getaddrinfo -#define freeaddrinfo mock_freeaddrinfo -#define gethostname mock_gethostname -#define gethostbyname mock_gethostbyname - - -#define GETNODEADDR_DEBUG -#include "getnodeaddr.c" - - -static -gpointer -create_host ( - const char* address, - const char* canonical_hostname, - const char* alias - ) -{ - struct mock_host_t* new_host; - - g_assert (address); - g_assert (canonical_hostname); - - new_host = g_slice_alloc0 (sizeof(struct mock_host_t)); - g_assert (pgm_sockaddr_pton (address, (struct sockaddr*)&new_host->address)); - new_host->canonical_hostname = g_strdup (canonical_hostname); - new_host->alias = alias ? g_strdup (alias) : NULL; - - return new_host; -} - -static -gpointer -create_interface ( - const unsigned index, - const char* name, - const char* flags - ) -{ - struct mock_interface_t* new_interface; - - g_assert (name); - g_assert (flags); - - new_interface = g_slice_alloc0 (sizeof(struct mock_interface_t)); - new_interface->index = index; - new_interface->name = g_strdup (name); - - struct sockaddr_in* sin = (gpointer)&new_interface->addr; - struct sockaddr_in6* sin6 = (gpointer)&new_interface->addr; - - gchar** tokens = g_strsplit (flags, ",", 0); - for (guint i = 0; tokens[i]; i++) - { - if (strcmp (tokens[i], "up") == 0) - new_interface->flags |= IFF_UP; - else if (strcmp (tokens[i], "down") == 0) - new_interface->flags |= 0; - else if (strcmp (tokens[i], "loop") == 0) - new_interface->flags |= IFF_LOOPBACK; - else if (strcmp (tokens[i], "broadcast") == 0) - new_interface->flags |= IFF_BROADCAST; - else if (strcmp (tokens[i], "multicast") == 0) - new_interface->flags |= IFF_MULTICAST; - else if (strncmp (tokens[i], "ip=", strlen("ip=")) == 0) { - const char* addr = tokens[i] + strlen("ip="); - g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->addr)); - } - else if (strncmp (tokens[i], "netmask=", strlen("netmask=")) == 0) { - const char* addr = tokens[i] + strlen("netmask="); - g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->netmask)); - } - else if (strncmp (tokens[i], "scope=", strlen("scope=")) == 0) { - const char* scope = tokens[i] + strlen("scope="); - g_assert (AF_INET6 == ((struct sockaddr*)&new_interface->addr)->sa_family); - ((struct sockaddr_in6*)&new_interface->addr)->sin6_scope_id = atoi (scope); - } - else - g_error ("parsing failed for flag %s%s%s", - tokens[i] ? "\"" : "", tokens[i] ? tokens[i] : "(null)", tokens[i] ? "\"" : ""); - } - - g_strfreev (tokens); - return new_interface; -} - -#define APPEND_HOST2(a,b,c) \ - do { \ - gpointer data = create_host ((a), (b), (c)); \ - g_assert (data); \ - mock_hosts = g_list_append (mock_hosts, data); \ - g_assert (mock_hosts); g_assert (mock_hosts->data); \ - } while (0) -#define APPEND_HOST(a,b) APPEND_HOST2((a),(b),NULL) -#define APPEND_INTERFACE(a,b,c) \ - do { \ - gpointer data = create_interface ((a), (b), (c)); \ - g_assert (data); \ - mock_interfaces = g_list_append (mock_interfaces, data); \ - g_assert (mock_interfaces); g_assert (mock_interfaces->data); \ - } while (0) -static -void -mock_setup_net (void) -{ - mock_hostname = mock_kiku; - - APPEND_HOST ( "127.0.0.1", "localhost"); - APPEND_HOST2( "10.6.28.33", "kiku.hk.miru.hk", "kiku"); - APPEND_HOST2( "2002:dce8:d28e::33", "ip6-kiku", "kiku"); - APPEND_HOST2( "::1", "ip6-localhost", "ip6-loopback"); - - APPEND_INTERFACE( 1, "lo", "up,loop"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast"); - APPEND_INTERFACE( 3, "eth1", "down,broadcast,multicast"); - APPEND_INTERFACE( 1, "lo", "up,loop,ip=127.0.0.1,netmask=255.0.0.0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=10.6.28.33,netmask=255.255.255.0"); - APPEND_INTERFACE( 1, "lo", "up,loop,ip=::1,netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,scope=0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=2002:dce8:d28e::33,netmask=ffff:ffff:ffff:ffff::0,scope=0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=fe80::214:5eff:febd:6dda,netmask=ffff:ffff:ffff:ffff::0,scope=2"); -} - -/* with broken IPv6 hostname setup */ -static -void -mock_setup_net2 (void) -{ - mock_hostname = mock_kiku; - - APPEND_HOST ( "127.0.0.1", "localhost"); - APPEND_HOST2( "10.6.28.33", "kiku.hk.miru.hk", "kiku"); - APPEND_HOST( "2002:dce8:d28e::33", "ip6-kiku"); - APPEND_HOST2( "::1", "ip6-localhost", "ip6-loopback"); - - APPEND_INTERFACE( 1, "lo", "up,loop"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast"); - APPEND_INTERFACE( 3, "eth1", "down,broadcast,multicast"); - APPEND_INTERFACE( 1, "lo", "up,loop,ip=127.0.0.1,netmask=255.0.0.0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=10.6.28.33,netmask=255.255.255.0"); - APPEND_INTERFACE( 1, "lo", "up,loop,ip=::1,netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,scope=0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=2002:dce8:d28e::33,netmask=ffff:ffff:ffff:ffff::0,scope=0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=fe80::214:5eff:febd:6dda,netmask=ffff:ffff:ffff:ffff::0,scope=2"); -} - -static -void -mock_teardown_net (void) -{ - GList* list; - - list = mock_hosts; - while (list) { - struct mock_host_t* host = list->data; - g_free (host->canonical_hostname); - if (host->alias) - g_free (host->alias); - g_slice_free1 (sizeof(struct mock_host_t), host); - list = list->next; - } - g_list_free (mock_hosts); - - list = mock_interfaces; - while (list) { - struct mock_interface_t* interface = list->data; - g_free (interface->name); - g_slice_free1 (sizeof(struct mock_interface_t), interface); - list = list->next; - } - g_list_free (mock_interfaces); -} - - -/* mock functions for external references */ - -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return 0; -} - -static -bool -mock_pgm_getifaddrs ( - struct pgm_ifaddrs_t** ifap, - pgm_error_t** err - ) -{ - if (NULL == ifap) { - return FALSE; - } - - g_debug ("mock_getifaddrs (ifap:%p err:%p)", (gpointer)ifap, (gpointer)err); - - GList* list = mock_interfaces; - int n = g_list_length (list); - struct pgm_ifaddrs_t* ifa = malloc (n * sizeof(struct pgm_ifaddrs_t)); - memset (ifa, 0, n * sizeof(struct pgm_ifaddrs_t)); - struct pgm_ifaddrs_t* ift = ifa; - while (list) { - struct mock_interface_t* interface = list->data; - ift->ifa_addr = (gpointer)&interface->addr; - ift->ifa_name = interface->name; - ift->ifa_flags = interface->flags; - ift->ifa_netmask = (gpointer)&interface->netmask; - list = list->next; - if (list) { - ift->ifa_next = ift + 1; - ift = ift->ifa_next; - } - } - - *ifap = ifa; - return TRUE; -} - -static -void -mock_pgm_freeifaddrs ( - struct pgm_ifaddrs_t* ifa - ) -{ - g_debug ("mock_freeifaddrs (ifa:%p)", (gpointer)ifa); - free (ifa); -} - -static -struct hostent* -mock_gethostbyname ( - const char* name - ) -{ - static struct hostent he; - static char* aliases[2]; - static char* addr_list[2]; - -/* pre-conditions */ - g_assert (NULL != name); - - g_debug ("mock_gethostbyname (name:%s%s%s)", - name ? "\"" : "", name ? name : "(null)", name ? "\"" : ""); - - GList* list = mock_hosts; - while (list) { - struct mock_host_t* host = list->data; - const int host_family = ((struct sockaddr*)&host->address)->sa_family; - if (((strcmp (host->canonical_hostname, name) == 0) || - (host->alias && strcmp (host->alias, name) == 0))) - { - he.h_name = host->canonical_hostname; - aliases[0] = host->alias; - aliases[1] = NULL; - he.h_aliases = aliases; - he.h_addrtype = host_family; - switch (host->address.ss_family){ - case AF_INET: - he.h_length = sizeof (struct in_addr); - addr_list[0] = (char*)&host->address + G_STRUCT_OFFSET(struct sockaddr_in, sin_addr); - break; - case AF_INET6: - he.h_length = sizeof (struct in6_addr); - addr_list[0] = (char*)&host->address + G_STRUCT_OFFSET(struct sockaddr_in6, sin6_addr); - break; - default: - g_assert_not_reached(); - } - addr_list[1] = NULL; - he.h_addr_list = addr_list; - return &he; - } - list = list->next; - } - h_errno = HOST_NOT_FOUND; - return NULL; -} - -static -int -mock_getaddrinfo ( - const char* node, - const char* service, - const struct addrinfo* hints, - struct addrinfo** res - ) -{ - const int ai_flags = hints ? hints->ai_flags : (AI_V4MAPPED | AI_ADDRCONFIG); - const int ai_family = hints ? hints->ai_family : AF_UNSPEC; - GList* list; - struct sockaddr_storage addr; - - if (NULL == node && NULL == service) - return EAI_NONAME; - -/* pre-conditions */ - g_assert (NULL != node); - g_assert (NULL == service); - g_assert (!(ai_flags & AI_CANONNAME)); - g_assert (!(ai_flags & AI_NUMERICSERV)); - g_assert (!(ai_flags & AI_V4MAPPED)); - - g_debug ("mock_getaddrinfo (node:\"%s\" service:%s hints:%p res:%p)", - node ? node : "(null)", - service ? service : "(null)", - (gpointer)hints, - (gpointer)res); - - gboolean has_ip4_config; - gboolean has_ip6_config; - - if (hints && hints->ai_flags & AI_ADDRCONFIG) - { - has_ip4_config = has_ip6_config = FALSE; - list = mock_interfaces; - while (list) { - const struct mock_interface_t* interface = list->data; - if (AF_INET == ((struct sockaddr*)&interface->addr)->sa_family) - has_ip4_config = TRUE; - else if (AF_INET6 == ((struct sockaddr*)&interface->addr)->sa_family) - has_ip6_config = TRUE; - if (has_ip4_config && has_ip6_config) - break; - list = list->next; - } - } else { - has_ip4_config = has_ip6_config = TRUE; - } - - if (ai_flags & AI_NUMERICHOST) { - pgm_sockaddr_pton (node, (struct sockaddr*)&addr); - } - list = mock_hosts; - while (list) { - struct mock_host_t* host = list->data; - const int host_family = ((struct sockaddr*)&host->address)->sa_family; - if (((strcmp (host->canonical_hostname, node) == 0) || - (host->alias && strcmp (host->alias, node) == 0) || - (ai_flags & AI_NUMERICHOST && - 0 == pgm_sockaddr_cmp ((struct sockaddr*)&addr, (struct sockaddr*)&host->address))) - && - (host_family == ai_family || AF_UNSPEC == ai_family) && - ((AF_INET == host_family && has_ip4_config) || (AF_INET6 == host_family && has_ip6_config))) - { - struct addrinfo* ai = malloc (sizeof(struct addrinfo)); - memset (ai, 0, sizeof(struct addrinfo)); - ai->ai_family = host_family; - ai->ai_addrlen = AF_INET == host_family ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - ai->ai_addr = (gpointer)&host->address; - *res = ai; - return 0; - } - list = list->next; - } - return EAI_NONAME; -} - -static -void -mock_freeaddrinfo ( - struct addrinfo* res - ) -{ - g_assert (NULL != res); - g_debug ("mock_freeaddrinfo (res:%p)", (gpointer)res); - free (res); -} - -static -int -mock_gethostname ( - char* name, - size_t len - ) -{ - g_debug ("mock_gethostname (name:%p len:%d)", - (gpointer)name, len); - - if (NULL == name) { - errno = EFAULT; - return -1; - } - if (len < 0) { - errno = EINVAL; - return -1; - } - if (len < (1 + strlen (mock_hostname))) { - errno = ENAMETOOLONG; - return -1; - } -/* force an error */ - if (mock_hostname == mock_toolong) { - errno = ENAMETOOLONG; - return -1; - } - strncpy (name, mock_hostname, len); - if (len > 0) - name[len - 1] = '\0'; - return 0; -} - - -/* target: - * bool - * pgm_if_getnodeaddr ( - * const sa_family_t family, - * struct sockaddr* addr, - * const socklen_t cnt, - * pgm_error_t** error - * ) - */ - -START_TEST (test_getnodeaddr_pass_001) -{ - struct sockaddr_storage addr; - char saddr[INET6_ADDRSTRLEN]; - pgm_error_t* err = NULL; - gboolean success = pgm_if_getnodeaddr (AF_UNSPEC, (struct sockaddr*)&addr, sizeof(addr), &err); - if (!success && err) { - g_error ("Resolving node address with AF_UNSPEC: %s", (err && err->message) ? err->message : "(null)"); - } - fail_unless (TRUE == success, "getnodeaddr failed"); - fail_unless (NULL == err, "error raised"); - pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); - g_message ("AF_UNSPEC:%s", saddr ? saddr : "(null)"); - fail_unless (TRUE == pgm_if_getnodeaddr (AF_INET, (struct sockaddr*)&addr, sizeof(addr), &err), "getnodeaddr failed"); - fail_unless (NULL == err, "error raised"); - pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); - g_message ("AF_INET:%s", saddr ? saddr : "(null)"); - fail_unless (TRUE == pgm_if_getnodeaddr (AF_INET6, (struct sockaddr*)&addr, sizeof(addr), &err), "getnodeaddr failed"); - fail_unless (NULL == err, "error raised"); - pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); - g_message ("AF_INET6:%s", saddr ? saddr : "(null)"); -} -END_TEST - -START_TEST (test_getnodeaddr_fail_001) -{ - pgm_error_t* err = NULL; - fail_unless (FALSE == pgm_if_getnodeaddr (AF_UNSPEC, NULL, 0, &err), "getnodeaddr failed"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - -{ - mock_setup_net(); - - struct sockaddr_storage addr; - char saddr[INET6_ADDRSTRLEN]; - pgm_error_t* err = NULL; - gboolean success = pgm_if_getnodeaddr (AF_UNSPEC, (struct sockaddr*)&addr, sizeof(addr), &err); - if (!success && err) { - g_error ("Resolving node address with AF_UNSPEC: %s", (err && err->message) ? err->message : "(null)"); - } -} - s = suite_create (__FILE__); - - TCase* tc_getnodeaddr = tcase_create ("getnodeaddr"); - suite_add_tcase (s, tc_getnodeaddr); - tcase_add_checked_fixture (tc_getnodeaddr, mock_setup_net, mock_teardown_net); - tcase_add_test (tc_getnodeaddr, test_getnodeaddr_pass_001); - tcase_add_test (tc_getnodeaddr, test_getnodeaddr_fail_001); - - TCase* tc_getnodeaddr2 = tcase_create ("getnodeaddr/2"); - suite_add_tcase (s, tc_getnodeaddr2); - tcase_add_checked_fixture (tc_getnodeaddr2, mock_setup_net2, mock_teardown_net); - tcase_add_test (tc_getnodeaddr2, test_getnodeaddr_pass_001); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/gsi.c b/3rdparty/openpgm-svn-r1085/pgm/gsi.c deleted file mode 100644 index e7ebec4..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/gsi.c +++ /dev/null @@ -1,227 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * global session ID helper functions. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#ifndef _WIN32 -# include -#endif -#include -#include - - -//#define GSI_DEBUG - - -/* create a GSI based on md5 of a user provided data block. - * - * returns TRUE on success, returns FALSE on error and sets error appropriately, - */ - -bool -pgm_gsi_create_from_data ( - pgm_gsi_t* restrict gsi, - const uint8_t* restrict data, - const size_t length - ) -{ - pgm_return_val_if_fail (NULL != gsi, FALSE); - pgm_return_val_if_fail (NULL != data, FALSE); - pgm_return_val_if_fail (length > 1, FALSE); - -#ifdef CONFIG_HAVE_GLIB_CHECKSUM - GChecksum* checksum = g_checksum_new (G_CHECKSUM_MD5); - pgm_return_val_if_fail (NULL != checksum, FALSE); - g_checksum_update (checksum, data, length); - memcpy (gsi, g_checksum_get_string (checksum) + 10, 6); - g_checksum_free (checksum); -#else - struct pgm_md5_t ctx; - char resblock[16]; - pgm_md5_init_ctx (&ctx); - pgm_md5_process_bytes (&ctx, data, length); - pgm_md5_finish_ctx (&ctx, resblock); - memcpy (gsi, resblock + 10, 6); -#endif - return TRUE; -} - -bool -pgm_gsi_create_from_string ( - pgm_gsi_t* restrict gsi, - const char* restrict str, - ssize_t length /* -1 for NULL terminated */ - ) -{ - pgm_return_val_if_fail (NULL != gsi, FALSE); - pgm_return_val_if_fail (NULL != str, FALSE); - - if (length < 0) - length = strlen (str); - - return pgm_gsi_create_from_data (gsi, (const uint8_t*)str, length); -} - -/* create a global session ID as recommended by the PGM draft specification using - * low order 48 bits of md5 of the hostname. - * - * returns TRUE on success, returns FALSE on error and sets error appropriately, - */ - -bool -pgm_gsi_create_from_hostname ( - pgm_gsi_t* restrict gsi, - pgm_error_t** restrict error - ) -{ - pgm_return_val_if_fail (NULL != gsi, FALSE); - - char hostname[NI_MAXHOST]; - int retval = gethostname (hostname, sizeof(hostname)); - if (0 != retval) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("Resolving hostname: %s"), -#ifndef _WIN32 - strerror (errno) -#else - pgm_wsastrerror (WSAGetLastError()) -#endif - ); - return FALSE; - } - - return pgm_gsi_create_from_string (gsi, hostname, -1); -} - -/* create a global session ID based on the IP address. - * - * returns TRUE on succcess, returns FALSE on error and sets error. - */ - -bool -pgm_gsi_create_from_addr ( - pgm_gsi_t* restrict gsi, - pgm_error_t** restrict error - ) -{ - char hostname[NI_MAXHOST]; - struct addrinfo hints, *res = NULL; - - pgm_return_val_if_fail (NULL != gsi, FALSE); - - int retval = gethostname (hostname, sizeof(hostname)); - if (0 != retval) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_errno (errno), - _("Resolving hostname: %s"), -#ifndef _WIN32 - strerror (errno) -#else - pgm_wsastrerror (WSAGetLastError()) -#endif - ); - return FALSE; - } - memset (&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_flags = AI_ADDRCONFIG; - retval = getaddrinfo (hostname, NULL, &hints, &res); - if (0 != retval) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_eai_errno (retval, errno), - _("Resolving hostname address: %s"), - gai_strerror (retval)); - return FALSE; - } - memcpy (gsi, &((struct sockaddr_in*)(res->ai_addr))->sin_addr, sizeof(struct in_addr)); - freeaddrinfo (res); - const uint16_t random_val = pgm_random_int_range (0, UINT16_MAX); - memcpy ((uint8_t*)gsi + sizeof(struct in_addr), &random_val, sizeof(random_val)); - return TRUE; -} - -/* re-entrant form of pgm_gsi_print() - * - * returns number of bytes written to buffer on success, returns -1 on - * invalid parameters. - */ - -int -pgm_gsi_print_r ( - const pgm_gsi_t* restrict gsi, - char* restrict buf, - const size_t bufsize - ) -{ - const uint8_t* restrict src = (const uint8_t* restrict)gsi; - - pgm_return_val_if_fail (NULL != gsi, -1); - pgm_return_val_if_fail (NULL != buf, -1); - pgm_return_val_if_fail (bufsize > 0, -1); - - return snprintf (buf, bufsize, "%i.%i.%i.%i.%i.%i", - src[0], src[1], src[2], src[3], src[4], src[5]); -} - -/* transform GSI to ASCII string form. - * - * on success, returns pointer to ASCII string. on error, returns NULL. - */ - -char* -pgm_gsi_print ( - const pgm_gsi_t* gsi - ) -{ - static char buf[PGM_GSISTRLEN]; - - pgm_return_val_if_fail (NULL != gsi, NULL); - - pgm_gsi_print_r (gsi, buf, sizeof(buf)); - return buf; -} - -/* compare two global session identifier GSI values and return TRUE if they are equal - */ - -bool -pgm_gsi_equal ( - const void* restrict p1, - const void* restrict p2 - ) -{ - const union { - pgm_gsi_t gsi; - uint16_t s[3]; - } *u1 = p1, *u2 = p2; - -/* pre-conditions */ - pgm_assert (NULL != p1); - pgm_assert (NULL != p2); - - return (u1->s[0] == u2->s[0] && u1->s[1] == u2->s[1] && u1->s[2] == u2->s[2]); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/gsi_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/gsi_unittest.c deleted file mode 100644 index dc4c244..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/gsi_unittest.c +++ /dev/null @@ -1,350 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for global session ID helper functions. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - - -/* mock state */ - -static char* mock_localhost = "localhost"; -static char* mock_invalid = "invalid.invalid"; /* RFC 2606 */ -static char* mock_toolong = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij12345"; /* 65 */ -static char* mock_hostname = NULL; - - -static -void -mock_setup_invalid (void) -{ - mock_hostname = mock_invalid; -} - -static -void -mock_setup_toolong (void) -{ - mock_hostname = mock_toolong; -} - -static -void -mock_setup_localhost (void) -{ - mock_hostname = mock_localhost; -} - -static -void -mock_teardown (void) -{ -// null -} - - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - -int -mock_gethostname ( - char* name, - size_t len - ) -{ - if (mock_hostname == mock_toolong) { - errno = EINVAL; - return -1; - } - strncpy (name, mock_hostname, len); - if (len > 0) - name[len - 1] = '\0'; - return 0; -} - - -#define gethostname mock_gethostname - -#define GSI_DEBUG -#include "gsi.c" - - -/* target: - * bool - * pgm_gsi_create_from_hostname ( - * pgm_gsi_t* gsi, - * pgm_error_t** err - * ) - */ - -START_TEST (test_create_from_hostname_pass_001) -{ - pgm_gsi_t gsi; - pgm_error_t* err = NULL; - fail_unless (pgm_gsi_create_from_hostname (&gsi, &err), "create_from_hostname failed"); - fail_if (err, "error raised"); - fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); -} -END_TEST - -START_TEST (test_create_from_hostname_pass_002) -{ - pgm_error_t* err = NULL; - fail_if (pgm_gsi_create_from_hostname (NULL, &err), "create_from_hostname failed"); - fail_if (err, "error raised"); - fail_if (pgm_gsi_create_from_hostname (NULL, NULL), "create_from_hostname failed"); -} -END_TEST - -/* hostname too long */ -START_TEST (test_create_from_hostname_pass_003) -{ - pgm_gsi_t gsi; - pgm_error_t* err = NULL; - fail_if (pgm_gsi_create_from_hostname (&gsi, &err), "create_from_hostname failed"); - fail_if (NULL == err, "error not raised"); - fail_if (NULL == err->message, "no error message"); - g_debug ("pgm_error_t: %s", err->message); - fail_if (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); -} -END_TEST - -/* target: - * bool - * pgm_gsi_create_from_addr ( - * pgm_gsi_t* gsi, - * pgm_error_t** err - * ) - */ - -START_TEST (test_create_from_addr_pass_001) -{ - pgm_gsi_t gsi; - pgm_error_t* err = NULL; - fail_unless (pgm_gsi_create_from_addr (&gsi, &err), "create_from_addr failed"); - fail_if (err, "error raised"); - fail_unless (pgm_gsi_create_from_addr (&gsi, NULL), "create_from_addr failed"); -} -END_TEST - -START_TEST (test_create_from_addr_pass_002) -{ - pgm_error_t* err = NULL; - fail_if (pgm_gsi_create_from_addr (NULL, &err), "create_from_addr failed"); - fail_if (pgm_gsi_create_from_addr (NULL, NULL), "create_from_addr failed"); -} -END_TEST - -/* invalid hostname */ -START_TEST (test_create_from_addr_pass_003) -{ - pgm_gsi_t gsi; - pgm_error_t* err = NULL; - fail_if (pgm_gsi_create_from_addr (&gsi, &err), "create_from_addr failed"); - fail_if (NULL == err, "error not raised"); - fail_if (NULL == err->message, "no error message"); - g_debug ("pgm_error_t: %s", err->message); - fail_if (pgm_gsi_create_from_addr (&gsi, NULL), "create_from_addr failed"); -} -END_TEST - -/* target: - * char* - * pgm_gsi_print ( - * const pgm_gsi_t* gsi - * ) - */ - -START_TEST (test_print_pass_001) -{ - pgm_gsi_t gsi; - fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); - fail_if (NULL == pgm_gsi_print (&gsi), "print failed"); -} -END_TEST - -START_TEST (test_print_pass_002) -{ - fail_unless (NULL == pgm_gsi_print (NULL), "print failed"); -} -END_TEST - -/* target: - * int - * pgm_gsi_print_r ( - * const pgm_gsi_t* gsi, - * char* buf, - * size_t bufsize - * ) - */ - -START_TEST (test_print_r_pass_001) -{ - pgm_gsi_t gsi; - char buf[PGM_GSISTRLEN]; - fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); - fail_unless (pgm_gsi_print_r (&gsi, buf, sizeof(buf)) > 0, "print_r failed"); -} -END_TEST - -START_TEST (test_print_r_pass_002) -{ - pgm_gsi_t gsi; - char buf[PGM_GSISTRLEN]; - fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); - fail_unless (pgm_gsi_print_r (NULL, buf, sizeof(buf)) == -1, "print_r failed"); - fail_unless (pgm_gsi_print_r (&gsi, NULL, sizeof(buf)) == -1, "print_r failed"); - fail_unless (pgm_gsi_print_r (&gsi, buf, 0) == -1, "print_r failed"); -} -END_TEST - -/* target: - * bool - * pgm_gsi_equal ( - * const void* gsi1, - * const void* gsi2 - * ) - */ - -START_TEST (test_equal_pass_001) -{ - pgm_gsi_t gsi1, gsi2; - fail_unless (pgm_gsi_create_from_hostname (&gsi1, NULL), "create_from_hostname failed"); - fail_unless (pgm_gsi_create_from_hostname (&gsi2, NULL), "create_from_hostname failed"); - fail_unless (pgm_gsi_equal (&gsi1, &gsi2), "equal failed"); -} -END_TEST - -START_TEST (test_equal_pass_002) -{ - pgm_gsi_t gsi1, gsi2; - fail_unless (pgm_gsi_create_from_hostname (&gsi1, NULL), "create_from_hostname failed"); - fail_unless (pgm_gsi_create_from_addr (&gsi2, NULL), "create_from_addr failed"); - fail_if (pgm_gsi_equal (&gsi1, &gsi2), "equal failed"); -} -END_TEST - -START_TEST (test_equal_fail_001) -{ - pgm_gsi_t gsi; - fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); - gboolean retval = pgm_gsi_equal (NULL, &gsi); - fail ("reached"); -} -END_TEST - -START_TEST (test_equal_fail_002) -{ - pgm_gsi_t gsi; - fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); - gboolean retval = pgm_gsi_equal (&gsi, NULL); - fail ("reached"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_create_from_hostname = tcase_create ("create-from-hostname"); - suite_add_tcase (s, tc_create_from_hostname); - tcase_add_checked_fixture (tc_create_from_hostname, mock_setup_localhost, mock_teardown); - tcase_add_test (tc_create_from_hostname, test_create_from_hostname_pass_001); - tcase_add_test (tc_create_from_hostname, test_create_from_hostname_pass_002); - - TCase* tc_create_from_hostname2 = tcase_create ("create-from-hostname/2"); - suite_add_tcase (s, tc_create_from_hostname2); - tcase_add_checked_fixture (tc_create_from_hostname2, mock_setup_toolong, mock_teardown); - tcase_add_test (tc_create_from_hostname2, test_create_from_hostname_pass_003); - - TCase* tc_create_from_addr = tcase_create ("create-from-addr"); - suite_add_tcase (s, tc_create_from_addr); - tcase_add_checked_fixture (tc_create_from_addr, mock_setup_localhost, mock_teardown); - tcase_add_test (tc_create_from_addr, test_create_from_addr_pass_001); - tcase_add_test (tc_create_from_addr, test_create_from_addr_pass_002); - - TCase* tc_create_from_addr2 = tcase_create ("create-from-addr/2"); - suite_add_tcase (s, tc_create_from_addr2); - tcase_add_checked_fixture (tc_create_from_addr2, mock_setup_invalid, mock_teardown); - tcase_add_test (tc_create_from_addr2, test_create_from_addr_pass_003); - - TCase* tc_print = tcase_create ("print"); - suite_add_tcase (s, tc_print); - tcase_add_checked_fixture (tc_print, mock_setup_localhost, mock_teardown); - tcase_add_test (tc_print, test_print_pass_001); - tcase_add_test (tc_print, test_print_pass_002); - - TCase* tc_print_r = tcase_create ("print-r"); - suite_add_tcase (s, tc_print_r); - tcase_add_checked_fixture (tc_print_r, mock_setup_localhost, mock_teardown); - tcase_add_test (tc_print_r, test_print_r_pass_001); - tcase_add_test (tc_print_r, test_print_r_pass_002); - - TCase* tc_equal = tcase_create ("equal"); - suite_add_tcase (s, tc_equal); - tcase_add_checked_fixture (tc_equal, mock_setup_localhost, mock_teardown); - tcase_add_test (tc_equal, test_equal_pass_001); - tcase_add_test (tc_equal, test_equal_pass_002); - tcase_add_test_raise_signal (tc_equal, test_equal_fail_001, SIGABRT); - tcase_add_test_raise_signal (tc_equal, test_equal_fail_002, SIGABRT); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/hashtable.c b/3rdparty/openpgm-svn-r1085/pgm/hashtable.c deleted file mode 100644 index da842aa..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/hashtable.c +++ /dev/null @@ -1,327 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable hashtable. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - - -//#define HASHTABLE_DEBUG - -#define HASHTABLE_MIN_SIZE 11 -#define HASHTABLE_MAX_SIZE 13845163 - -struct pgm_hashnode_t -{ - const void* key; - void* value; - struct pgm_hashnode_t* next; - uint_fast32_t key_hash; -}; - -typedef struct pgm_hashnode_t pgm_hashnode_t; - -struct pgm_hashtable_t -{ - unsigned size; - unsigned nnodes; - pgm_hashnode_t** nodes; - pgm_hashfunc_t hash_func; - pgm_equalfunc_t key_equal_func; -}; - -#define PGM_HASHTABLE_RESIZE(hash_ttable) \ - do { \ - if ( (hash_table->size >= 3 * hash_table->nnodes && hash_table->size > HASHTABLE_MIN_SIZE) || \ - (3 * hash_table->size <= hash_table->nnodes && hash_table->size < HASHTABLE_MAX_SIZE) ) \ - { \ - pgm_hashtable_resize (hash_table); \ - } \ - } while (0) - -static void pgm_hashtable_resize (pgm_hashtable_t*); -static pgm_hashnode_t** pgm_hashtable_lookup_node (const pgm_hashtable_t*restrict, const void*restrict, pgm_hash_t*restrict) PGM_GNUC_PURE; -static pgm_hashnode_t* pgm_hash_node_new (const void*restrict, void*restrict, const pgm_hash_t); -static void pgm_hash_node_destroy (pgm_hashnode_t*); -static void pgm_hash_nodes_destroy (pgm_hashnode_t*); - - -pgm_hashtable_t* -pgm_hashtable_new ( - pgm_hashfunc_t hash_func, - pgm_equalfunc_t key_equal_func - ) -{ - pgm_return_val_if_fail (NULL != hash_func, NULL); - pgm_return_val_if_fail (NULL != key_equal_func, NULL); - - pgm_hashtable_t *hash_table; - - hash_table = pgm_new (pgm_hashtable_t, 1); - hash_table->size = HASHTABLE_MIN_SIZE; - hash_table->nnodes = 0; - hash_table->hash_func = hash_func; - hash_table->key_equal_func = key_equal_func; - hash_table->nodes = pgm_new0 (pgm_hashnode_t*, hash_table->size); - - return hash_table; -} - -void -pgm_hashtable_unref ( - pgm_hashtable_t* hash_table - ) -{ - pgm_return_if_fail (hash_table != NULL); - - for (unsigned i = 0; i < hash_table->size; i++) - pgm_hash_nodes_destroy (hash_table->nodes[i]); - pgm_free (hash_table->nodes); - pgm_free (hash_table); -} - -void -pgm_hashtable_destroy ( - pgm_hashtable_t* hash_table - ) -{ - pgm_return_if_fail (hash_table != NULL); - - pgm_hashtable_remove_all (hash_table); - pgm_hashtable_unref (hash_table); -} - -static inline -pgm_hashnode_t** -pgm_hashtable_lookup_node ( - const pgm_hashtable_t* restrict hash_table, - const void* restrict key, - pgm_hash_t* restrict hash_return /* non-NULL to return hash value */ - ) -{ - const pgm_hash_t hash_value = (*hash_table->hash_func) (key); - pgm_hashnode_t** node = &hash_table->nodes[hash_value % hash_table->size]; - - if (hash_return) - *hash_return = hash_value; - - while (*node && (((*node)->key_hash != hash_value) || - !(*hash_table->key_equal_func) ((*node)->key, key))) - { - node = &(*node)->next; - } - - return node; -} - -void* -pgm_hashtable_lookup ( - const pgm_hashtable_t* restrict hash_table, - const void* restrict key - ) -{ - pgm_return_val_if_fail (hash_table != NULL, NULL); - - const pgm_hashnode_t* node = *pgm_hashtable_lookup_node (hash_table, key, NULL); - return node ? node->value : NULL; -} - -void* -pgm_hashtable_lookup_extended ( - const pgm_hashtable_t* restrict hash_table, - const void* restrict key, - void* restrict hash_return - ) -{ - pgm_return_val_if_fail (hash_table != NULL, NULL); - - const pgm_hashnode_t* node = *pgm_hashtable_lookup_node (hash_table, key, hash_return); - return node ? node->value : NULL; -} - -void -pgm_hashtable_insert ( - pgm_hashtable_t* restrict hash_table, - const void* restrict key, - void* restrict value - ) -{ - pgm_hashnode_t **node; - pgm_hash_t key_hash; - - pgm_return_if_fail (hash_table != NULL); - - node = pgm_hashtable_lookup_node (hash_table, key, &key_hash); - pgm_return_if_fail (NULL == *node); - - *node = pgm_hash_node_new (key, value, key_hash); - hash_table->nnodes++; - PGM_HASHTABLE_RESIZE (hash_table); -} - -bool -pgm_hashtable_remove ( - pgm_hashtable_t* restrict hash_table, - const void* restrict key - ) -{ - pgm_hashnode_t **node, *dest; - - pgm_return_val_if_fail (hash_table != NULL, FALSE); - - node = pgm_hashtable_lookup_node (hash_table, key, NULL); - if (*node) - { - dest = *node; - (*node) = dest->next; - pgm_hash_node_destroy (dest); - hash_table->nnodes--; - PGM_HASHTABLE_RESIZE (hash_table); - return TRUE; - } - return FALSE; -} - -void -pgm_hashtable_remove_all ( - pgm_hashtable_t* hash_table - ) -{ - pgm_return_if_fail (hash_table != NULL); - - for (unsigned i = 0; i < hash_table->size; i++) - { - pgm_hash_nodes_destroy (hash_table->nodes[i]); - hash_table->nodes[i] = NULL; - } - hash_table->nnodes = 0; - PGM_HASHTABLE_RESIZE (hash_table); -} - -static -void -pgm_hashtable_resize ( - pgm_hashtable_t* hash_table - ) -{ - const unsigned new_size = CLAMP (pgm_spaced_primes_closest (hash_table->nnodes), - HASHTABLE_MIN_SIZE, HASHTABLE_MAX_SIZE); - pgm_hashnode_t** new_nodes = pgm_new0 (pgm_hashnode_t*, new_size); - - for (unsigned i = 0; i < hash_table->size; i++) - for (pgm_hashnode_t *node = hash_table->nodes[i], *next; node; node = next) - { - next = node->next; - const pgm_hash_t hash_val = node->key_hash % new_size; - node->next = new_nodes[hash_val]; - new_nodes[hash_val] = node; - } - - pgm_free (hash_table->nodes); - hash_table->nodes = new_nodes; - hash_table->size = new_size; -} - -static -pgm_hashnode_t* -pgm_hash_node_new ( - const void* restrict key, - void* restrict value, - const pgm_hash_t key_hash - ) -{ - pgm_hashnode_t *hash_node = pgm_new (pgm_hashnode_t, 1); - hash_node->key = key; - hash_node->value = value; - hash_node->key_hash = key_hash; - hash_node->next = NULL; - return hash_node; -} - -static -void -pgm_hash_node_destroy ( - pgm_hashnode_t* hash_node - ) -{ - pgm_free (hash_node); -} - -static -void -pgm_hash_nodes_destroy ( - pgm_hashnode_t* hash_node - ) -{ - while (hash_node) { - pgm_hashnode_t *next = hash_node->next; - pgm_free (hash_node); - hash_node = next; - } -} - -/* common hash value compare and hash key generation functions */ - -bool -pgm_str_equal ( - const void* restrict p1, - const void* restrict p2 - ) -{ - const char *restrict s1 = p1, *restrict s2 = p2; - return (strcmp (s1, s2) == 0); -} - -/* 31 bit hash function */ - -pgm_hash_t -pgm_str_hash ( - const void* p - ) -{ - const char* s = p; - pgm_hash_t hash_val = *s; - - if (PGM_LIKELY (hash_val)) - for (s++; *s; s++) - hash_val = (hash_val << 5) - hash_val + *s; - return hash_val; -} - -bool -pgm_int_equal ( - const void* restrict p1, - const void* restrict p2 - ) -{ - const int i1 = *(const int*restrict)p1, i2 = *(const int*restrict)p2; - return (i1 == i2); -} - -pgm_hash_t -pgm_int_hash ( - const void* p - ) -{ - const int i = *(const int*)p; - return (pgm_hash_t)i; -} - - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/histogram.c b/3rdparty/openpgm-svn-r1085/pgm/histogram.c deleted file mode 100644 index 3e5ad66..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/histogram.c +++ /dev/null @@ -1,414 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Histograms. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - - -//#define HISTOGRAM_DEBUG - - -pgm_slist_t* pgm_histograms = NULL; - - -static void sample_set_accumulate (pgm_sample_set_t*, pgm_sample_t, pgm_count_t, unsigned); -static pgm_count_t sample_set_total_count (const pgm_sample_set_t*) PGM_GNUC_PURE; - -static void set_bucket_range (pgm_histogram_t*, unsigned, pgm_sample_t); -static void initialize_bucket_range (pgm_histogram_t*); -static unsigned bucket_index (const pgm_histogram_t*, const pgm_sample_t); -static void accumulate (pgm_histogram_t*, pgm_sample_t, pgm_count_t, unsigned); -static double get_peak_bucket_size (const pgm_histogram_t*restrict, const pgm_sample_set_t*restrict); -static double get_bucket_size (const pgm_histogram_t*, const pgm_count_t, const unsigned); - -static void pgm_histogram_write_html_graph (pgm_histogram_t*restrict, pgm_string_t*restrict); -static void write_ascii (pgm_histogram_t*restrict, const char*restrict, pgm_string_t*restrict); -static void write_ascii_header (pgm_histogram_t*restrict, pgm_sample_set_t*restrict, pgm_count_t, pgm_string_t*restrict); -static void write_ascii_bucket_graph (double, double, pgm_string_t*); -static void write_ascii_bucket_context (int64_t, pgm_count_t, int64_t, unsigned, pgm_string_t*); -static void write_ascii_bucket_value (pgm_count_t, double, pgm_string_t*); -static pgm_string_t* get_ascii_bucket_range (pgm_histogram_t*, unsigned); - - -void -pgm_histogram_add ( - pgm_histogram_t* histogram, - int value - ) -{ - if (value > INT_MAX) - value = INT_MAX - 1; - if (value < 0) - value = 0; - const unsigned i = bucket_index (histogram, value); - pgm_assert (value >= histogram->ranges[ i ]); - pgm_assert (value < histogram->ranges[ i + 1 ]); - accumulate (histogram, value, 1, i); -} - -void -pgm_histogram_write_html_graph_all ( - pgm_string_t* string - ) -{ - if (!pgm_histograms) - return; - pgm_slist_t* snapshot = pgm_histograms; - while (snapshot) { - pgm_histogram_t* histogram = snapshot->data; - pgm_histogram_write_html_graph (histogram, string); - snapshot = snapshot->next; - } -} - -static -void -pgm_histogram_write_html_graph ( - pgm_histogram_t* histogram, - pgm_string_t* string - ) -{ - pgm_string_append (string, "
");
-	write_ascii (histogram, "
", string); - pgm_string_append (string, "
"); -} - -static -void -sample_set_accumulate ( - pgm_sample_set_t* sample_set, - pgm_sample_t value, - pgm_count_t count, - unsigned i - ) -{ - pgm_assert (1 == count || -1 == count); - sample_set->counts[ i ] += count; - sample_set->sum += count * value; - sample_set->square_sum += (count * value) * (int64_t)value; - pgm_assert (sample_set->counts[ i ] >= 0); - pgm_assert (sample_set->sum >= 0); - pgm_assert (sample_set->square_sum >= 0); -} - -static -pgm_count_t -sample_set_total_count ( - const pgm_sample_set_t* sample_set - ) -{ - pgm_count_t total = 0; - for (unsigned i = 0; i < sample_set->counts_len; i++) - total += sample_set->counts[ i ]; - return total; -} - -void -pgm_histogram_init ( - pgm_histogram_t* histogram - ) -{ - if (histogram->declared_min <= 0) - histogram->declared_min = 1; - pgm_assert (histogram->declared_min > 0); - histogram->declared_max = INT_MAX - 1; - pgm_assert (histogram->declared_min <= histogram->declared_max); - pgm_assert (1 < histogram->bucket_count); - set_bucket_range (histogram, histogram->bucket_count, INT_MAX); - initialize_bucket_range (histogram); - -/* register with global list */ - histogram->histograms_link.data = histogram; - histogram->histograms_link.next = pgm_histograms; - pgm_histograms = &histogram->histograms_link; - histogram->is_registered = TRUE; -} - -static -void -set_bucket_range ( - pgm_histogram_t* histogram, - unsigned i, - pgm_sample_t value - ) -{ - histogram->ranges[ i ] = value; -} - -static -void -initialize_bucket_range ( - pgm_histogram_t* histogram - ) -{ - const double log_max = log(histogram->declared_max); - double log_ratio; - double log_next; - unsigned i = 1; - pgm_sample_t current = histogram->declared_min; - - set_bucket_range (histogram, i, current); - while (histogram->bucket_count > ++i) { - double log_current = log(current); - log_ratio = (log_max - log_current) / (histogram->bucket_count - i); - log_next = log_current + log_ratio; - int next = floor(exp(log_next) + 0.5); - if (next > current) - current = next; - else - current++; - set_bucket_range (histogram, i, current); - } - pgm_assert (histogram->bucket_count == i); -} - -static -unsigned -bucket_index ( - const pgm_histogram_t* histogram, - const pgm_sample_t value - ) -{ - pgm_assert (histogram->ranges[0] <= value); - pgm_assert (histogram->ranges[ histogram->bucket_count ] > value); - unsigned under = 0; - unsigned over = histogram->bucket_count; - unsigned mid; - - do { - pgm_assert (over >= under); - mid = ((unsigned)under + (unsigned)over) >> 1; - if (mid == under) - break; - if (histogram->ranges[ mid ] <= value) - under = mid; - else - over = mid; - } while (TRUE); - pgm_assert (histogram->ranges[ mid ] <= value && - histogram->ranges[ mid + 1] > value); - return mid; -} - -static -void -accumulate ( - pgm_histogram_t* histogram, - pgm_sample_t value, - pgm_count_t count, - unsigned i - ) -{ - sample_set_accumulate (&histogram->sample, value, count, i); -} - -static -void -write_ascii ( - pgm_histogram_t* restrict histogram, - const char* restrict newline, - pgm_string_t* restrict output - ) -{ - pgm_count_t snapshot_counts[ histogram->sample.counts_len ]; - pgm_sample_set_t snapshot = { - .counts = snapshot_counts, - .counts_len = histogram->sample.counts_len, - .sum = histogram->sample.sum, - .square_sum = histogram->sample.square_sum - }; - memcpy (snapshot_counts, histogram->sample.counts, sizeof(pgm_count_t) * histogram->sample.counts_len); - - pgm_count_t sample_count = sample_set_total_count (&snapshot); - write_ascii_header (histogram, &snapshot, sample_count, output); - pgm_string_append (output, newline); - - double max_size = get_peak_bucket_size (histogram, &snapshot); - unsigned largest_non_empty_bucket = histogram->bucket_count - 1; - while (0 == snapshot.counts[ largest_non_empty_bucket ]) - { - if (0 == largest_non_empty_bucket) - break; - largest_non_empty_bucket--; - } - - int print_width = 1; - for (unsigned i = 0; i < histogram->bucket_count; ++i) - { - if (snapshot.counts[ i ]) { - pgm_string_t* bucket_range = get_ascii_bucket_range (histogram, i); - const int width = bucket_range->len + 1; - pgm_string_free (bucket_range, TRUE); - if (width > print_width) - print_width = width; - } - } - - int64_t remaining = sample_count; - int64_t past = 0; - for (unsigned i = 0; i < histogram->bucket_count; ++i) - { - pgm_count_t current = snapshot.counts[ i ]; - remaining -= current; - pgm_string_t* bucket_range = get_ascii_bucket_range (histogram, i); - pgm_string_append_printf (output, "%*s ", print_width, bucket_range->str); - pgm_string_free (bucket_range, TRUE); - if (0 == current && - i < histogram->bucket_count - 1 && - 0 == snapshot.counts[ i + 1 ]) - { - while (i < histogram->bucket_count - 1 && - 0 == snapshot.counts[ i + 1 ]) - { - i++; - } - pgm_string_append (output, "... "); - pgm_string_append (output, newline); - continue; - } - - const double current_size = get_bucket_size (histogram, current, i); - write_ascii_bucket_graph (current_size, max_size, output); - write_ascii_bucket_context (past, current, remaining, i, output); - pgm_string_append (output, newline); - past += current; - } -} - -static -void -write_ascii_header ( - pgm_histogram_t* restrict histogram, - pgm_sample_set_t* restrict sample_set, - pgm_count_t sample_count, - pgm_string_t* restrict output - ) -{ - pgm_string_append_printf (output, - "Histogram: %s recorded %d samples", - histogram->histogram_name ? histogram->histogram_name : "(null)", - sample_count); - if (sample_count > 0) { - const double average = sample_set->sum / sample_count; - const double variance = sample_set->square_sum / sample_count - - average * average; - const double standard_deviation = sqrt (variance); - pgm_string_append_printf (output, - ", average = %.1f, standard deviation = %.1f", - average, standard_deviation); - } -} - -static -void -write_ascii_bucket_graph ( - double current_size, - double max_size, - pgm_string_t* output - ) -{ - static const int k_line_length = 72; - int x_count = (k_line_length * (current_size / max_size) + 0.5); - int x_remainder = k_line_length - x_count; - while (0 < x_count--) - pgm_string_append_c (output, '-'); - pgm_string_append_c (output, 'O'); - while (0 < x_remainder--) - pgm_string_append_c (output, ' '); -} - -static -void -write_ascii_bucket_context ( - int64_t past, - pgm_count_t current, - int64_t remaining, - unsigned i, - pgm_string_t* output - ) -{ - const double scaled_sum = (past + current + remaining) / 100.0; - write_ascii_bucket_value (current, scaled_sum, output); - if (0 < i) { - const double percentage = past / scaled_sum; - pgm_string_append_printf (output, " {%3.1f%%}", percentage); - } -} - -static -void -write_ascii_bucket_value ( - pgm_count_t current, - double scaled_sum, - pgm_string_t* output - ) -{ - pgm_string_append_printf (output, " (%d = %3.1f%%)", current, current/scaled_sum); -} - -static -double -get_peak_bucket_size ( - const pgm_histogram_t* restrict histogram, - const pgm_sample_set_t* restrict sample_set - ) -{ - double max_size = 0; - for (unsigned i = 0; i < histogram->bucket_count; i++) { - const double current_size = get_bucket_size (histogram, sample_set->counts[ i ], i); - if (current_size > max_size) - max_size = current_size; - } - return max_size; -} - -static -double -get_bucket_size ( - const pgm_histogram_t* histogram, - const pgm_count_t current, - const unsigned i - ) -{ - pgm_assert (histogram->ranges[ i + 1 ] > histogram->ranges[ i ]); - static const double kTransitionWidth = 5; - double denominator = histogram->ranges[ i + 1 ] - histogram->ranges[ i ]; - if (denominator > kTransitionWidth) - denominator = kTransitionWidth; - return current / denominator; -} - -static -pgm_string_t* -get_ascii_bucket_range ( - pgm_histogram_t* histogram, - unsigned i - ) -{ - pgm_string_t* result = pgm_string_new (NULL); - pgm_string_printf (result, "%d", histogram->ranges[ i ]); - return result; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/htdocs/404.html b/3rdparty/openpgm-svn-r1085/pgm/htdocs/404.html deleted file mode 100644 index 538c90a..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/htdocs/404.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - OpenPGM - Page Not Found - - - -

Lah, page not found.

-

Return to main page

- - diff --git a/3rdparty/openpgm-svn-r1085/pgm/htdocs/base.css b/3rdparty/openpgm-svn-r1085/pgm/htdocs/base.css deleted file mode 100644 index 5aba236..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/htdocs/base.css +++ /dev/null @@ -1,136 +0,0 @@ -html { - background-color: white; - font-family: Verdana; - font-size: 12px; - color: black; -} - -a, a:link, a:visited { - color: #0033cc; - text-decoration: none; -} - -#header { - text-align: right; -} - -#header #hostname { - font-weight: bold; -} - -#header a { - color: black; -} - -#header a:hover { - text-decoration: underline; -} - -#footer { - clear: both; - margin-top: 3.5em; - margin-bottom: 1em; - padding-top: 20px; - text-align: center; -} - -#navigation a { - color: black; -} - -#navigation .tab { - -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; - -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; - padding: 4px 1em 2px; - margin-right: 8px; - float: left; - font-weight: bold; -} - -#navigation #tabtop,#tabline { - background-color: #fb879c; -} - -#navigation #tabbottom { - background-color: #fbc1a9; -} - -#navigation #tabline { - clear: left; - -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; - height: 4px; -} - -#content { - margin-top: 6px; - padding: 3px; -} - -#content a:hover { - background: #ffffaa; -} - -.heading { - -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; - -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; - background-color: #fb879c; - padding: 6px; - margin-bottom: 3px; -} - -table { - border-collapse: separate; -} - -th { - text-align: left; -} - -#information { - float: right; -} - -.rounded { - background-color: #fbc1a9; - -moz-border-radius: 4px; -webkit-border-radius: 4px; - padding: 5px; - margin-top: 6px; - margin-bottom: 6px; - width: 25em; -} - -.break { - border-top: 3px solid white; - margin-top: 1em; - padding-top: 6px; -} - -.bubbly { - background-color: #fb879c; - -moz-border-radius: 4px; -webkit-border-radius: 4px; - padding: 4px; -} - -.bubbly table { - width: 100%; -} - -.bubbly th,.bubbly td { - border-bottom: 1px solid #bbbbbb; -} - -.bubbly th { - background-color: #fbc1a9; - border-left: 1px solid #bbbbbb; - padding: 2px 1px 2px 2px; -} - -.bubbly td { - background-color: white; - padding: 4px; -} - -.bubbly .empty { - padding: 3em; - text-align: center; -} diff --git a/3rdparty/openpgm-svn-r1085/pgm/htdocs/convert_to_macro.pl b/3rdparty/openpgm-svn-r1085/pgm/htdocs/convert_to_macro.pl deleted file mode 100755 index bea44af..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/htdocs/convert_to_macro.pl +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/perl - -use strict; -use File::Basename; - -die "usage: $0 [text file]\n" unless ($ARGV[0]); -open(MOO, $ARGV[0]) or die "cannot open $ARGV[0]: $!"; -my $all = do { local $/; }; -close(MOO); -$all =~ s/"/\\"/g; -$all =~ s/\n/\\n/mg; -$all =~ s/\r/\\r/mg; - -my $var = uc (basename($ARGV[0])); -$var =~ s/\s+/_/g; -$var =~ s/\./_/g; - -print< - - diff --git a/3rdparty/openpgm-svn-r1085/pgm/http.c b/3rdparty/openpgm-svn-r1085/pgm/http.c deleted file mode 100644 index 82e934c..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/http.c +++ /dev/null @@ -1,1718 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * HTTP administrative interface - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#ifndef _WIN32 -# include -#else -# include -# include -# include -#endif -#include -#include -#include -#include -#include -#include -#include - -#include "pgm/http.h" -#include "htdocs/404.html.h" -#include "htdocs/base.css.h" -#include "htdocs/robots.txt.h" -#include "htdocs/xhtml10_strict.doctype.h" - - -/* OpenSolaris */ -#ifndef LOGIN_NAME_MAX -# ifdef _WIN32 -# define LOGIN_NAME_MAX (UNLEN + 1) -# else -# define LOGIN_NAME_MAX 256 -# endif -#endif - -#ifdef _WIN32 -# define getpid _getpid -# define read _read -# define write _write -# define SHUT_WR SD_SEND -#endif - -#ifdef CONFIG_HAVE_SPRINTF_GROUPING -# define GROUP_FORMAT "'" -#else -# define GROUP_FORMAT "" -#endif - -#define HTTP_BACKLOG 10 /* connections */ -#define HTTP_TIMEOUT 60 /* seconds */ - - -/* locals */ - -struct http_connection_t { - pgm_list_t link_; - int sock; - enum { - HTTP_STATE_READ, - HTTP_STATE_WRITE, - HTTP_STATE_FINWAIT - } state; - - char* buf; - size_t buflen; - size_t bufoff; - unsigned status_code; - const char* status_text; - const char* content_type; -}; - -enum { - HTTP_MEMORY_STATIC, - HTTP_MEMORY_TAKE -}; - -static char http_hostname[NI_MAXHOST + 1]; -static char http_address[INET6_ADDRSTRLEN]; -static char http_username[LOGIN_NAME_MAX + 1]; -static int http_pid; - -#ifndef _WIN32 -static int http_sock = -1; -static pthread_t http_thread; -static void* http_routine (void*); -#else -static int http_sock = INVALID_SOCKET; -static HANDLE http_thread; -static unsigned __stdcall http_routine (void*); -#endif -static int http_max_sock = -1; -static fd_set http_readfds, http_writefds, http_exceptfds; -static pgm_list_t* http_socks = NULL; -static pgm_notify_t http_notify = PGM_NOTIFY_INIT; -static volatile uint32_t http_ref_count = 0; - - -static int http_tsi_response (struct http_connection_t*, pgm_tsi_t*); -static void http_each_receiver (pgm_peer_t*, pgm_string_t*); -static int http_receiver_response (struct http_connection_t*, pgm_peer_t*); - -static void default_callback (struct http_connection_t*, const char*); -static void robots_callback (struct http_connection_t*, const char*); -static void css_callback (struct http_connection_t*, const char*); -static void index_callback (struct http_connection_t*, const char*); -static void interfaces_callback (struct http_connection_t*, const char*); -static void transports_callback (struct http_connection_t*, const char*); -static void histograms_callback (struct http_connection_t*, const char*); - -static struct { - const char* path; - void (*callback) (struct http_connection_t*, const char*); -} http_directory[] = { - { "/robots.txt", robots_callback }, - { "/base.css", css_callback }, - { "/", index_callback }, - { "/interfaces", interfaces_callback }, - { "/transports", transports_callback } -#ifdef CONFIG_HISTOGRAMS - ,{ "/histograms", histograms_callback } -#endif -}; - - -static -int -http_sock_rcvtimeo ( - int sock, - int seconds - ) -{ -#if defined( sun ) - return 0; -#elif !defined( _WIN32 ) - const struct timeval timeout = { .tv_sec = seconds, .tv_usec = 0 }; - return setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)); -#else - const int optval = seconds * 1000; - return setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&optval, sizeof(optval)); -#endif -} - -static -int -http_sock_sndtimeo ( - int sock, - int seconds - ) -{ -#if defined( sun ) - return 0; -#elif !defined( _WIN32 ) - const struct timeval timeout = { .tv_sec = seconds, .tv_usec = 0 }; - return setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout)); -#else - const int optval = seconds * 1000; - return setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&optval, sizeof(optval)); -#endif -} - -bool -pgm_http_init ( - uint16_t http_port, - pgm_error_t** error - ) -{ - int e; - - if (pgm_atomic_exchange_and_add32 (&http_ref_count, 1) > 0) - return TRUE; - -/* resolve and store relatively constant runtime information */ - if (0 != gethostname (http_hostname, sizeof(http_hostname))) { - const int save_errno = errno; - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_errno (save_errno), - _("Resolving hostname: %s"), - strerror (save_errno)); - goto err_cleanup; - } - struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - .ai_protocol = IPPROTO_TCP, - .ai_flags = AI_ADDRCONFIG - }, *res = NULL; - e = getaddrinfo (http_hostname, NULL, &hints, &res); - if (0 != e) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_eai_errno (e, errno), - _("Resolving hostname address: %s"), - gai_strerror (e)); - goto err_cleanup; - } - e = getnameinfo (res->ai_addr, res->ai_addrlen, - http_address, sizeof(http_address), - NULL, 0, - NI_NUMERICHOST); - if (0 != e) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_eai_errno (e, errno), - _("Resolving numeric hostname: %s"), - gai_strerror (e)); - goto err_cleanup; - } - freeaddrinfo (res); -#ifndef _WIN32 - e = getlogin_r (http_username, sizeof(http_username)); - if (0 != e) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_errno (errno), - _("Retrieving user name: %s"), - strerror (errno)); - goto err_cleanup; - } -#else - wchar_t wusername[UNLEN + 1]; - DWORD nSize = PGM_N_ELEMENTS( wusername ); - if (!GetUserNameW (wusername, &nSize)) { - const DWORD save_errno = GetLastError(); - char winstr[1024]; - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_win_errno (save_errno), - _("Retrieving user name: %s"), - pgm_win_strerror (winstr, sizeof(winstr), save_errno)); - goto err_cleanup; - } - WideCharToMultiByte (CP_UTF8, 0, wusername, nSize + 1, http_username, sizeof(http_username), NULL, NULL); -#endif /* _WIN32 */ - http_pid = getpid(); - -/* create HTTP listen socket */ - if ((http_sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) { -#ifndef _WIN32 - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_errno (errno), - _("Creating HTTP socket: %s"), - strerror (errno)); -#else - const int save_errno = WSAGetLastError(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_wsa_errno (save_errno), - _("Creating HTTP socket: %s"), - pgm_wsastrerror (save_errno)); -#endif - goto err_cleanup; - } - const int v = 1; - if (0 != setsockopt (http_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&v, sizeof(v))) { -#ifndef _WIN32 - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_errno (errno), - _("Enabling reuse of socket local address: %s"), - strerror (errno)); -#else - const int save_errno = WSAGetLastError(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_wsa_errno (save_errno), - _("Enabling reuse of socket local address: %s"), - pgm_wsastrerror (save_errno)); -#endif - goto err_cleanup; - } - if (0 != http_sock_rcvtimeo (http_sock, HTTP_TIMEOUT) || - 0 != http_sock_sndtimeo (http_sock, HTTP_TIMEOUT)) { -#ifndef _WIN32 - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_errno (errno), - _("Setting socket timeout: %s"), - strerror (errno)); -#else - const int save_errno = WSAGetLastError(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_wsa_errno (save_errno), - _("Setting socket timeout: %s"), - pgm_wsastrerror (save_errno)); -#endif - goto err_cleanup; - } - struct sockaddr_in http_addr; - memset (&http_addr, 0, sizeof(http_addr)); - http_addr.sin_family = AF_INET; - http_addr.sin_addr.s_addr = INADDR_ANY; - http_addr.sin_port = htons (http_port); - if (0 != bind (http_sock, (struct sockaddr*)&http_addr, sizeof(http_addr))) { - char addr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&http_addr, addr, sizeof(addr)); -#ifndef _WIN32 - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_errno (errno), - _("Binding HTTP socket to address %s: %s"), - addr, - strerror (errno)); -#else - const int save_errno = WSAGetLastError(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_wsa_errno (save_errno), - _("Binding HTTP socket to address %s: %s"), - addr, - pgm_wsastrerror (save_errno)); -#endif - goto err_cleanup; - } - if (listen (http_sock, HTTP_BACKLOG) < 0) { -#ifndef _WIN32 - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_errno (errno), - _("Listening to HTTP socket: %s"), - strerror (errno)); -#else - const int save_errno = WSAGetLastError(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_wsa_errno (save_errno), - _("Listening to HTTP socket: %s"), - pgm_wsastrerror (save_errno)); -#endif - goto err_cleanup; - } - -/* non-blocking notification of new connections */ - pgm_sockaddr_nonblocking (http_sock, TRUE); - -/* create notification channel */ - if (0 != pgm_notify_init (&http_notify)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_errno (errno), - _("Creating HTTP notification channel: %s"), - strerror (errno)); - goto err_cleanup; - } - -/* spawn thread to handle HTTP requests */ -#ifndef _WIN32 - const int status = pthread_create (&http_thread, NULL, &http_routine, NULL); - if (0 != status) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_errno (errno), - _("Creating HTTP thread: %s"), - strerror (errno)); - goto err_cleanup; - } -#else - http_thread = (HANDLE)_beginthreadex (NULL, 0, &http_routine, NULL, 0, NULL); - const int save_errno = errno; - if (0 == http_thread) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_HTTP, - pgm_error_from_errno (save_errno), - _("Creating HTTP thread: %s"), - strerror (save_errno)); - goto err_cleanup; - } -#endif /* _WIN32 */ - pgm_minor (_("Web interface: http://%s:%i"), - http_hostname, - http_port); - return TRUE; - -err_cleanup: -#ifndef _WIN32 - if (-1 != http_sock) { - close (http_sock); - http_sock = -1; - } -#else - if (INVALID_SOCKET != http_sock) { - closesocket (http_sock); - http_sock = INVALID_SOCKET; - } -#endif /* _WIN32 */ - if (pgm_notify_is_valid (&http_notify)) { - pgm_notify_destroy (&http_notify); - } - pgm_atomic_dec32 (&http_ref_count); - return FALSE; -} - -/* notify HTTP thread to shutdown, wait for shutdown and cleanup. - */ - -bool -pgm_http_shutdown (void) -{ - pgm_return_val_if_fail (pgm_atomic_read32 (&http_ref_count) > 0, FALSE); - - if (pgm_atomic_exchange_and_add32 (&http_ref_count, (uint32_t)-1) != 1) - return TRUE; - - pgm_notify_send (&http_notify); -#ifndef _WIN32 - pthread_join (http_thread, NULL); -#else - CloseHandle (http_thread); -#endif -#ifndef _WIN32 - if (-1 != http_sock) { - close (http_sock); - http_sock = -1; - } -#else - if (INVALID_SOCKET != http_sock) { - closesocket (http_sock); - http_sock = INVALID_SOCKET; - } -#endif /* _WIN32 */ - pgm_notify_destroy (&http_notify); - return TRUE; -} - -/* accept a new incoming HTTP connection. - */ - -static -void -http_accept ( - int listen_sock - ) -{ -/* new connection */ - struct sockaddr_storage addr; - socklen_t addrlen = sizeof(addr); - int new_sock = accept (listen_sock, (struct sockaddr*)&addr, &addrlen); - if (-1 == new_sock) { - if (EAGAIN == errno) - return; -#ifndef _WIN32 - pgm_warn (_("HTTP accept: %s"), strerror (errno)); -#else - const int save_errno = WSAGetLastError(); - pgm_warn (_("HTTP accept: %s"), pgm_wsastrerror (save_errno)); -#endif - return; - } - -#ifndef _WIN32 -/* out of bounds file descriptor for select() */ - if (new_sock >= FD_SETSIZE) { - close (new_sock); - pgm_warn (_("Rejected new HTTP client socket due to out of bounds file descriptor.")); - return; - } -#endif - - pgm_sockaddr_nonblocking (new_sock, TRUE); - - struct http_connection_t* connection = pgm_new0 (struct http_connection_t, 1); - connection->sock = new_sock; - connection->state = HTTP_STATE_READ; - http_socks = pgm_list_prepend_link (http_socks, &connection->link_); - FD_SET( new_sock, &http_readfds ); - FD_SET( new_sock, &http_exceptfds ); - if (new_sock > http_max_sock) - http_max_sock = new_sock; -} - -static -void -http_close ( - struct http_connection_t* connection - ) -{ -#ifndef _WIN32 - if (0 != close (connection->sock)) { - pgm_warn (_("Close HTTP client socket: %s"), strerror (errno)); - } -#else - if (0 != closesocket (connection->sock)) { - const int save_errno = WSAGetLastError(); - pgm_warn (_("Close HTTP client socket: %s"), pgm_wsastrerror (save_errno)); - } -#endif - switch (connection->state) { - case HTTP_STATE_READ: - case HTTP_STATE_FINWAIT: - FD_CLR( connection->sock, &http_readfds ); - break; - case HTTP_STATE_WRITE: - FD_CLR( connection->sock, &http_writefds ); - break; - } - FD_CLR( connection->sock, &http_exceptfds ); - http_socks = pgm_list_remove_link (http_socks, &connection->link_); - if (connection->buflen > 0) { - pgm_free (connection->buf); - connection->buf = NULL; - connection->buflen = 0; - } -/* find new highest fd */ - if (connection->sock == http_max_sock) - { - http_max_sock = -1; - for (pgm_list_t* list = http_socks; list; list = list->next) - { - struct http_connection_t* c = (void*)list; - if (c->sock > http_max_sock) - http_max_sock = c->sock; - } - } - pgm_free (connection); -} - -/* non-blocking read an incoming HTTP request - */ - -static -void -http_read ( - struct http_connection_t* connection - ) -{ - for (;;) - { -/* grow buffer as needed */ - if (connection->bufoff + 1024 > connection->buflen) { - connection->buf = pgm_realloc (connection->buf, connection->buflen + 1024); - connection->buflen += 1024; - } - const ssize_t bytes_read = recv (connection->sock, &connection->buf[ connection->bufoff ], connection->buflen - connection->bufoff, 0); - if (bytes_read < 0) { - if (EINTR == errno || EAGAIN == errno) - return; -#ifndef _WIN32 - pgm_warn (_("HTTP client read: %s"), strerror (errno)); -#else - const int save_errno = WSAGetLastError(); - pgm_warn (_("HTTP client read: %s"), pgm_wsastrerror (save_errno)); -#endif - http_close (connection); - return; - } - -/* complete */ - if (strstr (connection->buf, "\r\n\r\n")) - break; - } - -/* process request, e.g. GET /index.html HTTP/1.1\r\n - */ - connection->buf[ connection->buflen - 1 ] = '\0'; - if (0 != memcmp (connection->buf, "GET ", strlen("GET "))) { -/* 501 (not implemented) */ - http_close (connection); - return; - } - - char* request_uri = connection->buf + strlen("GET "); - char* p = request_uri; - do { - if (*p == '?' || *p == ' ') { - *p = '\0'; - break; - } - } while (*(++p)); - - connection->status_code = 200; /* OK */ - connection->status_text = "OK"; - connection->content_type = "text/html"; - connection->bufoff = 0; - for (unsigned i = 0; i < PGM_N_ELEMENTS(http_directory); i++) - { - if (0 == strcmp (request_uri, http_directory[i].path)) - { - http_directory[i].callback (connection, request_uri); - goto complete; - } - } - default_callback (connection, request_uri); - -complete: - connection->state = HTTP_STATE_WRITE; - FD_CLR( connection->sock, &http_readfds ); - FD_SET( connection->sock, &http_writefds ); -} - -/* non-blocking write a HTTP response - */ - -static -void -http_write ( - struct http_connection_t* connection - ) -{ - do { - const ssize_t bytes_written = send (connection->sock, &connection->buf[ connection->bufoff ], connection->buflen - connection->bufoff, 0); - if (bytes_written < 0) { - if (EINTR == errno || EAGAIN == errno) - return; -#ifndef _WIN32 - pgm_warn (_("HTTP client write: %s"), strerror (errno)); -#else - const int save_errno = WSAGetLastError(); - pgm_warn (_("HTTP client write: %s"), pgm_wsastrerror (save_errno)); -#endif - http_close (connection); - return; - } - connection->bufoff += bytes_written; - } while (connection->bufoff < connection->buflen); - - if (0 == shutdown (connection->sock, SHUT_WR)) { - http_close (connection); - } else { - pgm_debug ("HTTP socket entering finwait state."); - connection->state = HTTP_STATE_FINWAIT; - FD_CLR( connection->sock, &http_writefds ); - FD_SET( connection->sock, &http_readfds ); - } -} - -/* read and discard pending data waiting for FIN - */ - -static -void -http_finwait ( - struct http_connection_t* connection - ) -{ - char buf[1024]; - const ssize_t bytes_read = read (connection->sock, buf, sizeof(buf)); - if (bytes_read < 0 && (EINTR == errno || EAGAIN == errno)) - return; - http_close (connection); -} - -static -void -http_process ( - struct http_connection_t* connection - ) -{ - switch (connection->state) { - case HTTP_STATE_READ: http_read (connection); break; - case HTTP_STATE_WRITE: http_write (connection); break; - case HTTP_STATE_FINWAIT: http_finwait (connection); break; - } -} - -static -void -http_set_status ( - struct http_connection_t* connection, - int status_code, - const char* status_text - ) -{ - connection->status_code = status_code; - connection->status_text = status_text; -} - -static -void -http_set_content_type ( - struct http_connection_t* connection, - const char* content_type - ) -{ - connection->content_type = content_type; -} - -/* finalise response buffer with headers and content */ - -static -void -http_set_static_response ( - struct http_connection_t* connection, - const char* content, - size_t content_length - ) -{ - pgm_string_t* response = pgm_string_new (NULL); - pgm_string_printf (response, "HTTP/1.0 %d %s\r\n" - "Server: OpenPGM HTTP Server %u.%u.%u\r\n" - "Last-Modified: Fri, 1 Jan 2010, 00:00:01 GMT\r\n" - "Content-Length: %d\r\n" - "Content-Type: %s\r\n" - "Connection: close\r\n" - "\r\n", - connection->status_code, - connection->status_text, - pgm_major_version, pgm_minor_version, pgm_micro_version, - content_length, - connection->content_type - ); - pgm_string_append (response, content); - if (connection->buflen) - pgm_free (connection->buf); - connection->buflen = response->len; - connection->buf = pgm_string_free (response, FALSE); -} - -static -void -http_set_response ( - struct http_connection_t* connection, - char* content, - size_t content_length - ) -{ - pgm_string_t* response = pgm_string_new (NULL); - pgm_string_printf (response, "HTTP/1.0 %d %s\r\n" - "Server: OpenPGM HTTP Server %u.%u.%u\r\n" - "Content-Length: %d\r\n" - "Content-Type: %s\r\n" - "Connection: close\r\n" - "\r\n", - connection->status_code, - connection->status_text, - pgm_major_version, pgm_minor_version, pgm_micro_version, - content_length, - connection->content_type - ); - pgm_string_append (response, content); - pgm_free (content); - if (connection->buflen) - pgm_free (connection->buf); - connection->buflen = response->len; - connection->buf = pgm_string_free (response, FALSE); -} - -/* Thread routine for processing HTTP requests - */ - -static -#ifndef _WIN32 -void* -#else -unsigned -__stdcall -#endif -http_routine ( - PGM_GNUC_UNUSED void* arg - ) -{ - const int notify_fd = pgm_notify_get_fd (&http_notify); - const int max_fd = MAX( notify_fd, http_sock ); - - FD_ZERO( &http_readfds ); - FD_ZERO( &http_writefds ); - FD_ZERO( &http_exceptfds ); - FD_SET( notify_fd, &http_readfds ); - FD_SET( http_sock, &http_readfds ); - - for (;;) - { - int fds = MAX( http_max_sock, max_fd ) + 1; - fd_set readfds = http_readfds, writefds = http_writefds, exceptfds = http_exceptfds; - - fds = select (fds, &readfds, &writefds, &exceptfds, NULL); -/* signal interrupt */ - if (PGM_UNLIKELY(fds < 0 && EINTR == errno)) - continue; -/* terminate */ - if (PGM_UNLIKELY(FD_ISSET( notify_fd, &readfds ))) - break; -/* new connection */ - if (FD_ISSET( http_sock, &readfds )) { - http_accept (http_sock); - continue; - } -/* existing connection */ - for (pgm_list_t* list = http_socks; list;) - { - struct http_connection_t* c = (void*)list; - list = list->next; - if ((FD_ISSET( c->sock, &readfds ) && HTTP_STATE_READ == c->state) || - (FD_ISSET( c->sock, &writefds ) && HTTP_STATE_WRITE == c->state) || - (FD_ISSET( c->sock, &exceptfds ))) - { - http_process (c); - } - } - } - -/* cleanup */ -#ifndef _WIN32 - return NULL; -#else - _endthread(); - return 0; -#endif /* WIN32 */ -} - -/* add xhtml doctype and head, populate with runtime values - */ - -typedef enum { - HTTP_TAB_GENERAL_INFORMATION, - HTTP_TAB_INTERFACES, - HTTP_TAB_TRANSPORTS, - HTTP_TAB_HISTOGRAMS -} http_tab_e; - -static -pgm_string_t* -http_create_response ( - const char* subtitle, - http_tab_e tab - ) -{ - pgm_assert (NULL != subtitle); - pgm_assert (tab == HTTP_TAB_GENERAL_INFORMATION || - tab == HTTP_TAB_INTERFACES || - tab == HTTP_TAB_TRANSPORTS || - tab == HTTP_TAB_HISTOGRAMS); - -/* surprising deficiency of GLib is no support of display locale time */ - char timestamp[100]; - time_t now; - time (&now); - const struct tm* time_ptr = localtime (&now); -#ifndef _WIN32 - strftime (timestamp, sizeof(timestamp), "%c", time_ptr); -#else - wchar_t wtimestamp[100]; - const size_t slen = strftime (timestamp, sizeof(timestamp), "%c", time_ptr); - const size_t wslen = MultiByteToWideChar (CP_ACP, 0, timestamp, slen, wtimestamp, 100); - WideCharToMultiByte (CP_UTF8, 0, wtimestamp, wslen + 1, timestamp, sizeof(timestamp), NULL, NULL); -#endif - - pgm_string_t* response = pgm_string_new (WWW_XHTML10_STRICT_DOCTYPE); - pgm_string_append_printf (response, "\n" - "%s - %s" - "" - "\n" - "" - "
" - "%s" - " | OpenPGM %u.%u.%u" - " | %s" - "
" - "
" - "General Information" - "Interfaces" - "Transports" -#ifdef CONFIG_HISTOGRAMS - "Histograms" -#endif - "
" - "
" - "
", - http_hostname, - subtitle, - http_hostname, - pgm_major_version, pgm_minor_version, pgm_micro_version, - timestamp, - tab == HTTP_TAB_GENERAL_INFORMATION ? "top" : "bottom", - tab == HTTP_TAB_INTERFACES ? "top" : "bottom", - tab == HTTP_TAB_TRANSPORTS ? "top" : "bottom" -#ifdef CONFIG_HISTOGRAMS - ,tab == HTTP_TAB_HISTOGRAMS ? "top" : "bottom" -#endif - ); - - return response; -} - -static -void -http_finalize_response ( - struct http_connection_t* connection, - pgm_string_t* response - ) -{ - pgm_string_append (response, "
" - "
" - "©2010 Miru" - "
" - "\n" - ""); - - char* buf = pgm_string_free (response, FALSE); - http_set_response (connection, buf, strlen (buf)); -} - -static -void -robots_callback ( - struct http_connection_t* connection, - PGM_GNUC_UNUSED const char* path - ) -{ - http_set_content_type (connection, "text/plain"); - http_set_static_response (connection, WWW_ROBOTS_TXT, strlen(WWW_ROBOTS_TXT)); -} - -static -void -css_callback ( - struct http_connection_t* connection, - PGM_GNUC_UNUSED const char* path - ) -{ - http_set_content_type (connection, "text/css"); - http_set_static_response (connection, WWW_BASE_CSS, strlen(WWW_BASE_CSS)); -} - -static -void -index_callback ( - struct http_connection_t* connection, - const char* path - ) -{ - if (strlen (path) > 1) { - default_callback (connection, path); - return; - } - pgm_rwlock_reader_lock (&pgm_sock_list_lock); - const unsigned transport_count = pgm_slist_length (pgm_sock_list); - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - - pgm_string_t* response = http_create_response ("OpenPGM", HTTP_TAB_GENERAL_INFORMATION); - pgm_string_append_printf (response, "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "
host name:%s
user name:%s
IP address:%s
transports:%i
process ID:%i
\n", - http_hostname, - http_username, - http_address, - transport_count, - http_pid); - http_finalize_response (connection, response); -} - -static -void -interfaces_callback ( - struct http_connection_t* connection, - PGM_GNUC_UNUSED const char* path - ) -{ - pgm_string_t* response = http_create_response ("Interfaces", HTTP_TAB_INTERFACES); - pgm_string_append (response, "
");
-	struct pgm_ifaddrs_t *ifap, *ifa;
-	pgm_error_t* err = NULL;
-	if (!pgm_getifaddrs (&ifap, &err)) {
-		pgm_string_append_printf (response, "pgm_getifaddrs(): %s", (err && err->message) ? err->message : "(null)");
-		http_finalize_response (connection, response);
-		return;
-	}
-	for (ifa = ifap; ifa; ifa = ifa->ifa_next)
-	{
-		int i = NULL == ifa->ifa_addr ? 0 : pgm_if_nametoindex (ifa->ifa_addr->sa_family, ifa->ifa_name);
-		char rname[IF_NAMESIZE * 2 + 3];
-		char b[IF_NAMESIZE * 2 + 3];
-
-		pgm_if_indextoname (i, rname);
-		sprintf (b, "%s (%s)", ifa->ifa_name, rname);
-
-		 if (NULL == ifa->ifa_addr ||
-		      (ifa->ifa_addr->sa_family != AF_INET &&
-		       ifa->ifa_addr->sa_family != AF_INET6) )
-		{
-			pgm_string_append_printf (response,
-				"#%d name %-15.15s ---- %-46.46s scope 0 status %s loop %s b/c %s m/c %s
\n", - i, - b, - "", - ifa->ifa_flags & IFF_UP ? "UP " : "DOWN", - ifa->ifa_flags & IFF_LOOPBACK ? "YES" : "NO ", - ifa->ifa_flags & IFF_BROADCAST ? "YES" : "NO ", - ifa->ifa_flags & IFF_MULTICAST ? "YES" : "NO " - ); - continue; - } - - char s[INET6_ADDRSTRLEN]; - getnameinfo (ifa->ifa_addr, pgm_sockaddr_len(ifa->ifa_addr), - s, sizeof(s), - NULL, 0, - NI_NUMERICHOST); - pgm_string_append_printf (response, - "#%d name %-15.15s IPv%i %-46.46s scope %u status %s loop %s b/c %s m/c %s
\n", - i, - b, - ifa->ifa_addr->sa_family == AF_INET ? 4 : 6, - s, - (unsigned)pgm_sockaddr_scope_id(ifa->ifa_addr), - ifa->ifa_flags & IFF_UP ? "UP " : "DOWN", - ifa->ifa_flags & IFF_LOOPBACK ? "YES" : "NO ", - ifa->ifa_flags & IFF_BROADCAST ? "YES" : "NO ", - ifa->ifa_flags & IFF_MULTICAST ? "YES" : "NO " - ); - } - pgm_freeifaddrs (ifap); - pgm_string_append (response, "
\n"); - http_finalize_response (connection, response); -} - -static -void -transports_callback ( - struct http_connection_t* connection, - PGM_GNUC_UNUSED const char* path - ) -{ - pgm_string_t* response = http_create_response ("Transports", HTTP_TAB_TRANSPORTS); - pgm_string_append (response, "
" - "\n" - "" - "" - "" - "" - "" - "" - ); - - if (pgm_sock_list) - { - pgm_rwlock_reader_lock (&pgm_sock_list_lock); - - pgm_slist_t* list = pgm_sock_list; - while (list) - { - pgm_slist_t* next = list->next; - pgm_sock_t* sock = list->data; - - char group_address[INET6_ADDRSTRLEN]; - getnameinfo ((struct sockaddr*)&sock->send_gsr.gsr_group, pgm_sockaddr_len ((struct sockaddr*)&sock->send_gsr.gsr_group), - group_address, sizeof(group_address), - NULL, 0, - NI_NUMERICHOST); - char gsi[ PGM_GSISTRLEN ]; - pgm_gsi_print_r (&sock->tsi.gsi, gsi, sizeof(gsi)); - const uint16_t sport = ntohs (sock->tsi.sport); - const uint16_t dport = ntohs (sock->dport); - pgm_string_append_printf (response, "" - "" - "" - "" - "" - "", - group_address, - dport, - gsi, sport, - gsi, - gsi, sport, - sport); - list = next; - } - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - } - else - { -/* no transports */ - pgm_string_append (response, "" - "" - "" - ); - } - - pgm_string_append (response, "
Group addressDest portSource GSISource port
%s%i%s%u
This transport has no peers.
\n" - "
"); - http_finalize_response (connection, response); -} - -static -void -histograms_callback ( - struct http_connection_t* connection, - PGM_GNUC_UNUSED const char* path - ) -{ - pgm_string_t* response = http_create_response ("Histograms", HTTP_TAB_HISTOGRAMS); - pgm_histogram_write_html_graph_all (response); - http_finalize_response (connection, response); -} - -static -void -default_callback ( - struct http_connection_t* connection, - const char* path - ) -{ - pgm_tsi_t tsi; - const int count = sscanf (path, "/%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hu", - (unsigned char*)&tsi.gsi.identifier[0], - (unsigned char*)&tsi.gsi.identifier[1], - (unsigned char*)&tsi.gsi.identifier[2], - (unsigned char*)&tsi.gsi.identifier[3], - (unsigned char*)&tsi.gsi.identifier[4], - (unsigned char*)&tsi.gsi.identifier[5], - &tsi.sport); - tsi.sport = htons (tsi.sport); - if (count == 7) - { - int retval = http_tsi_response (connection, &tsi); - if (!retval) return; - } - - http_set_status (connection, 404, "Not Found"); - http_set_static_response (connection, WWW_404_HTML, strlen(WWW_404_HTML)); -} - -static -int -http_tsi_response ( - struct http_connection_t* connection, - pgm_tsi_t* tsi - ) -{ -/* first verify this is a valid TSI */ - pgm_rwlock_reader_lock (&pgm_sock_list_lock); - - pgm_sock_t* sock = NULL; - pgm_slist_t* list = pgm_sock_list; - while (list) - { - pgm_sock_t* list_sock = (pgm_sock_t*)list->data; - pgm_slist_t* next = list->next; - -/* check source */ - if (pgm_tsi_equal (tsi, &list_sock->tsi)) - { - sock = list_sock; - break; - } - -/* check receivers */ - pgm_rwlock_reader_lock (&list_sock->peers_lock); - pgm_peer_t* receiver = pgm_hashtable_lookup (list_sock->peers_hashtable, tsi); - if (receiver) { - int retval = http_receiver_response (connection, receiver); - pgm_rwlock_reader_unlock (&list_sock->peers_lock); - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - return retval; - } - pgm_rwlock_reader_unlock (&list_sock->peers_lock); - - list = next; - } - - if (!sock) { - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - return -1; - } - -/* transport now contains valid matching TSI */ - char gsi[ PGM_GSISTRLEN ]; - pgm_gsi_print_r (&sock->tsi.gsi, gsi, sizeof(gsi)); - - char title[ sizeof("Transport .00000") + PGM_GSISTRLEN ]; - sprintf (title, "Transport %s.%hu", - gsi, - ntohs (sock->tsi.sport)); - - char source_address[INET6_ADDRSTRLEN]; - getnameinfo ((struct sockaddr*)&sock->send_gsr.gsr_source, pgm_sockaddr_len ((struct sockaddr*)&sock->send_gsr.gsr_source), - source_address, sizeof(source_address), - NULL, 0, - NI_NUMERICHOST); - - char group_address[INET6_ADDRSTRLEN]; - getnameinfo ((struct sockaddr*)&sock->send_gsr.gsr_group, pgm_sockaddr_len ((struct sockaddr*)&sock->send_gsr.gsr_group), - group_address, sizeof(group_address), - NULL, 0, - NI_NUMERICHOST); - - const uint16_t dport = ntohs (sock->dport); - const uint16_t sport = ntohs (sock->tsi.sport); - - const pgm_time_t ihb_min = sock->spm_heartbeat_len ? sock->spm_heartbeat_interval[ 1 ] : 0; - const pgm_time_t ihb_max = sock->spm_heartbeat_len ? sock->spm_heartbeat_interval[ sock->spm_heartbeat_len - 1 ] : 0; - - char spm_path[INET6_ADDRSTRLEN]; - getnameinfo ((struct sockaddr*)&sock->recv_gsr[0].gsr_source, pgm_sockaddr_len ((struct sockaddr*)&sock->recv_gsr[0].gsr_source), - spm_path, sizeof(spm_path), - NULL, 0, - NI_NUMERICHOST); - - pgm_string_t* response = http_create_response (title, HTTP_TAB_TRANSPORTS); - pgm_string_append_printf (response, "
" - "Transport: " - "%s.%hu" - "
", - gsi, sport); - -/* peers */ - - pgm_string_append (response, "
" - "\n" - "" - "" - "" - "" - "" - "" - "" - "" - ); - - if (sock->peers_list) - { - pgm_rwlock_reader_lock (&sock->peers_lock); - pgm_list_t* peers_list = sock->peers_list; - while (peers_list) { - pgm_list_t* next = peers_list->next; - http_each_receiver (peers_list->data, response); - peers_list = next; - } - pgm_rwlock_reader_unlock (&sock->peers_lock); - } - else - { -/* no peers */ - - pgm_string_append (response, "" - "" - "" - ); - - } - - pgm_string_append (response, "
Group addressDest portSource addressLast hopSource GSISource port
This transport has no peers.
\n" - "
"); - -/* source and configuration information */ - - pgm_string_append_printf (response, "
" - "\n" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "", - source_address, - group_address, - dport, - gsi, - sport); - -/* continue with source information */ - - pgm_string_append_printf (response, "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "
Source address%s
Group address%s
Dest port%u
Source GSI%s
Source port%u
Ttl%u
Adv Mode%s
Late joindisable(2)
TXW_MAX_RTE%" GROUP_FORMAT "zd
TXW_SECS%" GROUP_FORMAT "u
TXW_ADV_SECS0
Ambient SPM interval%" GROUP_FORMAT PGM_TIME_FORMAT " ms
IHB_MIN%" GROUP_FORMAT PGM_TIME_FORMAT " ms
IHB_MAX%" GROUP_FORMAT PGM_TIME_FORMAT " ms
NAK_BO_IVL%" GROUP_FORMAT PGM_TIME_FORMAT " ms
FECdisabled(1)
Source Path Address%s
\n" - "
", - sock->hops, - 0 == sock->adv_mode ? "time(0)" : "data(1)", - sock->txw_max_rte, - sock->txw_secs, - pgm_to_msecs(sock->spm_ambient_interval), - ihb_min, - ihb_max, - pgm_to_msecs(sock->nak_bo_ivl), - spm_path); - -/* performance information */ - - const pgm_txw_t* window = sock->window; - pgm_string_append_printf (response, "\n

Performance information

" - "\n" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "
Data bytes sent%" GROUP_FORMAT PRIu32 "
Data packets sent%" GROUP_FORMAT PRIu32 "
Bytes buffered%" GROUP_FORMAT PRIu32 "
Packets buffered%" GROUP_FORMAT PRIu32 "
Bytes sent%" GROUP_FORMAT PRIu32 "
Raw NAKs received%" GROUP_FORMAT PRIu32 "
Checksum errors%" GROUP_FORMAT PRIu32 "
Malformed NAKs%" GROUP_FORMAT PRIu32 "
Packets discarded%" GROUP_FORMAT PRIu32 "
Bytes retransmitted%" GROUP_FORMAT PRIu32 "
Packets retransmitted%" GROUP_FORMAT PRIu32 "
NAKs received%" GROUP_FORMAT PRIu32 "
NAKs ignored%" GROUP_FORMAT PRIu32 "
Transmission rate%" GROUP_FORMAT PRIu32 " bps
NNAK packets received%" GROUP_FORMAT PRIu32 "
NNAKs received%" GROUP_FORMAT PRIu32 "
Malformed NNAKs%" GROUP_FORMAT PRIu32 "
\n", - sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT], - sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT], - window ? pgm_txw_size (window) : 0, /* minus IP & any UDP header */ - window ? pgm_txw_length (window) : 0, - sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED], - sock->cumulative_stats[PGM_PC_SOURCE_CKSUM_ERRORS], - sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS], - sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED], - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED], - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED], - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED], - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_IGNORED], - sock->cumulative_stats[PGM_PC_SOURCE_TRANSMISSION_CURRENT_RATE], - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED], - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED], - sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]); - - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - http_finalize_response (connection, response); - return 0; -} - -static -void -http_each_receiver ( - pgm_peer_t* peer, - pgm_string_t* response - ) -{ - char group_address[INET6_ADDRSTRLEN]; - getnameinfo ((struct sockaddr*)&peer->group_nla, pgm_sockaddr_len ((struct sockaddr*)&peer->group_nla), - group_address, sizeof(group_address), - NULL, 0, - NI_NUMERICHOST); - - char source_address[INET6_ADDRSTRLEN]; - getnameinfo ((struct sockaddr*)&peer->nla, pgm_sockaddr_len ((struct sockaddr*)&peer->nla), - source_address, sizeof(source_address), - NULL, 0, - NI_NUMERICHOST); - - char last_hop[INET6_ADDRSTRLEN]; - getnameinfo ((struct sockaddr*)&peer->local_nla, pgm_sockaddr_len ((struct sockaddr*)&peer->local_nla), - last_hop, sizeof(last_hop), - NULL, 0, - NI_NUMERICHOST); - - char gsi[ PGM_GSISTRLEN + sizeof(".00000") ]; - pgm_gsi_print_r (&peer->tsi.gsi, gsi, sizeof(gsi)); - - const int sport = ntohs (peer->tsi.sport); - const int dport = ntohs (peer->sock->dport); /* by definition must be the same */ - pgm_string_append_printf (response, "" - "%s" - "%u" - "%s" - "%s" - "%s" - "%u" - "", - group_address, - dport, - source_address, - last_hop, - gsi, sport, gsi, - gsi, sport, sport - ); -} - -static -int -http_time_summary ( - const time_t* activity_time, - char* sz - ) -{ - time_t now_time = time (NULL); - - if (*activity_time > now_time) { - return sprintf (sz, "clock skew"); - } - - struct tm* activity_tm = localtime (activity_time); - - now_time -= *activity_time; - - if (now_time < (24 * 60 * 60)) - { - char hourmin[6]; - strftime (hourmin, sizeof(hourmin), "%H:%M", activity_tm); - - if (now_time < 60) { - return sprintf (sz, "%s (%li second%s ago)", - hourmin, now_time, now_time > 1 ? "s" : ""); - } - now_time /= 60; - if (now_time < 60) { - return sprintf (sz, "%s (%li minute%s ago)", - hourmin, now_time, now_time > 1 ? "s" : ""); - } - now_time /= 60; - return sprintf (sz, "%s (%li hour%s ago)", - hourmin, now_time, now_time > 1 ? "s" : ""); - } - else - { - char daymonth[32]; -#ifndef _WIN32 - strftime (daymonth, sizeof(daymonth), "%d %b", activity_tm); -#else - wchar_t wdaymonth[32]; - const size_t slen = strftime (daymonth, sizeof(daymonth), "%d %b", &activity_tm); - const size_t wslen = MultiByteToWideChar (CP_ACP, 0, daymonth, slen, wdaymonth, 32); - WideCharToMultiByte (CP_UTF8, 0, wdaymonth, wslen + 1, daymonth, sizeof(daymonth), NULL, NULL); -#endif - now_time /= 24; - if (now_time < 14) { - return sprintf (sz, "%s (%li day%s ago)", - daymonth, now_time, now_time > 1 ? "s" : ""); - } else { - return sprintf (sz, "%s", daymonth); - } - } -} - -static -int -http_receiver_response ( - struct http_connection_t* connection, - pgm_peer_t* peer - ) -{ - char gsi[ PGM_GSISTRLEN ]; - pgm_gsi_print_r (&peer->tsi.gsi, gsi, sizeof(gsi)); - char title[ sizeof("Peer .00000") + PGM_GSISTRLEN ]; - sprintf (title, "Peer %s.%u", - gsi, - ntohs (peer->tsi.sport)); - - char group_address[INET6_ADDRSTRLEN]; - getnameinfo ((struct sockaddr*)&peer->group_nla, pgm_sockaddr_len ((struct sockaddr*)&peer->group_nla), - group_address, sizeof(group_address), - NULL, 0, - NI_NUMERICHOST); - - char source_address[INET6_ADDRSTRLEN]; - getnameinfo ((struct sockaddr*)&peer->nla, pgm_sockaddr_len ((struct sockaddr*)&peer->nla), - source_address, sizeof(source_address), - NULL, 0, - NI_NUMERICHOST); - - char last_hop[INET6_ADDRSTRLEN]; - getnameinfo ((struct sockaddr*)&peer->local_nla, pgm_sockaddr_len ((struct sockaddr*)&peer->local_nla), - last_hop, sizeof(last_hop), - NULL, 0, - NI_NUMERICHOST); - - const uint16_t sport = ntohs (peer->tsi.sport); - const uint16_t dport = ntohs (peer->sock->dport); /* by definition must be the same */ - const pgm_rxw_t* window = peer->window; - const uint32_t outstanding_naks = window->nak_backoff_queue.length + - window->wait_ncf_queue.length + - window->wait_data_queue.length; - - time_t last_activity_time; - pgm_time_since_epoch (&peer->last_packet, &last_activity_time); - - char last_activity[100]; - http_time_summary (&last_activity_time, last_activity); - - pgm_string_t* response = http_create_response (title, HTTP_TAB_TRANSPORTS); - pgm_string_append_printf (response, "
" - "Peer: " - "%s.%u" - "
", - gsi, sport); - - -/* peer information */ - pgm_string_append_printf (response, "
" - "\n" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "", - group_address, - dport, - source_address, - last_hop, - gsi, - sport); - - pgm_string_append_printf (response, "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "
Group address%s
Dest port%u
Source address%s
Last hop%s
Source GSI%s
Source port%u
NAK_BO_IVL%" GROUP_FORMAT PGM_TIME_FORMAT " ms
NAK_RPT_IVL%" GROUP_FORMAT PGM_TIME_FORMAT " ms
NAK_NCF_RETRIES%" GROUP_FORMAT "u
NAK_RDATA_IVL%" GROUP_FORMAT PGM_TIME_FORMAT " ms
NAK_DATA_RETRIES%" GROUP_FORMAT "u
Send NAKsenabled(1)
Late joindisabled(2)
NAK TTL%u
Delivery orderordered(2)
Multicast NAKsdisabled(2)
\n" - "
", - pgm_to_msecs(peer->sock->nak_bo_ivl), - pgm_to_msecs(peer->sock->nak_rpt_ivl), - peer->sock->nak_ncf_retries, - pgm_to_msecs(peer->sock->nak_rdata_ivl), - peer->sock->nak_data_retries, - peer->sock->hops); - - pgm_string_append_printf (response, "\n

Performance information

" - "\n" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" /* detected missed packets */ - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "
Data bytes received%" GROUP_FORMAT PRIu32 "
Data packets received%" GROUP_FORMAT PRIu32 "
NAK failures%" GROUP_FORMAT PRIu32 "
Bytes received%" GROUP_FORMAT PRIu32 "
Checksum errors%" GROUP_FORMAT PRIu32 "
Malformed SPMs%" GROUP_FORMAT PRIu32 "
Malformed ODATA%" GROUP_FORMAT PRIu32 "
Malformed RDATA%" GROUP_FORMAT PRIu32 "
Malformed NCFs%" GROUP_FORMAT PRIu32 "
Packets discarded%" GROUP_FORMAT PRIu32 "
Losses%" GROUP_FORMAT PRIu32 "
Bytes delivered to app%" GROUP_FORMAT PRIu32 "
Packets delivered to app%" GROUP_FORMAT PRIu32 "
Duplicate SPMs%" GROUP_FORMAT PRIu32 "
Duplicate ODATA/RDATA%" GROUP_FORMAT PRIu32 "
NAK packets sent%" GROUP_FORMAT PRIu32 "
NAKs sent%" GROUP_FORMAT PRIu32 "
NAKs retransmitted%" GROUP_FORMAT PRIu32 "
NAKs failed%" GROUP_FORMAT PRIu32 "
NAKs failed due to RXW advance%" GROUP_FORMAT PRIu32 "
NAKs failed due to NCF retries%" GROUP_FORMAT PRIu32 "
NAKs failed due to DATA retries%" GROUP_FORMAT PRIu32 "
NAK failures delivered to app%" GROUP_FORMAT PRIu32 "
NAKs suppressed%" GROUP_FORMAT PRIu32 "
Malformed NAKs%" GROUP_FORMAT PRIu32 "
Outstanding NAKs%" GROUP_FORMAT PRIu32 "
Last activity%s
NAK repair min time%" GROUP_FORMAT PRIu32 " μs
NAK repair mean time%" GROUP_FORMAT PRIu32 " μs
NAK repair max time%" GROUP_FORMAT PRIu32 " μs
NAK fail min time%" GROUP_FORMAT PRIu32 " μs
NAK fail mean time%" GROUP_FORMAT PRIu32 " μs
NAK fail max time%" GROUP_FORMAT PRIu32 " μs
NAK min retransmit count%" GROUP_FORMAT PRIu32 "
NAK mean retransmit count%" GROUP_FORMAT PRIu32 "
NAK max retransmit count%" GROUP_FORMAT PRIu32 "
\n", - peer->cumulative_stats[PGM_PC_RECEIVER_DATA_BYTES_RECEIVED], - peer->cumulative_stats[PGM_PC_RECEIVER_DATA_MSGS_RECEIVED], - peer->cumulative_stats[PGM_PC_RECEIVER_NAK_FAILURES], - peer->cumulative_stats[PGM_PC_RECEIVER_BYTES_RECEIVED], - peer->sock->cumulative_stats[PGM_PC_SOURCE_CKSUM_ERRORS], - peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS], - peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_ODATA], - peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_RDATA], - peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS], - peer->cumulative_stats[PGM_PC_RECEIVER_PACKETS_DISCARDED], - window->cumulative_losses, - window->bytes_delivered, - window->msgs_delivered, - peer->cumulative_stats[PGM_PC_RECEIVER_DUP_SPMS], - peer->cumulative_stats[PGM_PC_RECEIVER_DUP_DATAS], - peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT], - peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT], - peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_RETRANSMITTED], - peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_FAILED], - peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_RXW_ADVANCED], - peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_NCF_RETRIES_EXCEEDED], - peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_DATA_RETRIES_EXCEEDED], - peer->cumulative_stats[PGM_PC_RECEIVER_NAK_FAILURES_DELIVERED], - peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED], - peer->cumulative_stats[PGM_PC_RECEIVER_NAK_ERRORS], - outstanding_naks, - last_activity, - window->min_fill_time, - peer->cumulative_stats[PGM_PC_RECEIVER_NAK_SVC_TIME_MEAN], - window->max_fill_time, - peer->min_fail_time, - peer->cumulative_stats[PGM_PC_RECEIVER_NAK_FAIL_TIME_MEAN], - peer->max_fail_time, - window->min_nak_transmit_count, - peer->cumulative_stats[PGM_PC_RECEIVER_TRANSMIT_MEAN], - window->max_nak_transmit_count); - http_finalize_response (connection, response); - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/http_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/http_unittest.c deleted file mode 100644 index 32ba11b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/http_unittest.c +++ /dev/null @@ -1,186 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for the HTTP administration interface. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include - -#include "pgm/transport.h" - - -/* mock state */ -static const guint mock_pgm_major_version = 0; -static const guint mock_pgm_minor_version = 0; -static const guint mock_pgm_micro_version = 0; -static GStaticRWLock mock_pgm_transport_list_lock = G_STATIC_RW_LOCK_INIT; -static GSList* mock_pgm_transport_list = NULL; - -static -gboolean -mock_pgm_tsi_equal ( - gconstpointer v1, - gconstpointer v2 - ) -{ - return memcmp (v1, v2, sizeof(struct pgm_tsi_t)) == 0; -} - -static -void -mock_pgm_time_since_epoch ( - pgm_time_t* pgm_time_t_time, - time_t* time_t_time - ) -{ - *time_t_time = pgm_to_secs (*pgm_time_t_time + 0); -} - -static -void -mock_pgm_histogram_write_html_graph_all - ( - GString* string - ) -{ -} - - -/* mock functions for external references */ - -#define pgm_major_version mock_pgm_major_version -#define pgm_minor_version mock_pgm_minor_version -#define pgm_micro_version mock_pgm_micro_version -#define pgm_transport_list_lock mock_pgm_transport_list_lock -#define pgm_transport_list mock_pgm_transport_list -#define pgm_tsi_equal mock_pgm_tsi_equal -#define pgm_time_since_epoch mock_pgm_time_since_epoch -#define pgm_histogram_write_html_graph_all mock_pgm_histogram_write_html_graph_all - -#define HTTP_DEBUG -#include "http.c" - - -/* target: - * gboolean - * pgm_http_init ( - * guint16* http_port, - * GError** error - * ) - */ - -START_TEST (test_init_pass_001) -{ - GError* err = NULL; - fail_unless (TRUE == pgm_http_init (8080, &err)); - fail_unless (NULL == err); -} -END_TEST - -/* duplicate servers */ -START_TEST (test_init_fail_001) -{ - GError* err = NULL; - fail_unless (TRUE == pgm_http_init (8080, &err)); - fail_unless (FALSE == pgm_http_init (8080, &err)); -} -END_TEST - -/* target: - * gboolean - * pgm_http_shutdown (void) - */ - -START_TEST (test_shutdown_pass_001) -{ - GError* err = NULL; - fail_unless (TRUE == pgm_http_init (8080, &err)); - fail_unless (NULL == err); - fail_unless (TRUE == pgm_http_shutdown ()); -} -END_TEST - -/* repeatability - */ -START_TEST (test_shutdown_pass_002) -{ - GError* err = NULL; - fail_unless (TRUE == pgm_http_init (8080, &err)); - fail_unless (NULL == err); - fail_unless (TRUE == pgm_http_shutdown ()); - fail_unless (TRUE == pgm_http_init (8080, &err)); - fail_unless (NULL == err); - fail_unless (TRUE == pgm_http_shutdown ()); -} -END_TEST - -/* no running server */ -START_TEST (test_shutdown_fail_001) -{ - fail_unless (FALSE == pgm_http_shutdown ()); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_init = tcase_create ("init"); - suite_add_tcase (s, tc_init); - tcase_add_test (tc_init, test_init_pass_001); - tcase_add_test (tc_init, test_init_fail_001); - - TCase* tc_shutdown = tcase_create ("shutdown"); - suite_add_tcase (s, tc_shutdown); - tcase_add_test (tc_shutdown, test_shutdown_pass_001); - tcase_add_test (tc_shutdown, test_shutdown_pass_002); - tcase_add_test (tc_shutdown, test_shutdown_fail_001); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/if.c b/3rdparty/openpgm-svn-r1085/pgm/if.c deleted file mode 100644 index f034758..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/if.c +++ /dev/null @@ -1,1595 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * network interface handling. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define _GNU_SOURCE -#include -#include -#include -#ifndef _WIN32 -# include -# include -# include /* _GNU_SOURCE for EAI_NODATA */ -#endif -#include -#include -#include - - -//#define IF_DEBUG - -/* temporary structure to contain interface name whilst address family - * has not been resolved. - */ -struct interface_req { - char ir_name[IF_NAMESIZE]; - unsigned int ir_flags; /* from SIOCGIFFLAGS */ - unsigned int ir_interface; /* interface index */ - struct sockaddr_storage ir_addr; /* interface address */ -}; - - -/* locals */ - -#ifndef _WIN32 -# define IF_DEFAULT_GROUP ((in_addr_t)0xefc00001) /* 239.192.0.1 */ -#else -# define IF_DEFAULT_GROUP ((u_long)0xefc00001) -#endif - -/* ff08::1 */ -#define IF6_DEFAULT_INIT { { { 0xff,8,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } -const struct in6_addr if6_default_group_addr = IF6_DEFAULT_INIT; - - -static inline bool is_in_net (const struct in_addr*restrict, const struct in_addr*restrict, const struct in_addr*restrict) PGM_GNUC_WARN_UNUSED_RESULT; -static inline bool is_in_net6 (const struct in6_addr*restrict, const struct in6_addr*restrict, const struct in6_addr*restrict) PGM_GNUC_WARN_UNUSED_RESULT; -static inline bool is_network_char (const int, const char) PGM_GNUC_CONST; -static const char* pgm_family_string (const int) PGM_GNUC_CONST; - - -/* recommended address space for multicast: - * rfc4607, rfc3180, rfc2365 - * - * avoid 5 high-order bit overlap. - * - * loopback: ffx1::/16 - * segment: ffx2::/16 - * glop: 238/8 - * mysterious admin: 239/8, ffx6::/16 - * site: 239.252-255/16, ffx5::/16 - * org: 239.192/14, ffx8::/16 - * - * internets: 224.0.1.0-238.255.255.255, ffxe::/16 - */ - - -/* dump all interfaces to console. - * - * note that interface indexes are only in regard to the link layer and hence - * no 1-1 mapping between adapter name to index back to address. - */ - -void -pgm_if_print_all (void) -{ - struct pgm_ifaddrs_t *ifap, *ifa; - - if (!pgm_getifaddrs (&ifap, NULL)) - return; - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) - { - const unsigned int i = NULL == ifa->ifa_addr ? 0 : pgm_if_nametoindex (ifa->ifa_addr->sa_family, ifa->ifa_name); - char rname[IF_NAMESIZE * 2 + 3]; - char b[IF_NAMESIZE * 2 + 3]; - - pgm_if_indextoname (i, rname); - sprintf (b, "%s (%s)", - ifa->ifa_name ? ifa->ifa_name : "(null)", rname); - - if (NULL == ifa->ifa_addr || - (ifa->ifa_addr->sa_family != AF_INET && - ifa->ifa_addr->sa_family != AF_INET6) ) - { - pgm_info (_("#%d name %-15.15s ---- %-46.46s scope 0 status %s loop %s b/c %s m/c %s"), - i, - b, - "", - ifa->ifa_flags & IFF_UP ? "UP " : "DOWN", - ifa->ifa_flags & IFF_LOOPBACK ? "YES" : "NO ", - ifa->ifa_flags & IFF_BROADCAST ? "YES" : "NO ", - ifa->ifa_flags & IFF_MULTICAST ? "YES" : "NO " - ); - continue; - } - - char s[INET6_ADDRSTRLEN]; - getnameinfo (ifa->ifa_addr, pgm_sockaddr_len(ifa->ifa_addr), - s, sizeof(s), - NULL, 0, - NI_NUMERICHOST); - pgm_info (_("#%d name %-15.15s IPv%i %-46.46s scope %u status %s loop %s b/c %s m/c %s"), - i, - b, - ifa->ifa_addr->sa_family == AF_INET ? 4 : 6, - s, - (unsigned)pgm_sockaddr_scope_id(ifa->ifa_addr), - ifa->ifa_flags & IFF_UP ? "UP " : "DOWN", - ifa->ifa_flags & IFF_LOOPBACK ? "YES" : "NO ", - ifa->ifa_flags & IFF_BROADCAST ? "YES" : "NO ", - ifa->ifa_flags & IFF_MULTICAST ? "YES" : "NO " - ); - } - - pgm_freeifaddrs (ifap); -} - -static inline -bool -is_in_net ( - const struct in_addr* restrict addr, /* host byte order */ - const struct in_addr* restrict netaddr, - const struct in_addr* restrict netmask - ) -{ - pgm_assert (NULL != addr); - pgm_assert (NULL != netaddr); - pgm_assert (NULL != netmask); - -#ifdef IF_DEBUG - const struct in_addr taddr = { .s_addr = htonl (addr->s_addr) }; - const struct in_addr tnetaddr = { .s_addr = htonl (netaddr->s_addr) }; - const struct in_addr tnetmask = { .s_addr = htonl (netmask->s_addr) }; - char saddr[INET_ADDRSTRLEN], snetaddr[INET_ADDRSTRLEN], snetmask[INET_ADDRSTRLEN]; - pgm_debug ("is_in_net (addr:%s netaddr:%s netmask:%s)", - pgm_inet_ntop (AF_INET, &taddr, saddr, sizeof(saddr)), - pgm_inet_ntop (AF_INET, &tnetaddr, snetaddr, sizeof(snetaddr)), - pgm_inet_ntop (AF_INET, &tnetmask, snetmask, sizeof(snetmask))); -#endif - - if ((addr->s_addr & netmask->s_addr) == (netaddr->s_addr & netmask->s_addr)) - return TRUE; - return FALSE; -} - -static -bool -is_in_net6 ( - const struct in6_addr* restrict addr, - const struct in6_addr* restrict netaddr, - const struct in6_addr* restrict netmask - ) -{ - pgm_assert (NULL != addr); - pgm_assert (NULL != netaddr); - pgm_assert (NULL != netmask); - -#ifdef IF_DEBUG - char saddr[INET6_ADDRSTRLEN], snetaddr[INET6_ADDRSTRLEN], snetmask[INET6_ADDRSTRLEN]; - pgm_debug ("is_in_net6 (addr:%s netaddr:%s netmask:%s)", - pgm_inet_ntop (AF_INET6, addr, saddr, sizeof(saddr)), - pgm_inet_ntop (AF_INET6, netaddr, snetaddr, sizeof(snetaddr)), - pgm_inet_ntop (AF_INET6, netmask, snetmask, sizeof(snetmask))); -#endif - - for (unsigned i = 0; i < 16; i++) - if ((addr->s6_addr[i] & netmask->s6_addr[i]) != (netaddr->s6_addr[i] & netmask->s6_addr[i])) - return FALSE; - return TRUE; -} - -/* parse interface entity into an interface-request structure. - * - * e.g. eth0 - * 1.2.3.4 - * 1.2 - * abcd:: - * [abcd::] - * - * - * - * special addresses should be ignored: - * - * local physical link: 169.254.0.0/16, fe80::/64 - * broadcast: 255.255.255.255 - * multicast: 224.0.0.0/4 (224.0.0.0 to 239.255.255.255), ff00::/8 - * - * We could use if_nametoindex() but we might as well check that the interface is - * actually UP and capable of multicast traffic. - * - * returns TRUE on success, FALSE on error and sets error appropriately. - */ - -static -bool -parse_interface ( - int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ - const char* restrict ifname, /* NULL terminated */ - struct interface_req* restrict ir, /* location to write interface details to */ - pgm_error_t** restrict error - ) -{ - bool check_inet_network = FALSE, check_inet6_network = FALSE; - bool check_addr = FALSE; - bool check_ifname = FALSE; - char literal[1024]; - struct in_addr in_addr; - struct in6_addr in6_addr; - struct pgm_ifaddrs_t *ifap, *ifa; - struct sockaddr_storage addr; - unsigned interface_matches = 0; - -/* pre-conditions */ - pgm_assert (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family); - pgm_assert (NULL != ifname); - pgm_assert (NULL != ir); - - pgm_debug ("parse_interface (family:%s ifname:%s%s%s ir:%p error:%p)", - pgm_family_string (family), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : "", - (const void*)ir, - (const void*)error); - -/* strip any square brackets for IPv6 early evaluation */ - if (AF_INET != family && - '[' == ifname[0]) - { - const size_t ifnamelen = strlen(ifname); - if (']' == ifname[ ifnamelen - 1 ]) { - strncpy (literal, ifname + 1, ifnamelen - 2); - literal[ ifnamelen - 2 ] = 0; - family = AF_INET6; /* force IPv6 evaluation */ - check_inet6_network = TRUE; /* may be a network IP or CIDR block */ - check_addr = TRUE; /* cannot be not a name */ - ifname = literal; - } - } - -/* network address: in_addr in host byte order */ - if (AF_INET6 != family && 0 == pgm_inet_network (ifname, &in_addr)) - { -#ifdef IF_DEBUG - struct in_addr t = { .s_addr = htonl (in_addr.s_addr) }; - pgm_debug ("IPv4 network address: %s", inet_ntoa (t)); -#endif - if (IN_MULTICAST(in_addr.s_addr)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_XDEV, - _("Expecting network interface address, found IPv4 multicast network %s%s%s"), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - return FALSE; - } - struct sockaddr_in s4; - memset (&s4, 0, sizeof(s4)); - s4.sin_family = AF_INET; - s4.sin_addr.s_addr = htonl (in_addr.s_addr); - memcpy (&addr, &s4, sizeof(s4)); - - check_inet_network = TRUE; - check_addr = TRUE; - } - if (AF_INET != family && 0 == pgm_inet6_network (ifname, &in6_addr)) - { - if (IN6_IS_ADDR_MULTICAST(&in6_addr)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_XDEV, - _("Expecting network interface address, found IPv6 multicast network %s%s%s"), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - return FALSE; - } - struct sockaddr_in6 s6; - memset (&s6, 0, sizeof(s6)); - s6.sin6_family = AF_INET6; - s6.sin6_addr = in6_addr; - memcpy (&addr, &s6, sizeof(s6)); - - check_inet6_network = TRUE; - check_addr = TRUE; - } - -/* numeric host with scope id */ - if (!check_addr) - { - struct addrinfo hints = { - .ai_family = family, - .ai_socktype = SOCK_STREAM, /* not really, SOCK_RAW */ - .ai_protocol = IPPROTO_TCP, /* not really, IPPROTO_PGM */ - .ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST /* AI_V4MAPPED is unhelpful */ - }, *res; - const int eai = getaddrinfo (ifname, NULL, &hints, &res); - switch (eai) { - case 0: - if (AF_INET == res->ai_family && - IN_MULTICAST(ntohl (((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr))) - { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_XDEV, - _("Expecting interface address, found IPv4 multicast address %s%s%s"), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - freeaddrinfo (res); - return FALSE; - } - else if (AF_INET6 == res->ai_family && - IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)res->ai_addr)->sin6_addr)) - { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_XDEV, - _("Expecting interface address, found IPv6 multicast address %s%s%s"), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - freeaddrinfo (res); - return FALSE; - } - - memcpy (&addr, res->ai_addr, pgm_sockaddr_len (res->ai_addr)); - freeaddrinfo (res); - check_addr = TRUE; - break; - -#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME - case EAI_NODATA: -#endif - case EAI_NONAME: - break; - - default: - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_eai_errno (eai, errno), - _("Numeric host resolution: %s"), - gai_strerror (eai)); - return FALSE; - } - } - -#ifndef _WIN32 -/* network name into network address, can be expensive with NSS network lookup - * - * Only Class A, B or C networks are supported, partitioned networks - * (i.e. network/26 or network/28) are not supported by this facility. - */ - if (!(check_inet_network || check_inet6_network)) - { - const struct netent* ne = getnetbyname (ifname); -/* ne::n_net in host byte order */ - - if (ne) { - switch (ne->n_addrtype) { - case AF_INET: - if (AF_INET6 == family) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("IP address family conflict when resolving network name %s%s%s, found AF_INET when AF_INET6 expected."), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - return FALSE; - } -/* ne->n_net in network order */ - in_addr.s_addr = ne->n_net; - if (IN_MULTICAST(in_addr.s_addr)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_XDEV, - _("Network name %s%s%s resolves to IPv4 mulicast address."), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - return FALSE; - } - check_inet_network = TRUE; - break; - case AF_INET6: -#ifndef CONFIG_HAVE_IP6_NETWORKS - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("Not configured for IPv6 network name support, %s%s%s is an IPv6 network name."), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - return FALSE; -#else - if (AF_INET == family) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("IP address family conflict when resolving network name %s%s%s, found AF_INET6 when AF_INET expected."), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - return FALSE; - } - if (IN6_IS_ADDR_MULTICAST(&ne->n_net)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_XDEV, - _("Network name resolves to IPv6 mulicast address %s%s%s"), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - return FALSE; - } - in6_addr = *(const struct in6_addr*)&ne->n_net; - check_inet6_network = TRUE; - break; -#endif - default: - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("Network name resolves to non-internet protocol address family %s%s%s"), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - return FALSE; - } - } - } -#endif /* _WIN32 */ - -/* hostname lookup with potential DNS delay or error */ - if (!check_addr) - { - struct addrinfo hints = { - .ai_family = family, - .ai_socktype = SOCK_STREAM, /* not really, SOCK_RAW */ - .ai_protocol = IPPROTO_TCP, /* not really, IPPROTO_PGM */ - .ai_flags = AI_ADDRCONFIG, /* AI_V4MAPPED is unhelpful */ - }, *res; - - const int eai = getaddrinfo (ifname, NULL, &hints, &res); - switch (eai) { - case 0: - if (AF_INET == res->ai_family && - IN_MULTICAST(ntohl (((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr))) - { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_XDEV, - _("Expecting interface address, found IPv4 multicast name %s%s%s"), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - freeaddrinfo (res); - return FALSE; - } - else if (AF_INET6 == res->ai_family && - IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)res->ai_addr)->sin6_addr)) - { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_XDEV, - _("Expecting interface address, found IPv6 multicast name %s%s%s"), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - freeaddrinfo (res); - return FALSE; - } - memcpy (&addr, res->ai_addr, pgm_sockaddr_len (res->ai_addr)); - freeaddrinfo (res); - check_addr = TRUE; - break; - -#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME - case EAI_NODATA: -#endif - case EAI_NONAME: - check_ifname = TRUE; - break; - - default: - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_eai_errno (eai, errno), - _("Internet host resolution: %s(%d)"), - gai_strerror (eai), eai); - return FALSE; - } - } - -/* iterate through interface list and match device name, ip or net address */ - if (!pgm_getifaddrs (&ifap, error)) { - pgm_prefix_error (error, - _("Enumerating network interfaces: ")); - return FALSE; - } - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) - { - if (NULL == ifa->ifa_addr) - continue; - - switch (ifa->ifa_addr->sa_family) { -/* ignore raw entries on Linux */ -#ifdef AF_PACKET - case AF_PACKET: - continue; -#endif - case AF_INET: - if (AF_INET6 == family) - continue; - break; - case AF_INET6: - if (AF_INET == family) - continue; - break; - default: - continue; - } - - const unsigned ifindex = pgm_if_nametoindex (ifa->ifa_addr->sa_family, ifa->ifa_name); - pgm_assert (0 != ifindex); - -/* check numeric host */ - if (check_addr && - (0 == pgm_sockaddr_cmp (ifa->ifa_addr, (const struct sockaddr*)&addr))) - { - strcpy (ir->ir_name, ifa->ifa_name); - ir->ir_flags = ifa->ifa_flags; - if (ir->ir_flags & IFF_LOOPBACK) - pgm_warn (_("Interface %s reports as a loopback device."), ir->ir_name); - if (!(ir->ir_flags & IFF_MULTICAST)) - pgm_warn (_("Interface %s reports as a non-multicast capable device."), ir->ir_name); - ir->ir_interface = ifindex; - memcpy (&ir->ir_addr, ifa->ifa_addr, pgm_sockaddr_len (ifa->ifa_addr)); - pgm_freeifaddrs (ifap); - return TRUE; - } - -/* check network address */ - if (check_inet_network && - AF_INET == ifa->ifa_addr->sa_family) - { - const struct in_addr ifaddr = { .s_addr = ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr) }; - const struct in_addr netmask = { .s_addr = ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr) }; - if (is_in_net (&ifaddr, &in_addr, &netmask)) { - strcpy (ir->ir_name, ifa->ifa_name); - ir->ir_flags = ifa->ifa_flags; - if (ir->ir_flags & IFF_LOOPBACK) { - pgm_warn (_("Skipping matching loopback network device %s."), ir->ir_name); - goto skip_inet_network; - } - if (!(ir->ir_flags & IFF_MULTICAST)) { - pgm_warn (_("Skipping matching non-multicast capable network device %s."), ir->ir_name); - goto skip_inet_network; - } - ir->ir_interface = ifindex; - memcpy (&ir->ir_addr, ifa->ifa_addr, pgm_sockaddr_len (ifa->ifa_addr)); - pgm_freeifaddrs (ifap); - return TRUE; - } - } - if (check_inet6_network && - AF_INET6 == ifa->ifa_addr->sa_family) - { - const struct in6_addr ifaddr = ((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr; - const struct in6_addr netmask = ((struct sockaddr_in6*)ifa->ifa_netmask)->sin6_addr; - if (is_in_net6 (&ifaddr, &in6_addr, &netmask)) { - strcpy (ir->ir_name, ifa->ifa_name); - ir->ir_flags = ifa->ifa_flags; - if (ir->ir_flags & IFF_LOOPBACK) { - pgm_warn (_("Skipping matching loopback network device %s."), ir->ir_name); - goto skip_inet_network; - } - if (!(ir->ir_flags & IFF_MULTICAST)) { - pgm_warn (_("Skipping matching non-multicast capable network device %s."), ir->ir_name); - goto skip_inet_network; - } - ir->ir_interface = ifindex; - memcpy (&ir->ir_addr, ifa->ifa_addr, pgm_sockaddr_len (ifa->ifa_addr)); - pgm_freeifaddrs (ifap); - return TRUE; - } - } -skip_inet_network: - -/* check interface name */ - if (check_ifname) - { - if (0 != strcmp (ifname, ifa->ifa_name)) - continue; - - ir->ir_flags = ifa->ifa_flags; -/* skip loopback and non-multicast capable devices */ - if ((ir->ir_flags & IFF_LOOPBACK) || !(ir->ir_flags & IFF_MULTICAST)) - continue; - -/* check for multiple interfaces */ - if (interface_matches++) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NOTUNIQ, - _("Network interface name not unique %s%s%s"), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - pgm_freeifaddrs (ifap); - return FALSE; - } - - ir->ir_interface = ifindex; - strcpy (ir->ir_name, ifa->ifa_name); - memcpy (&ir->ir_addr, ifa->ifa_addr, pgm_sockaddr_len (ifa->ifa_addr)); - continue; - } - - } - - if (0 == interface_matches) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("No matching non-loopback and multicast capable network interface %s%s%s"), - ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); - pgm_freeifaddrs (ifap); - return FALSE; - } - - pgm_freeifaddrs (ifap); - return TRUE; -} - -/* parse one multicast address, conflict resolution of multiple address families of DNS multicast names is - * deferred to libc. - * - * Zone indices are ignored as interface specification is already available. - * - * reserved addresses may flag warnings: - * - * 224.0.0.0/24 for local network control - * 224.0.1/24 for internetwork control - * 169.254.255.255, ff02::1 all local nodes on segment - * ff02::2 all routers - * ff05::1 all nodes - * ff0x::fb multicast DNS - * ff0x::108 NIS - * ff05::1:3 DHCP - * - * returns TRUE on success, FALSE on error and sets error appropriately. - */ - -static -bool -parse_group ( - const int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ - const char* restrict group, /* NULL terminated */ - struct sockaddr* restrict addr, /* pointer to sockaddr_storage for writing */ - pgm_error_t** restrict error - ) -{ -/* pre-conditions */ - pgm_assert (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family); - pgm_assert (NULL != group); - pgm_assert (NULL != addr); - - pgm_debug ("parse_group (family:%s group:%s%s%s addr:%p error:%p)", - pgm_family_string (family), - group ? "\"" : "", group ? group : "(null)", group ? "\"" : "", - (const void*)addr, - (const void*)error); - -/* strip any square brackets for early IPv6 literal evaluation */ - if (AF_INET != family && - '[' == group[0]) - { - const size_t grouplen = strlen(group); - if (']' == group[ grouplen - 1 ]) { - char literal[1024]; - strncpy (literal, group + 1, grouplen - 2); - literal[ grouplen - 2 ] = 0; - if (pgm_inet_pton (AF_INET6, literal, &((struct sockaddr_in6*)addr)->sin6_addr) && - IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr)) - { - addr->sa_family = AF_INET6; - ((struct sockaddr_in6*)addr)->sin6_port = 0; - ((struct sockaddr_in6*)addr)->sin6_flowinfo = 0; - ((struct sockaddr_in6*)addr)->sin6_scope_id = 0; - return TRUE; - } - } - } - -/* IPv4 address */ - if (AF_INET6 != family && - pgm_inet_pton (AF_INET, group, &((struct sockaddr_in*)addr)->sin_addr) && - IN_MULTICAST(ntohl (((struct sockaddr_in*)addr)->sin_addr.s_addr))) - { - addr->sa_family = AF_INET; - return TRUE; - } - if (AF_INET != family && - pgm_inet_pton (AF_INET6, group, &((struct sockaddr_in6*)addr)->sin6_addr) && - IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr)) - { - addr->sa_family = AF_INET6; - ((struct sockaddr_in6*)addr)->sin6_port = 0; - ((struct sockaddr_in6*)addr)->sin6_flowinfo = 0; - ((struct sockaddr_in6*)addr)->sin6_scope_id = 0; - return TRUE; - } - -#ifndef _WIN32 -/* NSS network */ - const struct netent* ne = getnetbyname (group); -/* ne::n_net in host byte order */ - if (ne) { - switch (ne->n_addrtype) { - case AF_INET: - if (AF_INET6 == family) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("IP address family conflict when resolving network name %s%s%s, found IPv4 when IPv6 expected."), - group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); - return FALSE; - } - if (IN_MULTICAST(ne->n_net)) { - addr->sa_family = AF_INET; - ((struct sockaddr_in*)addr)->sin_addr.s_addr = htonl (ne->n_net); - return TRUE; - } - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("IP address class conflict when resolving network name %s%s%s, expected IPv4 multicast."), - group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); - return FALSE; - case AF_INET6: -#ifndef CONFIG_HAVE_IP6_NETWORKS - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("Not configured for IPv6 network name support, %s%s%s is an IPv6 network name."), - group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); - return FALSE; -#else - if (AF_INET == family) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("IP address family conflict when resolving network name %s%s%s, found IPv6 when IPv4 expected."), - group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); - return FALSE; - } - if (IN6_IS_ADDR_MULTICAST(&ne->n_net)) { - addr->sa_family = AF_INET6; - ((struct sockaddr_in6*)addr)->sin6_addr = *(const struct in6_addr*)ne->n_net; - ((struct sockaddr_in6*)&addr)->sin6_port = 0; - ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; - ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; - return TRUE; - } - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("IP address class conflict when resolving network name %s%s%s, expected IPv6 multicast."), - group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); - return FALSE; -#endif /* CONFIG_HAVE_IP6_NETWORKS */ - default: - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("Network name resolves to non-internet protocol address family %s%s%s"), - group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); - return FALSE; - } - } -#endif /* _WIN32 */ - -/* lookup group through name service */ - struct addrinfo hints = { - .ai_family = family, - .ai_socktype = SOCK_STREAM, /* not really, SOCK_RAW */ - .ai_protocol = IPPROTO_TCP, /* not really, IPPROTO_PGM */ - .ai_flags = AI_ADDRCONFIG, /* AI_V4MAPPED is unhelpful */ - }, *res; - - const int eai = getaddrinfo (group, NULL, &hints, &res); - if (0 != eai) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - pgm_error_from_eai_errno (eai, errno), - _("Resolving receive group: %s"), - gai_strerror (eai)); - return FALSE; - } - - if ((AF_INET6 != family && IN_MULTICAST(ntohl (((struct sockaddr_in*)res->ai_addr)->sin_addr.s_addr))) || - (AF_INET != family && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)res->ai_addr)->sin6_addr))) - { - memcpy (addr, res->ai_addr, res->ai_addrlen); - freeaddrinfo (res); - return TRUE; - } - - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_INVAL, - _("Unresolvable receive group %s%s%s"), - group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); - freeaddrinfo (res); - return FALSE; -} - -/* parse an interface entity from a network parameter. - * - * family can be unspecified - AF_UNSPEC, can return interfaces with the unspecified - * address family - * - * examples: "eth0" - * "hme0,hme1" - * "qe0,qe1,qe2" - * "qe0,qe2,qe2" => valid even though duplicate interface name - * - * returns TRUE on success with device_list containing double linked list of devices as - * sockaddr/idx pairs. returns FALSE on error, including multiple matching adapters. - * - * memory ownership of linked list is passed to caller and must be freed with pgm_free - * and the pgm_list_free* api. - */ - -static -bool -parse_interface_entity ( - int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ - const char* restrict entity, /* NULL terminated */ - pgm_list_t** restrict interface_list, /* */ - pgm_error_t** restrict error - ) -{ - struct interface_req* ir; - pgm_list_t* source_list = NULL; - -/* pre-conditions */ - pgm_assert (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family); - pgm_assert (NULL != interface_list); - pgm_assert (NULL == *interface_list); - pgm_assert (NULL != error); - - pgm_debug ("parse_interface_entity (family:%s entity:%s%s%s interface_list:%p error:%p)", - pgm_family_string (family), - entity ? "\"":"", entity ? entity : "(null)", entity ? "\"":"", - (const void*)interface_list, - (const void*)error); - -/* the empty entity, returns in_addr_any for both receive and send interfaces */ - if (NULL == entity) - { - ir = pgm_new0 (struct interface_req, 1); - ir->ir_addr.ss_family = family; - *interface_list = pgm_list_append (*interface_list, ir); - return TRUE; - } - -/* check interface name length limit */ - char** tokens = pgm_strsplit (entity, ",", 10); - int j = 0; - while (tokens && tokens[j]) - { - pgm_error_t* sub_error = NULL; - ir = pgm_new (struct interface_req, 1); - if (!parse_interface (family, tokens[j], ir, &sub_error)) - { -/* mark multiple interfaces for later decision based on group families */ - if (sub_error && PGM_ERROR_NOTUNIQ == sub_error->code) - { - ir->ir_addr.ss_family = AF_UNSPEC; - pgm_error_free (sub_error); - } -/* bail out on first interface with an error */ - else - { - pgm_propagate_error (error, sub_error); - pgm_free (ir); - pgm_strfreev (tokens); - while (source_list) { - pgm_free (source_list->data); - source_list = pgm_list_delete_link (source_list, source_list); - } - return FALSE; - } - } - - source_list = pgm_list_append (source_list, ir); - ++j; - } - - pgm_strfreev (tokens); - *interface_list = source_list; - return TRUE; -} - -/* parse a receive multicast group entity. can contain more than one multicast group to - * support asymmetric fan-out. - * - * if group is ambiguous, i.e. empty or a name mapping then the address family of the matching - * interface is queried. if the interface is also ambiguous, i.e. empty interface and receive group - * then the hostname will be used to determine the default node address family. if the hosts - * node name resolves both IPv4 and IPv6 address families then the first matching value is taken. - * - * e.g. "239.192.0.1" - * "239.192.0.100,239.192.0.101" - * - * unspecified address family interfaces are forced to AF_INET or AF_INET6. - * - * returns TRUE on success, returns FALSE on error and sets error appropriately. - */ - -static -bool -parse_receive_entity ( - int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ - const char* restrict entity, /* NULL terminated */ - pgm_list_t** restrict interface_list, /* */ - pgm_list_t** restrict recv_list, /* */ - pgm_error_t** restrict error - ) -{ -/* pre-conditions */ - pgm_assert (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family); - pgm_assert (NULL != recv_list); - pgm_assert (NULL == *recv_list); - pgm_assert (NULL != error); - - pgm_debug ("parse_receive_entity (family:%s entity:%s%s%s interface_list:%p recv_list:%p error:%p)", - pgm_family_string (family), - entity ? "\"":"", entity ? entity : "(null)", entity ? "\"":"", - (const void*)interface_list, - (const void*)recv_list, - (const void*)error); - - struct group_source_req* recv_gsr; - struct interface_req* primary_interface = (struct interface_req*)pgm_memdup ((*interface_list)->data, sizeof(struct interface_req)); - -/* the empty entity */ - if (NULL == entity) - { -/* default receive object */ - recv_gsr = pgm_new0 (struct group_source_req, 1); - recv_gsr->gsr_interface = primary_interface->ir_interface; - recv_gsr->gsr_group.ss_family = family; - -/* track IPv6 scope from any resolved interface */ - unsigned scope_id = 0; - -/* if using unspec default group check the interface for address family - */ - if (AF_UNSPEC == recv_gsr->gsr_group.ss_family) - { - if (AF_UNSPEC == primary_interface->ir_addr.ss_family) - { - struct sockaddr_storage addr; - if (!pgm_if_getnodeaddr (AF_UNSPEC, (struct sockaddr*)&addr, sizeof(addr), error)) - { - pgm_prefix_error (error, - _("Node primary address family cannot be determined: ")); - pgm_free (recv_gsr); - pgm_free (primary_interface); - return FALSE; - } - recv_gsr->gsr_group.ss_family = addr.ss_family; - scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&addr); - -/* was an interface actually specified */ - if (primary_interface->ir_name[0] != '\0') - { - struct interface_req ir; - if (!parse_interface (recv_gsr->gsr_group.ss_family, primary_interface->ir_name, &ir, error)) - { - pgm_prefix_error (error, - _("Unique address cannot be determined for interface %s%s%s: "), - primary_interface->ir_name ? "\"" : "", primary_interface->ir_name ? primary_interface->ir_name : "(null)", primary_interface->ir_name ? "\"" : ""); - pgm_free (recv_gsr); - pgm_free (primary_interface); - return FALSE; - } - - recv_gsr->gsr_interface = ir.ir_interface; - memcpy (&primary_interface->ir_addr, &ir.ir_addr, pgm_sockaddr_len ((struct sockaddr*)&ir.ir_addr)); - scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&ir.ir_addr); - } - } - else - { -/* use interface address family for multicast group */ - recv_gsr->gsr_group.ss_family = primary_interface->ir_addr.ss_family; - scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&primary_interface->ir_addr); - } - } - - - pgm_assert (AF_UNSPEC != recv_gsr->gsr_group.ss_family); - if (AF_UNSPEC != primary_interface->ir_addr.ss_family) - { - pgm_assert (recv_gsr->gsr_group.ss_family == primary_interface->ir_addr.ss_family); - } - else - { -/* check if we can now resolve the interface by address family of the receive group */ - if (primary_interface->ir_name[0] != '\0') - { - struct interface_req ir; - if (!parse_interface (recv_gsr->gsr_group.ss_family, primary_interface->ir_name, &ir, error)) - { - pgm_prefix_error (error, - _("Unique address cannot be determined for interface %s%s%s: "), - primary_interface->ir_name ? "\"" : "", primary_interface->ir_name ? primary_interface->ir_name : "(null)", primary_interface->ir_name ? "\"" : ""); - pgm_free (recv_gsr); - pgm_free (primary_interface); - return FALSE; - } - - recv_gsr->gsr_interface = ir.ir_interface; - scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&ir.ir_addr); - } - } - -/* copy default PGM multicast group */ - switch (recv_gsr->gsr_group.ss_family) { - case AF_INET6: - memcpy (&((struct sockaddr_in6*)&recv_gsr->gsr_group)->sin6_addr, - &if6_default_group_addr, - sizeof(if6_default_group_addr)); - ((struct sockaddr_in6*)&recv_gsr->gsr_group)->sin6_scope_id = scope_id; - break; - - case AF_INET: - ((struct sockaddr_in*)&recv_gsr->gsr_group)->sin_addr.s_addr = htonl(IF_DEFAULT_GROUP); - break; - - default: - pgm_assert_not_reached(); - } - -/* ASM: source = group */ - memcpy (&recv_gsr->gsr_source, &recv_gsr->gsr_group, pgm_sockaddr_len ((struct sockaddr*)&recv_gsr->gsr_group)); - *recv_list = pgm_list_append (*recv_list, recv_gsr); - pgm_free (primary_interface); - return TRUE; - } - -/* parse one or more multicast receive groups. - */ - - int j = 0; - char** tokens = pgm_strsplit (entity, ",", 10); - while (tokens && tokens[j]) - { -/* default receive object */ - recv_gsr = pgm_new0 (struct group_source_req, 1); - recv_gsr->gsr_interface = primary_interface->ir_interface; - recv_gsr->gsr_group.ss_family = family; - - if (AF_UNSPEC == recv_gsr->gsr_group.ss_family) - { - if (AF_UNSPEC == primary_interface->ir_addr.ss_family) - { - pgm_debug ("Address family of receive group cannot be determined from interface."); - } - else - { - recv_gsr->gsr_group.ss_family = primary_interface->ir_addr.ss_family; - ((struct sockaddr_in6*)&recv_gsr->gsr_group)->sin6_scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&primary_interface->ir_addr); - } - } - - if (!parse_group (recv_gsr->gsr_group.ss_family, tokens[j], (struct sockaddr*)&recv_gsr->gsr_group, error)) - { - pgm_prefix_error (error, - _("Unresolvable receive entity %s%s%s: "), - tokens[j] ? "\"" : "", tokens[j] ? tokens[j] : "(null)", tokens[j] ? "\"" : ""); - pgm_free (recv_gsr); - pgm_strfreev (tokens); - pgm_free (primary_interface); - return FALSE; - } - -/* check if we can now resolve the source interface by address family of the receive group */ - if (AF_UNSPEC == primary_interface->ir_addr.ss_family) - { - if (primary_interface->ir_name[0] != '\0') - { - struct interface_req ir; - if (!parse_interface (recv_gsr->gsr_group.ss_family, primary_interface->ir_name, &ir, error)) - { - pgm_prefix_error (error, - _("Unique address cannot be determined for interface %s%s%s: "), - primary_interface->ir_name ? "\"" : "", primary_interface->ir_name ? primary_interface->ir_name : "(null)", primary_interface->ir_name ? "\"" : ""); - pgm_free (recv_gsr); - pgm_free (primary_interface); - return FALSE; - } - - recv_gsr->gsr_interface = ir.ir_interface; - ((struct sockaddr_in6*)&recv_gsr->gsr_group)->sin6_scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&ir.ir_addr); - } - } - else - { -/* keep interface scope */ - ((struct sockaddr_in6*)&recv_gsr->gsr_group)->sin6_scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&primary_interface->ir_addr); - } - -/* ASM: source = group */ - memcpy (&recv_gsr->gsr_source, &recv_gsr->gsr_group, pgm_sockaddr_len ((struct sockaddr*)&recv_gsr->gsr_group)); - *recv_list = pgm_list_append (*recv_list, recv_gsr); - ++j; - } - - pgm_strfreev (tokens); - pgm_free (primary_interface); - return TRUE; -} - -static -bool -parse_send_entity ( - int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ - const char* restrict entity, /* null = empty entity */ - pgm_list_t** restrict interface_list, /* */ - pgm_list_t** restrict recv_list, /* */ - pgm_list_t** restrict send_list, /* */ - pgm_error_t** restrict error - ) -{ -/* pre-conditions */ - pgm_assert (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family); - pgm_assert (NULL != recv_list); - pgm_assert (NULL != *recv_list); - pgm_assert (NULL != send_list); - pgm_assert (NULL == *send_list); - pgm_assert (NULL != error); - - pgm_debug ("parse_send_entity (family:%s entity:%s%s%s interface_list:%p recv_list:%p send_list:%p error:%p)", - pgm_family_string (family), - entity ? "\"":"", entity ? entity : "(null)", entity ? "\"":"", - (const void*)interface_list, - (const void*)recv_list, - (const void*)send_list, - (const void*)error); - - struct group_source_req* send_gsr; - const struct interface_req* primary_interface = (struct interface_req*)(*interface_list)->data; - - if (entity == NULL) - { - send_gsr = pgm_memdup ((*recv_list)->data, sizeof(struct group_source_req)); - *send_list = pgm_list_append (*send_list, send_gsr); - return TRUE; - } - -/* default send object */ - send_gsr = pgm_new0 (struct group_source_req, 1); - send_gsr->gsr_interface = primary_interface->ir_interface; - if (!parse_group (family, entity, (struct sockaddr*)&send_gsr->gsr_group, error)) - { - pgm_prefix_error (error, - _("Unresolvable send entity %s%s%s: "), - entity ? "\"":"", entity ? entity : "(null)", entity ? "\"":""); - pgm_free (send_gsr); - return FALSE; - } - -/* check if we can now resolve the source interface by address family of the send group */ - if (AF_UNSPEC == primary_interface->ir_addr.ss_family) - { - if (primary_interface->ir_name[0] != '\0') - { - struct interface_req ir; - if (!parse_interface (send_gsr->gsr_group.ss_family, primary_interface->ir_name, &ir, error)) - { - pgm_prefix_error (error, - _("Unique address cannot be determined for interface %s%s%s: "), - primary_interface->ir_name ? "\"":"", primary_interface->ir_name ? primary_interface->ir_name : "(null)", primary_interface->ir_name ? "\"":""); - pgm_free (send_gsr); - return FALSE; - } - - send_gsr->gsr_interface = ir.ir_interface; - ((struct sockaddr_in6*)&send_gsr->gsr_group)->sin6_scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&ir.ir_addr); - } - } - -/* ASM: source = group */ - memcpy (&send_gsr->gsr_source, &send_gsr->gsr_group, pgm_sockaddr_len ((struct sockaddr*)&send_gsr->gsr_group)); - *send_list = pgm_list_append (*send_list, send_gsr); - return TRUE; -} - -/* parse network parameter - * - * interface list; receive multicast group list; send multicast group - */ - -#define IS_HOSTNAME(x) ( /* RFC 952 */ \ - isalnum(x) || \ - ((x) == '-') || \ - ((x) == '.') \ - ) -#define IS_IP(x) ( \ - isdigit(x) || \ - ((x) == '.') || \ - ((x) == '/') \ - ) -#define IS_IP6(x) ( \ - isxdigit(x) || \ - ((x) == ':') || \ - ((x) == '/') || \ - ((x) == '.') || \ - ((x) == '[') || \ - ((x) == ']') \ - ) -/* e.g. fe80::1%eth0.620 vlan tag, - * fe80::1%eth0:0 IP alias - * fe80::1%qe0_0 Solaris link name - * - * The Linux kernel generally doesn't care too much, but everything else falls apart with - * random characters in interface names. Hyphen is a popular problematic character. - */ -#define IS_IP6_WITH_ZONE(x) ( \ - IS_IP6(x) || \ - ((x) == '%') || \ - isalpha(x) || \ - ((x) == '_') \ - ) -#define IS_NETPARAM(x) ( \ - ((x) == ',') || \ - ((x) == ';') \ - ) - -static inline -bool -is_network_char ( - const int family, - const char c - ) -{ - if (IS_HOSTNAME(c) || - (AF_INET == family && IS_IP(c)) || - ((AF_INET6 == family || AF_UNSPEC == family) && IS_IP6_WITH_ZONE(c)) || - IS_NETPARAM(c)) - return TRUE; - else - return FALSE; -} - -static -bool -network_parse ( - const char* restrict network, /* NULL terminated */ - int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ - pgm_list_t** restrict recv_list, /* */ - pgm_list_t** restrict send_list, /* */ - pgm_error_t** restrict error - ) -{ - bool retval = FALSE; - const char *p = network; - const char *e = p + strlen(network); - enum { ENTITY_INTERFACE, ENTITY_RECEIVE, ENTITY_SEND, ENTITY_ERROR } ec = ENTITY_INTERFACE; - const char *b = p; /* begin of entity */ - pgm_list_t* source_list = NULL; - pgm_error_t* sub_error = NULL; - -/* pre-conditions */ - pgm_assert (NULL != network); - pgm_assert (AF_UNSPEC == family || AF_INET == family || AF_INET6 == family); - pgm_assert (NULL != recv_list); - pgm_assert (NULL != send_list); - - pgm_debug ("network_parse (network:%s%s%s family:%s recv_list:%p send_list:%p error:%p)", - network ? "\"" : "", network ? network : "(null)", network ? "\"" : "", - pgm_family_string (family), - (const void*)recv_list, - (const void*)send_list, - (const void*)error); - - while (p < e) - { - if (!is_network_char (family, *p)) - { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_INVAL, - _("'%c' is not a valid character."), - *p); - goto free_lists; - } - - if (*p == ';') /* end of entity */ - { - if (b == p) /* empty entity */ - { - switch (ec++) { - case ENTITY_INTERFACE: - retval = parse_interface_entity (family, NULL, &source_list, error); - break; - - case ENTITY_RECEIVE: - retval = parse_receive_entity (family, NULL, &source_list, recv_list, error); - break; - - case ENTITY_SEND: - retval = parse_send_entity (family, NULL, &source_list, recv_list, send_list, error); - break; - - default: - pgm_assert_not_reached(); - break; - } - - if (!retval) - goto free_lists; - - b = ++p; - continue; - } - -/* entity from b to p-1 */ - char entity[1024]; - strncpy (entity, b, sizeof(entity)); - entity[p - b] = 0; - - switch (ec++) { - case ENTITY_INTERFACE: - if (parse_interface_entity (family, entity, &source_list, &sub_error)) - break; - if (!(sub_error && PGM_ERROR_XDEV == sub_error->code)) - { -/* fall through on multicast */ - if (!(sub_error && PGM_ERROR_NOTUNIQ == sub_error->code)) - { - pgm_propagate_error (error, sub_error); - goto free_lists; - } - pgm_clear_error (&sub_error); -/* FIXME: too many interfaces */ - if (pgm_list_length (source_list) > 1) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_INVAL, - _("Send group list contains more than one entity.")); - goto free_lists; - } - break; - } - pgm_clear_error (&sub_error); - while (source_list) { - pgm_free (source_list->data); - source_list = pgm_list_delete_link (source_list, source_list); - } - if (!parse_interface_entity (family, NULL, &source_list, &sub_error) && - !(sub_error && PGM_ERROR_NOTUNIQ == sub_error->code)) - { - pgm_propagate_error (error, sub_error); - goto free_lists; - } - pgm_clear_error (&sub_error); - ec++; - - case ENTITY_RECEIVE: - if (!parse_receive_entity (family, entity, &source_list, recv_list, error)) - goto free_lists; - break; - - case ENTITY_SEND: - if (!parse_send_entity (family, entity, &source_list, recv_list, send_list, error)) - goto free_lists; - break; - - default: - pgm_assert_not_reached(); - break; - } - - b = ++p; - continue; - } - - p++; - } - - if (b < e) { - switch (ec++) { - case ENTITY_INTERFACE: - if (parse_interface_entity (family, b, &source_list, &sub_error)) - break; - if (!(sub_error && PGM_ERROR_XDEV == sub_error->code)) - { -/* fall through on multicast */ - if (!(sub_error && PGM_ERROR_NOTUNIQ == sub_error->code)) - { - pgm_propagate_error (error, sub_error); - goto free_lists; - } - pgm_clear_error (&sub_error); - -/* FIXME: too many interfaces */ - if (pgm_list_length (source_list) > 1) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_INVAL, - _("Send group list contains more than one entity.")); - goto free_lists; - } - break; - } - pgm_clear_error (&sub_error); - while (source_list) { - pgm_free (source_list->data); - source_list = pgm_list_delete_link (source_list, source_list); - } - if (!parse_interface_entity (family, NULL, &source_list, &sub_error) && - !(sub_error && PGM_ERROR_NOTUNIQ == sub_error->code)) - { - pgm_propagate_error (error, sub_error); - goto free_lists; - } - ec++; - - case ENTITY_RECEIVE: - if (!parse_receive_entity (family, b, &source_list, recv_list, error)) - goto free_lists; - break; - - case ENTITY_SEND: - if (!parse_send_entity (family, b, &source_list, recv_list, send_list, error)) - goto free_lists; - break; - - default: - pgm_assert_not_reached(); - break; - } - } - - while (ec <= ENTITY_SEND) - { - switch (ec++) { - case ENTITY_INTERFACE: - if (!parse_interface_entity (family, NULL, &source_list, error)) - goto free_lists; - break; - - case ENTITY_RECEIVE: - if (!parse_receive_entity (family, NULL, &source_list, recv_list, error)) - goto free_lists; - break; - - case ENTITY_SEND: - if (!parse_send_entity (family, NULL, &source_list, recv_list, send_list, error)) - goto free_lists; - break; - - default: - pgm_assert_not_reached(); - break; - } - } - - if (pgm_list_length (source_list) > 1) - goto free_lists; - -/* cleanup source interface list */ - while (source_list) { - pgm_free (source_list->data); - source_list = pgm_list_delete_link (source_list, source_list); - } - - return TRUE; - -free_lists: - while (source_list) { - pgm_free (source_list->data); - source_list = pgm_list_delete_link (source_list, source_list); - } - while (*recv_list) { - pgm_free ((*recv_list)->data); - *recv_list = pgm_list_delete_link (*recv_list, *recv_list); - } - while (*send_list) { - pgm_free ((*send_list)->data); - *send_list = pgm_list_delete_link (*send_list, *send_list); - } - return FALSE; -} - -/* create group_source_req as used by pgm_transport_create which specify port, address & interface. - * gsr_source is copied from gsr_group for ASM, caller needs to populate gsr_source for SSM. - * - * returns TRUE on success, returns FALSE on error and sets error appropriately. - */ - -bool -pgm_getaddrinfo ( - const char* restrict network, - const struct pgm_addrinfo_t* const restrict hints, - struct pgm_addrinfo_t** restrict res, - pgm_error_t** restrict error - ) -{ - struct pgm_addrinfo_t* ai; - const int family = hints ? hints->ai_family : AF_UNSPEC; - pgm_list_t* recv_list = NULL; /* */ - pgm_list_t* send_list = NULL; /* */ - - pgm_return_val_if_fail (NULL != network, FALSE); - pgm_return_val_if_fail (AF_UNSPEC == family || AF_INET == family || AF_INET6 == family, FALSE); - pgm_return_val_if_fail (NULL != res, FALSE); - - if (hints) { - pgm_debug ("pgm_getaddrinfo (network:%s%s%s hints: {family:%s} res:%p error:%p)", - network ? "\"" : "", network ? network : "(null)", network ? "\"" : "", - pgm_family_string (family), - (const void*)res, - (const void*)error); - } else { - pgm_debug ("pgm_getaddrinfo (network:%s%s%s hints:%p res:%p error:%p)", - network ? "\"" : "", network ? network : "(null)", network ? "\"" : "", - (const void*)hints, - (const void*)res, - (const void*)error); - } - - if (!network_parse (network, family, &recv_list, &send_list, error)) - return FALSE; - const size_t recv_list_len = pgm_list_length (recv_list); - const size_t send_list_len = pgm_list_length (send_list); - ai = pgm_malloc0 (sizeof(struct pgm_addrinfo_t) + - (recv_list_len + send_list_len) * sizeof(struct group_source_req)); - ai->ai_recv_addrs_len = recv_list_len; - ai->ai_recv_addrs = (void*)((char*)ai + sizeof(struct pgm_addrinfo_t)); - ai->ai_send_addrs_len = send_list_len; - ai->ai_send_addrs = (void*)((char*)ai->ai_recv_addrs + recv_list_len * sizeof(struct group_source_req)); - - size_t i = 0; - while (recv_list) { - memcpy (&ai->ai_recv_addrs[i++], recv_list->data, sizeof(struct group_source_req)); - pgm_free (recv_list->data); - recv_list = pgm_list_delete_link (recv_list, recv_list); - } - i = 0; - while (send_list) { - memcpy (&ai->ai_send_addrs[i++], send_list->data, sizeof(struct group_source_req)); - pgm_free (send_list->data); - send_list = pgm_list_delete_link (send_list, send_list); - } - *res = ai; - return TRUE; -} - -void -pgm_freeaddrinfo ( - struct pgm_addrinfo_t* res - ) -{ - pgm_free (res); -} - - -static -const char* -pgm_family_string ( - const int family - ) -{ - const char* c; - - switch (family) { - case AF_UNSPEC: c = "AF_UNSPEC"; break; - case AF_INET: c = "AF_INET"; break; - case AF_INET6: c = "AF_INET6"; break; - default: c = "(unknown)"; break; - } - - return c; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/if_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/if_unittest.c deleted file mode 100644 index dbaa684..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/if_unittest.c +++ /dev/null @@ -1,1495 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for network interface declaration parsing. - * - * CAUTION: Assumes host is IPv4 by default for AF_UNSPEC - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* IFF_UP */ -#define _BSD_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -/* mock state */ - -struct mock_host_t { - struct sockaddr_storage address; - char* canonical_hostname; - char* alias; -}; - -struct mock_network_t { - char* name; - struct sockaddr_storage number; - char** aliases; -}; - -struct mock_interface_t { - unsigned int index; - char* name; - unsigned int flags; - struct sockaddr_storage addr; - struct sockaddr_storage netmask; -}; - -static GList *mock_hosts = NULL, *mock_networks = NULL, *mock_interfaces = NULL; - -#define MOCK_HOSTNAME "kiku" -#define MOCK_HOSTNAME6 "ip6-kiku" /* ping6 doesn't work on fe80:: */ -#define MOCK_NETWORK "private" /* /etc/networks */ -#define MOCK_NETWORK6 "ip6-private" -#define MOCK_PGM_NETWORK "pgm-private" -#define MOCK_PGM_NETWORK6 "pgm-ip6-private" -#define MOCK_INTERFACE "eth0" -#define MOCK_INTERFACE_INDEX 2 -#define MOCK_ADDRESS "10.6.28.33" -#define MOCK_GROUP ((in_addr_t) 0xefc00001) /* 239.192.0.1 */ -#define MOCK_GROUP6_INIT { { { 0xff,8,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } /* ff08::1 */ -static const struct in6_addr mock_group6_addr = MOCK_GROUP6_INIT; -#define MOCK_ADDRESS6 "2002:dce8:d28e::33" -#define MOCK_ADDRESS6_INIT { { { 0x20,2,0xdc,0xe8,0xd2,0x8e,0,0,0,0,0,0,0,0,0,0x33 } } } -static const struct in6_addr mock_address6_addr = MOCK_ADDRESS6_INIT; - -static int mock_family = 0; -static char* mock_kiku = MOCK_HOSTNAME; -static char* mock_localhost = "localhost"; -static char* mock_invalid = "invalid.invalid"; /* RFC 2606 */ -static char* mock_toolong = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij12345"; /* 65 */ -static char* mock_hostname = NULL; - -struct pgm_ifaddrs_t; -struct pgm_error_t; - -bool mock_pgm_getifaddrs (struct pgm_ifaddrs_t**, struct pgm_error_t**); -void mock_pgm_freeifaddrs (struct pgm_ifaddrs_t*); -unsigned mock_pgm_if_nametoindex (const sa_family_t, const char*); -char* mock_if_indextoname (unsigned int, char*); -int mock_getnameinfo (const struct sockaddr*, socklen_t, char*, size_t, char*, size_t, int); -int mock_getaddrinfo (const char*, const char*, const struct addrinfo*, struct addrinfo**); -void mock_freeaddrinfo (struct addrinfo*); -int mock_gethostname (char*, size_t); -struct netent* mock_getnetbyname (const char*); -bool mock_pgm_if_getnodeaddr (const sa_family_t, struct sockaddr*, const socklen_t, struct pgm_error_t**); - -#define pgm_getifaddrs mock_pgm_getifaddrs -#define pgm_freeifaddrs mock_pgm_freeifaddrs -#define pgm_if_nametoindex mock_pgm_if_nametoindex -#define if_indextoname mock_if_indextoname -#define getnameinfo mock_getnameinfo -#define getaddrinfo mock_getaddrinfo -#define freeaddrinfo mock_freeaddrinfo -#define gethostname mock_gethostname -#define getnetbyname mock_getnetbyname -#define pgm_if_getnodeaddr mock_pgm_if_getnodeaddr - - -#define IF_DEBUG -#include "if.c" - - -static -gpointer -create_host ( - const char* address, - const char* canonical_hostname, - const char* alias - ) -{ - struct mock_host_t* new_host; - - g_assert (address); - g_assert (canonical_hostname); - - new_host = g_slice_alloc0 (sizeof(struct mock_host_t)); - g_assert (pgm_sockaddr_pton (address, (struct sockaddr*)&new_host->address)); - new_host->canonical_hostname = g_strdup (canonical_hostname); - new_host->alias = alias ? g_strdup (alias) : NULL; - - return new_host; -} - -static -gpointer -create_network ( - const char* name, - const char* number - ) -{ - struct mock_network_t* new_network; - - g_assert (name); - g_assert (number); - - new_network = g_slice_alloc0 (sizeof(struct mock_network_t)); - new_network->name = g_strdup (name); - g_assert (pgm_sockaddr_pton (number, (struct sockaddr*)&new_network->number)); - - return new_network; -} - -static -gpointer -create_interface ( - const unsigned index, - const char* name, - const char* flags - ) -{ - struct mock_interface_t* new_interface; - - g_assert (name); - g_assert (flags); - - new_interface = g_slice_alloc0 (sizeof(struct mock_interface_t)); - new_interface->index = index; - new_interface->name = g_strdup (name); - - struct sockaddr_in* sin = (gpointer)&new_interface->addr; - struct sockaddr_in6* sin6 = (gpointer)&new_interface->addr; - - gchar** tokens = g_strsplit (flags, ",", 0); - for (guint i = 0; tokens[i]; i++) - { - if (strcmp (tokens[i], "up") == 0) - new_interface->flags |= IFF_UP; - else if (strcmp (tokens[i], "down") == 0) - new_interface->flags |= 0; - else if (strcmp (tokens[i], "loop") == 0) - new_interface->flags |= IFF_LOOPBACK; - else if (strcmp (tokens[i], "broadcast") == 0) - new_interface->flags |= IFF_BROADCAST; - else if (strcmp (tokens[i], "multicast") == 0) - new_interface->flags |= IFF_MULTICAST; - else if (strncmp (tokens[i], "ip=", strlen("ip=")) == 0) { - const char* addr = tokens[i] + strlen("ip="); - g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->addr)); - } - else if (strncmp (tokens[i], "netmask=", strlen("netmask=")) == 0) { - const char* addr = tokens[i] + strlen("netmask="); - g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->netmask)); - } - else if (strncmp (tokens[i], "scope=", strlen("scope=")) == 0) { - const char* scope = tokens[i] + strlen("scope="); - g_assert (AF_INET6 == ((struct sockaddr*)&new_interface->addr)->sa_family); - ((struct sockaddr_in6*)&new_interface->addr)->sin6_scope_id = atoi (scope); - } - else - g_error ("parsing failed for flag %s%s%s", - tokens[i] ? "\"" : "", tokens[i] ? tokens[i] : "(null)", tokens[i] ? "\"" : ""); - } - - g_strfreev (tokens); - return new_interface; -} - -#define APPEND_HOST2(a,b,c) \ - do { \ - gpointer data = create_host ((a), (b), (c)); \ - g_assert (data); \ - mock_hosts = g_list_append (mock_hosts, data); \ - g_assert (mock_hosts); g_assert (mock_hosts->data); \ - } while (0) -#define APPEND_HOST(a,b) APPEND_HOST2((a),(b),NULL) -#define APPEND_NETWORK(a,b) \ - do { \ - gpointer data = create_network ((a), (b)); \ - g_assert (data); \ - mock_networks = g_list_append (mock_networks, data); \ - g_assert (mock_networks); g_assert (mock_networks->data); \ - } while (0) -#define APPEND_INTERFACE(a,b,c) \ - do { \ - gpointer data = create_interface ((a), (b), (c)); \ - g_assert (data); \ - mock_interfaces = g_list_append (mock_interfaces, data); \ - g_assert (mock_interfaces); g_assert (mock_interfaces->data); \ - } while (0) -static -void -mock_setup_net (void) -{ - mock_hostname = mock_kiku; - - APPEND_HOST ( "127.0.0.1", "localhost"); - APPEND_HOST2( "10.6.28.33", "kiku.hk.miru.hk", "kiku"); - APPEND_HOST2( "2002:dce8:d28e::33", "ip6-kiku", "kiku"); - APPEND_HOST2( "172.12.90.1", "mi-hee.ko.miru.hk", "mi-hee"); - APPEND_HOST2( "::1", "ip6-localhost", "ip6-loopback"); - APPEND_HOST ( "239.192.0.1", "PGM.MCAST.NET"); - APPEND_HOST ( "ff08::1", "IP6-PGM.MCAST.NET"); - - APPEND_NETWORK( "loopback", "127.0.0.0"); - APPEND_NETWORK( "private", "10.6.28.0"); - APPEND_NETWORK( "private2", "172.16.90.0"); - APPEND_NETWORK( "pgm-private", "239.192.0.1"); -#ifdef CONFIG_HAVE_IP6_NETWORKS - APPEND_NETWORK( "ip6-private", "2002:dce8:d28e:0:0:0"); - APPEND_NETWORK( "ip6-pgm-private","ff08::1"); -#endif - - APPEND_INTERFACE( 1, "lo", "up,loop"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast"); - APPEND_INTERFACE( 3, "eth1", "down,broadcast,multicast"); - APPEND_INTERFACE( 1, "lo", "up,loop,ip=127.0.0.1,netmask=255.0.0.0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=10.6.28.33,netmask=255.255.255.0"); - APPEND_INTERFACE( 1, "lo", "up,loop,ip=::1,netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,scope=0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=2002:dce8:d28e::33,netmask=ffff:ffff:ffff:ffff::0,scope=0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=fe80::214:5eff:febd:6dda,netmask=ffff:ffff:ffff:ffff::0,scope=2"); -} - -static -void -mock_teardown_net (void) -{ - GList* list; - - list = mock_hosts; - while (list) { - struct mock_host_t* host = list->data; - g_free (host->canonical_hostname); - if (host->alias) - g_free (host->alias); - g_slice_free1 (sizeof(struct mock_host_t), host); - list = list->next; - } - g_list_free (mock_hosts); - - list = mock_networks; - while (list) { - struct mock_network_t* network = list->data; - g_free (network->name); - g_slice_free1 (sizeof(struct mock_network_t), network); - list = list->next; - } - g_list_free (mock_networks); - - list = mock_interfaces; - while (list) { - struct mock_interface_t* interface = list->data; - g_free (interface->name); - g_slice_free1 (sizeof(struct mock_interface_t), interface); - list = list->next; - } - g_list_free (mock_interfaces); -} - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - -bool -mock_pgm_getifaddrs ( - struct pgm_ifaddrs_t** ifap, - pgm_error_t** err - ) -{ - if (NULL == ifap) { - return -1; - } - - g_debug ("mock_getifaddrs (ifap:%p err:%p)", (gpointer)ifap, (gpointer)err); - - GList* list = mock_interfaces; - int n = g_list_length (list); - struct pgm_ifaddrs_t* ifa = calloc (n, sizeof(struct pgm_ifaddrs_t)); - struct pgm_ifaddrs_t* ift = ifa; - while (list) { - struct mock_interface_t* interface = list->data; - ift->ifa_addr = (gpointer)&interface->addr; - ift->ifa_name = interface->name; - ift->ifa_flags = interface->flags; - ift->ifa_netmask = (gpointer)&interface->netmask; - list = list->next; - if (list) { - ift->ifa_next = ift + 1; - ift = ift->ifa_next; - } - } - - *ifap = ifa; - return TRUE; -} - -void -mock_pgm_freeifaddrs ( - struct pgm_ifaddrs_t* ifa - ) -{ - free (ifa); -} - -unsigned -mock_pgm_if_nametoindex ( - const sa_family_t iffamily, - const char* ifname - ) -{ - GList* list = mock_interfaces; - while (list) { - const struct mock_interface_t* interface = list->data; - if (0 == strcmp (ifname, interface->name)) - return interface->index; - list = list->next; - } - return 0; -} - -char* -mock_if_indextoname ( - unsigned ifindex, - char* ifname - ) -{ - GList* list = mock_interfaces; - while (list) { - const struct mock_interface_t* interface = list->data; - if (interface->index == ifindex) { - strcpy (ifname, interface->name); - return ifname; - } - list = list->next; - } - errno = ENXIO; - return NULL; -} - -int -mock_getnameinfo ( - const struct sockaddr* sa, - socklen_t salen, - char* host, - size_t hostlen, - char* serv, - size_t servlen, - int flags - ) -{ - if ((0 == hostlen && 0 == servlen) || - (NULL == host && NULL == serv)) - return EAI_NONAME; - - if (flags & NI_NUMERICHOST && flags & NI_NAMEREQD) - return EAI_BADFLAGS; - -/* pre-conditions */ - g_assert (NULL != host); - g_assert (hostlen > 0); - g_assert (NULL == serv); - g_assert (0 == servlen); - - const int sa_family = sa->sa_family; - - if (AF_INET == sa_family) - g_assert (sizeof(struct sockaddr_in) == salen); - else { - g_assert (AF_INET6 == sa_family); - g_assert (sizeof(struct sockaddr_in6) == salen); - } - - if (!(flags & NI_NUMERICHOST)) - { - GList* list = mock_hosts; - while (list) { - const struct mock_host_t* _host = list->data; - const int host_family = ((struct sockaddr*)&_host->address)->sa_family; - const size_t host_len = AF_INET == host_family ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - - if (host_family == sa_family && - host_len == salen && - 0 == memcmp (sa, &_host->address, salen)) - { - if (hostlen < (1 + strlen(_host->canonical_hostname))) - return EAI_OVERFLOW; - strncpy (host, _host->canonical_hostname, hostlen); - return 0; - } - list = list->next; - } - - if (flags & NI_NAMEREQD) - return EAI_NONAME; - } - - if (AF_INET == sa_family) - pgm_inet_ntop (sa_family, &((const struct sockaddr_in*)sa)->sin_addr, host, hostlen); - else { - const unsigned scope = ((const struct sockaddr_in6*)sa)->sin6_scope_id; - pgm_inet_ntop (sa_family, &((const struct sockaddr_in6*)sa)->sin6_addr, host, hostlen); - if (scope) { - char buffer[1+IF_NAMESIZE]; - strcat (host, "%"); - strcat (host, mock_if_indextoname (scope, buffer)); - } - } - return 0; -} - -int -mock_getaddrinfo ( - const char* node, - const char* service, - const struct addrinfo* hints, - struct addrinfo** res - ) -{ - const int ai_flags = hints ? hints->ai_flags : (AI_V4MAPPED | AI_ADDRCONFIG); - const int ai_family = hints ? hints->ai_family : AF_UNSPEC; - GList* list; - struct sockaddr_storage addr; - - if (NULL == node && NULL == service) - return EAI_NONAME; - -/* pre-conditions */ - g_assert (NULL != node); - g_assert (NULL == service); - g_assert (!(ai_flags & AI_CANONNAME)); - g_assert (!(ai_flags & AI_NUMERICSERV)); - g_assert (!(ai_flags & AI_V4MAPPED)); - - g_message ("mock_getaddrinfo (node:%s%s%s service:%s%s%s hints:%p res:%p)", - node ? "\"" : "", node ? node : "(null)", node ? "\"" : "", - service ? "\"" : "", service ? service : "(null)", service ? "\"" : "", - (gpointer)hints, - (gpointer)res); - - gboolean has_ip4_config; - gboolean has_ip6_config; - - if (hints && hints->ai_flags & AI_ADDRCONFIG) - { - has_ip4_config = has_ip6_config = FALSE; - list = mock_interfaces; - while (list) { - const struct mock_interface_t* interface = list->data; - if (AF_INET == ((struct sockaddr*)&interface->addr)->sa_family) - has_ip4_config = TRUE; - else if (AF_INET6 == ((struct sockaddr*)&interface->addr)->sa_family) - has_ip6_config = TRUE; - if (has_ip4_config && has_ip6_config) - break; - list = list->next; - } - } else { - has_ip4_config = has_ip6_config = TRUE; - } - - if (ai_flags & AI_NUMERICHOST) { - pgm_sockaddr_pton (node, (struct sockaddr*)&addr); - } - list = mock_hosts; - while (list) { - struct mock_host_t* host = list->data; - const int host_family = ((struct sockaddr*)&host->address)->sa_family; - if (((strcmp (host->canonical_hostname, node) == 0) || - (host->alias && strcmp (host->alias, node) == 0) || - (ai_flags & AI_NUMERICHOST && - 0 == pgm_sockaddr_cmp ((struct sockaddr*)&addr, (struct sockaddr*)&host->address))) - && - (host_family == ai_family || AF_UNSPEC == ai_family) && - ((AF_INET == host_family && has_ip4_config) || (AF_INET6 == host_family && has_ip6_config))) - { - struct addrinfo* ai = malloc (sizeof(struct addrinfo)); - memset (ai, 0, sizeof(struct addrinfo)); - ai->ai_family = host_family; - ai->ai_addrlen = AF_INET == host_family ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - ai->ai_addr = (gpointer)&host->address; - *res = ai; - return 0; - } - list = list->next; - } - return EAI_NONAME; -} - -void -mock_freeaddrinfo ( - struct addrinfo* res - ) -{ - free (res); -} - -int -mock_gethostname ( - char* name, - size_t len - ) -{ - if (NULL == name) { - errno = EFAULT; - return -1; - } - if (len < 0) { - errno = EINVAL; - return -1; - } - if (len < (1 + strlen (mock_hostname))) { - errno = ENAMETOOLONG; - return -1; - } -/* force an error */ - if (mock_hostname == mock_toolong) { - errno = ENAMETOOLONG; - return -1; - } - strncpy (name, mock_hostname, len); - if (len > 0) - name[len - 1] = '\0'; - return 0; -} - -struct netent* -mock_getnetbyname ( - const char* name - ) -{ - static struct netent ne; - GList* list = mock_networks; - - if (NULL == name) - return NULL; - - while (list) { - const struct mock_network_t* network = list->data; - if (strcmp (network->name, name) == 0) { - ne.n_name = network->name; - ne.n_aliases = network->aliases; - ne.n_addrtype = AF_INET; - ne.n_net = g_ntohl (((struct sockaddr_in*)&network->number)->sin_addr.s_addr); - return ≠ - } - list = list->next; - } - return NULL; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_if_getnodeaddr ( - const sa_family_t family, - struct sockaddr* addr, - const socklen_t cnt, - pgm_error_t** error - ) -{ - switch (family) { - case AF_UNSPEC: - case AF_INET: - ((struct sockaddr*)addr)->sa_family = AF_INET; - ((struct sockaddr_in*)addr)->sin_addr.s_addr = inet_addr(MOCK_ADDRESS); - break; - case AF_INET6: - ((struct sockaddr*)addr)->sa_family = AF_INET6; - ((struct sockaddr_in6*)addr)->sin6_addr = mock_address6_addr; - break; - default: - g_assert_not_reached(); - } - return TRUE; -} - -/* following tests will use AF_UNSPEC address family */ - -static -void -mock_setup_unspec (void) -{ - mock_family = AF_UNSPEC; -} - -/* following tests will use AF_INET address family */ - -static -void -mock_setup_ip4 (void) -{ - mock_family = AF_INET; -} - -/* following tests will use AF_INET6 address family */ - -static -void -mock_setup_ip6 (void) -{ - mock_family = AF_INET6; -} - - -/* return 0 if gsr multicast group does not match the default PGM group for - * the address family, return -1 on no match. - */ - -static -gboolean -match_default_group ( - const int ai_family, - const struct group_source_req* gsr - ) -{ - const struct sockaddr_in sa_default = { - .sin_family = AF_INET, - .sin_addr.s_addr = g_htonl (MOCK_GROUP) - }; - const struct sockaddr_in6 sa6_default = { - .sin6_family = AF_INET6, - .sin6_addr = MOCK_GROUP6_INIT - }; - gboolean is_match = FALSE; - - switch (ai_family) { - case AF_UNSPEC: - case AF_INET: - is_match = (0 == pgm_sockaddr_cmp ((struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&sa_default)); - if (!is_match) { - char addr1[INET6_ADDRSTRLEN], addr2[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&gsr->gsr_group, addr1, sizeof(addr1)); - pgm_sockaddr_ntop ((struct sockaddr*)&sa_default, addr2, sizeof(addr2)); - g_message ("FALSE == cmp(%s%s%s, default-group %s%s%s)", - addr1 ? "\"" : "", addr1 ? addr1 : "(null)", addr1 ? "\"" : "", - addr2 ? "\"" : "", addr2 ? addr2 : "(null)", addr2 ? "\"" : ""); - } - break; - case AF_INET6: - is_match = (0 == pgm_sockaddr_cmp ((struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&sa6_default)); - if (!is_match) { - char addr1[INET6_ADDRSTRLEN], addr2[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&gsr->gsr_group, addr1, sizeof(addr1)); - pgm_sockaddr_ntop ((struct sockaddr*)&sa6_default, addr2, sizeof(addr2)); - g_message ("FALSE == cmp(%s%s%s, default-group %s%s%s)", - addr1 ? "\"" : "", addr1 ? addr1 : "(null)", addr1 ? "\"" : "", - addr2 ? "\"" : "", addr2 ? addr2 : "(null)", addr2 ? "\"" : ""); - } - default: - break; - } - return is_match; -} - -/* return 0 if gsr source inteface does not match the INADDR_ANY reserved - * address, return -1 on no match. - */ - -static -int -match_default_source ( - const int ai_family, - const struct group_source_req* gsr - ) -{ - if (0 != gsr->gsr_interface) - return FALSE; - -/* ASM: source == group */ - return (0 == pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&gsr->gsr_source)); -} - -/* return 0 if gsr source interface does not match the hosts default interface, - * return -1 on mismatch - */ - -static -int -match_default_interface ( - const int ai_family, - const struct group_source_req* gsr - ) -{ - if (MOCK_INTERFACE_INDEX != gsr->gsr_interface) - return FALSE; - -/* ASM: source == group */ - return (0 == pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&gsr->gsr_source)); -} - -/* target: - * bool - * pgm_getaddrinfo ( - * const char* s, - * const struct pgm_addrinfo_t* const hints, - * struct pgm_addrinfo_t** res, - * pgm_error_t** err - * ) - */ - -struct test_case_t { - const char* ip4; - const char* ip6; -}; - -#define IP4_AND_IP6(x) x, x - -static const struct test_case_t cases_001[] = { - { IP4_AND_IP6("") }, - { IP4_AND_IP6(";") }, - { IP4_AND_IP6(";;") }, - { "239.192.0.1", "ff08::1" }, - { "239.192.0.1", "[ff08::1]" }, - { ";239.192.0.1", ";ff08::1" }, - { ";239.192.0.1", ";[ff08::1]" }, - { ";239.192.0.1;239.192.0.1", ";ff08::1;ff08::1" }, - { ";239.192.0.1;239.192.0.1", ";[ff08::1];[ff08::1]" }, - { "PGM.MCAST.NET", "IP6-PGM.MCAST.NET" }, - { ";PGM.MCAST.NET", ";IP6-PGM.MCAST.NET" }, - { ";PGM.MCAST.NET;PGM.MCAST.NET", ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, - { ";239.192.0.1;PGM.MCAST.NET", ";ff08::1;IP6-PGM.MCAST.NET" }, - { ";239.192.0.1;PGM.MCAST.NET", ";[ff08::1];IP6-PGM.MCAST.NET" }, - { ";PGM.MCAST.NET;239.192.0.1", ";IP6-PGM.MCAST.NET;ff08::1" }, - { ";PGM.MCAST.NET;239.192.0.1", ";IP6-PGM.MCAST.NET;[ff08::1]" }, - { "pgm-private", /* ‡ */ "pgm-ip6-private" }, - { ";pgm-private", /* ‡ */ ";pgm-ip6-private" }, - { ";pgm-private;pgm-private", /* ‡ */ ";pgm-ip6-private;pgm-ip6-private" }, - { ";PGM.MCAST.NET;pgm-private", /* ‡ */ ";IP6-PGM.MCAST.NET;pgm-ip6-private" }, - { ";pgm-private;PGM.MCAST.NET", /* ‡ */ ";pgm-ip6-private;IP6-PGM.MCAST.NET" }, - { ";239.192.0.1;pgm-private", /* ‡ */ ";ff08::1;pgm-ip6-private" }, - { ";239.192.0.1;pgm-private", /* ‡ */ ";[ff08::1];pgm-ip6-private" }, - { ";pgm-private;239.192.0.1", /* ‡ */ ";pgm-ip6-private;ff08::1" }, - { ";pgm-private;239.192.0.1", /* ‡ */ ";pgm-ip6-private;[ff08::1]" }, -}; - -START_TEST (test_parse_transport_pass_001) -{ - fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); - - const char* s = (mock_family == AF_INET6) ? cases_001[_i].ip6 : cases_001[_i].ip4; - struct pgm_addrinfo_t hints = { - .ai_family = mock_family - }, *res = NULL; - pgm_error_t* err = NULL; - - g_message ("%i: test_parse_transport_001(%s, %s%s%s)", - _i, - (mock_family == AF_INET6) ? "AF_INET6" : ( (mock_family == AF_INET) ? "AF_INET" : "AF_UNSPEC" ), - s ? "\"" : "", s ? s : "(null)", s ? "\"" : ""); - -/* ‡ Linux does not support IPv6 /etc/networks so IPv6 entries appear as 255.255.255.255 and - * pgm_if_parse_transport will fail. - */ -#ifndef CONFIG_HAVE_IP6_NETWORKS - if (NULL != strstr (s, MOCK_NETWORK6) || NULL != strstr (s, MOCK_PGM_NETWORK6)) - { - g_message ("IPv6 exception, /etc/networks not supported on this platform."); - return; - } -#endif - - gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); - if (!retval) { - g_message ("pgm_getaddrinfo: %s", - (err && err->message) ? err->message : "(null)"); - } - fail_unless (TRUE == retval, "pgm_getaddrinfo failed"); - fail_if (NULL == res, "no result"); - fail_unless (NULL == err, "error raised"); - - fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); - fail_unless (match_default_group (mock_family, &res->ai_recv_addrs[0]), "receive address not match default group"); - fail_unless (match_default_source (mock_family, &res->ai_recv_addrs[0]), "receive address not match default source"); - fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); - fail_unless (match_default_group (mock_family, &res->ai_send_addrs[0]), "send address not match default group"); - fail_unless (match_default_source (mock_family, &res->ai_send_addrs[0]), "send address not match default source"); -} -END_TEST - -/* interface name - * - * pre-condition: interface defined to match running host - * ipv4 and ipv6 hostnames are different, otherwise "" tests might go unexpected. - */ - -static const struct test_case_t cases_002[] = { - { MOCK_INTERFACE, /* † */ MOCK_INTERFACE }, - { MOCK_INTERFACE ";", /* † */ MOCK_INTERFACE ";" }, - { MOCK_INTERFACE ";;", /* † */ MOCK_INTERFACE ";;" }, - { MOCK_INTERFACE ";239.192.0.1", /* † */ MOCK_INTERFACE ";ff08::1" }, - { MOCK_INTERFACE ";239.192.0.1", /* † */ MOCK_INTERFACE ";[ff08::1]" }, - { MOCK_INTERFACE ";239.192.0.1;239.192.0.1", /* † */ MOCK_INTERFACE ";ff08::1;ff08::1" }, - { MOCK_INTERFACE ";239.192.0.1;239.192.0.1", /* † */ MOCK_INTERFACE ";[ff08::1];[ff08::1]" }, - { MOCK_INTERFACE ";PGM.MCAST.NET", /* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET" }, - { MOCK_INTERFACE ";PGM.MCAST.NET;PGM.MCAST.NET",/* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, - { MOCK_INTERFACE ";239.192.0.1;PGM.MCAST.NET", /* † */ MOCK_INTERFACE ";ff08::1;IP6-PGM.MCAST.NET" }, - { MOCK_INTERFACE ";239.192.0.1;PGM.MCAST.NET", /* † */ MOCK_INTERFACE ";[ff08::1];IP6-PGM.MCAST.NET" }, - { MOCK_INTERFACE ";PGM.MCAST.NET;239.192.0.1", /* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET;ff08::1" }, - { MOCK_INTERFACE ";PGM.MCAST.NET;239.192.0.1", /* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET;[ff08::1]" }, - { MOCK_INTERFACE ";pgm-private", /* ‡ */ MOCK_INTERFACE ";pgm-ip6-private" }, - { MOCK_INTERFACE ";pgm-private;pgm-private", /* ‡ */ MOCK_INTERFACE ";pgm-ip6-private;pgm-ip6-private" }, - { MOCK_ADDRESS, MOCK_ADDRESS6 }, - { MOCK_ADDRESS, "[" MOCK_ADDRESS6 "]" }, - { MOCK_ADDRESS ";", MOCK_ADDRESS6 ";" }, - { MOCK_ADDRESS ";", "[" MOCK_ADDRESS6 "];" }, - { MOCK_ADDRESS ";;", MOCK_ADDRESS6 ";;" }, - { MOCK_ADDRESS ";;", "[" MOCK_ADDRESS6 "];;" }, - { MOCK_ADDRESS ";239.192.0.1", MOCK_ADDRESS6 ";ff08::1" }, - { MOCK_ADDRESS ";239.192.0.1", "[" MOCK_ADDRESS6 "];[ff08::1]" }, - { MOCK_ADDRESS ";239.192.0.1;239.192.0.1", MOCK_ADDRESS6 ";ff08::1;ff08::1" }, - { MOCK_ADDRESS ";239.192.0.1;239.192.0.1", "[" MOCK_ADDRESS6 "];[ff08::1];[ff08::1]" }, - { MOCK_ADDRESS ";PGM.MCAST.NET", MOCK_ADDRESS6 ";IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS ";PGM.MCAST.NET", "[" MOCK_ADDRESS6 "];IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS ";PGM.MCAST.NET;PGM.MCAST.NET", MOCK_ADDRESS6 ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS ";PGM.MCAST.NET;PGM.MCAST.NET", "[" MOCK_ADDRESS6 "];IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS ";239.192.0.1;PGM.MCAST.NET", MOCK_ADDRESS6 ";ff08::1;IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS ";239.192.0.1;PGM.MCAST.NET", "[" MOCK_ADDRESS6 "];[ff08::1];IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS ";PGM.MCAST.NET;239.192.0.1", MOCK_ADDRESS6 ";IP6-PGM.MCAST.NET;ff08::1" }, - { MOCK_ADDRESS ";PGM.MCAST.NET;239.192.0.1", "[" MOCK_ADDRESS6 "];IP6-PGM.MCAST.NET;[ff08::1]" }, - { MOCK_ADDRESS ";pgm-private", MOCK_ADDRESS6 ";pgm-ip6-private" }, - { MOCK_ADDRESS ";pgm-private", "[" MOCK_ADDRESS6 "];pgm-ip6-private" }, - { MOCK_ADDRESS ";pgm-private;pgm-private", MOCK_ADDRESS6 ";pgm-ip6-private;pgm-ip6-private" }, - { MOCK_ADDRESS ";pgm-private;pgm-private", "[" MOCK_ADDRESS6 "];pgm-ip6-private;pgm-ip6-private" }, - { MOCK_NETWORK, /* ‡ */ MOCK_NETWORK6 }, - { MOCK_NETWORK ";", /* ‡ */ MOCK_NETWORK6 ";" }, - { MOCK_NETWORK ";;", /* ‡ */ MOCK_NETWORK6 ";;" }, - { MOCK_NETWORK ";239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";ff08::1" }, - { MOCK_NETWORK ";239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";[ff08::1]" }, - { MOCK_NETWORK ";239.192.0.1;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";ff08::1;ff08::1" }, - { MOCK_NETWORK ";239.192.0.1;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";[ff08::1];[ff08::1]" }, - { MOCK_NETWORK ";PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET" }, - { MOCK_NETWORK ";PGM.MCAST.NET;PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, - { MOCK_NETWORK ";239.192.0.1;PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";ff08::1;IP6-PGM.MCAST.NET" }, - { MOCK_NETWORK ";239.192.0.1;PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";[ff08::1];IP6-PGM.MCAST.NET" }, - { MOCK_NETWORK ";PGM.MCAST.NET;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET;ff08::1" }, - { MOCK_NETWORK ";PGM.MCAST.NET;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET;[ff08::1]" }, - { MOCK_NETWORK ";pgm-private", /* ‡ */ MOCK_NETWORK6 ";pgm-ip6-private" }, - { MOCK_NETWORK ";pgm-private;pgm-private", /* ‡ */ MOCK_NETWORK6 ";pgm-ip6-private;pgm-ip6-private" }, - { MOCK_HOSTNAME, MOCK_HOSTNAME6 }, - { MOCK_HOSTNAME ";", MOCK_HOSTNAME6 ";" }, - { MOCK_HOSTNAME ";;", MOCK_HOSTNAME6 ";;" }, - { MOCK_HOSTNAME ";239.192.0.1", MOCK_HOSTNAME6 ";ff08::1" }, - { MOCK_HOSTNAME ";239.192.0.1", MOCK_HOSTNAME6 ";[ff08::1]" }, - { MOCK_HOSTNAME ";239.192.0.1;239.192.0.1", MOCK_HOSTNAME6 ";ff08::1;ff08::1" }, - { MOCK_HOSTNAME ";239.192.0.1;239.192.0.1", MOCK_HOSTNAME6 ";[ff08::1];[ff08::1]" }, - { MOCK_HOSTNAME ";PGM.MCAST.NET", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET" }, - { MOCK_HOSTNAME ";PGM.MCAST.NET;PGM.MCAST.NET", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, - { MOCK_HOSTNAME ";239.192.0.1;PGM.MCAST.NET", MOCK_HOSTNAME6 ";ff08::1;IP6-PGM.MCAST.NET" }, - { MOCK_HOSTNAME ";239.192.0.1;PGM.MCAST.NET", MOCK_HOSTNAME6 ";[ff08::1];IP6-PGM.MCAST.NET" }, - { MOCK_HOSTNAME ";PGM.MCAST.NET;239.192.0.1", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET;ff08::1" }, - { MOCK_HOSTNAME ";PGM.MCAST.NET;239.192.0.1", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET;[ff08::1]" }, - { MOCK_HOSTNAME ";pgm-private", MOCK_HOSTNAME6 ";pgm-ip6-private" }, - { MOCK_HOSTNAME ";pgm-private;pgm-private", MOCK_HOSTNAME6 ";pgm-ip6-private;pgm-ip6-private" }, -}; - -START_TEST (test_parse_transport_pass_002) -{ - fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); - - const char* s = (mock_family == AF_INET6) ? cases_002[_i].ip6 : cases_002[_i].ip4; - struct pgm_addrinfo_t hints = { - .ai_family = mock_family - }, *res = NULL; - pgm_error_t* err = NULL; - - g_message ("%i: test_parse_transport_002(%s, %s%s%s)", - _i, - (mock_family == AF_INET6) ? "AF_INET6" : ( (mock_family == AF_INET) ? "AF_INET" : "AF_UNSPEC" ), - s ? "\"" : "", s ? s : "(null)", s ? "\"" : ""); - -/* ‡ Linux does not support IPv6 /etc/networks so IPv6 entries appear as 255.255.255.255 and - * pgm_if_parse_transport will fail. - */ -#ifndef CONFIG_HAVE_IP6_NETWORKS - if (NULL != strstr (s, MOCK_NETWORK6) || NULL != strstr (s, MOCK_PGM_NETWORK6)) - { - g_message ("IPv6 exception, /etc/networks not supported on this platform."); - return; - } -#endif - -/* † Multiple scoped IPv6 interfaces match a simple interface name network parameter and so - * pgm-if_parse_transport will fail finding multiple matching interfaces - */ - if (AF_INET6 == mock_family && 0 == strncmp (s, MOCK_INTERFACE, strlen (MOCK_INTERFACE))) - { - g_message ("IPv6 exception, multiple scoped addresses on one interface"); - fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); - fail_unless (NULL == res, "unexpected result"); - fail_if (NULL == err, "error not raised"); - fail_unless (PGM_ERROR_NOTUNIQ == err->code, "interfaces not found unique"); - return; - } - - fail_unless (TRUE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); - fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); - fail_unless (match_default_group (mock_family, &res->ai_recv_addrs[0]), "receive address not match default group"); - fail_unless (match_default_interface (mock_family, &res->ai_recv_addrs[0]), "receive address not match default interface"); - fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); - fail_unless (match_default_group (mock_family, &res->ai_send_addrs[0]), "send address not match default group"); - fail_unless (match_default_interface (mock_family, &res->ai_send_addrs[0]), "send address not match default interface"); -} -END_TEST - -/* network to node address in bits, 8-32 - * - * e.g. 127.0.0.1/16 - */ - -static const struct test_case_t cases_003[] = { - { MOCK_ADDRESS "/24", MOCK_ADDRESS6 "/64" }, - { MOCK_ADDRESS "/24;", MOCK_ADDRESS6 "/64;" }, - { MOCK_ADDRESS "/24;;", MOCK_ADDRESS6 "/64;;" }, - { MOCK_ADDRESS "/24;239.192.0.1", MOCK_ADDRESS6 "/64;ff08::1" }, - { MOCK_ADDRESS "/24;239.192.0.1", MOCK_ADDRESS6 "/64;[ff08::1]" }, - { MOCK_ADDRESS "/24;239.192.0.1;239.192.0.1", MOCK_ADDRESS6 "/64;ff08::1;ff08::1" }, - { MOCK_ADDRESS "/24;239.192.0.1;239.192.0.1", MOCK_ADDRESS6 "/64;[ff08::1];[ff08::1]" }, - { MOCK_ADDRESS "/24;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS "/24;PGM.MCAST.NET;PGM.MCAST.NET",MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS "/24;239.192.0.1;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;ff08::1;IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS "/24;239.192.0.1;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;[ff08::1];IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS "/24;PGM.MCAST.NET;239.192.0.1", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;ff08::1" }, - { MOCK_ADDRESS "/24;PGM.MCAST.NET;239.192.0.1", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;[ff08::1]" }, - { MOCK_ADDRESS "/24;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS "/24;PGM.MCAST.NET;PGM.MCAST.NET",MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, - { MOCK_ADDRESS "/24;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private" }, - { MOCK_ADDRESS "/24;pgm-private;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;pgm-ip6-private" }, - { MOCK_ADDRESS "/24;239.192.0.1;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;ff08::1;pgm-ip6-private" }, - { MOCK_ADDRESS "/24;239.192.0.1;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;[ff08::1];pgm-ip6-private" }, - { MOCK_ADDRESS "/24;pgm-private;239.192.0.1", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;ff08::1" }, - { MOCK_ADDRESS "/24;pgm-private;239.192.0.1", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;[ff08::1]" }, - { MOCK_ADDRESS "/24;PGM.MCAST.NET;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;pgm-ip6-private" }, - { MOCK_ADDRESS "/24;pgm-private;PGM.MCAST.NET", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;IP6-PGM.MCAST.NET" }, -}; - -START_TEST (test_parse_transport_pass_003) -{ - fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); - - const char* s = (mock_family == AF_INET6) ? cases_003[_i].ip6 : cases_003[_i].ip4; - struct pgm_addrinfo_t hints = { - .ai_family = mock_family - }, *res = NULL; - pgm_error_t* err = NULL; - - g_message ("%i: test_parse_transport_003(%s, %s%s%s)", - _i, - (mock_family == AF_INET6) ? "AF_INET6" : ( (mock_family == AF_INET) ? "AF_INET" : "AF_UNSPEC" ), - s ? "\"" : "", s ? s : "(null)", s ? "\"" : ""); - -/* ‡ Linux does not support IPv6 /etc/networks so IPv6 entries appear as 255.255.255.255 and - * pgm_if_parse_transport will fail. - */ -#ifndef CONFIG_HAVE_IP6_NETWORKS - if (NULL != strstr (s, MOCK_NETWORK6) || NULL != strstr (s, MOCK_PGM_NETWORK6)) - { - g_message ("IPv6 exception, /etc/networks not supported on this platform."); - return; - } -#endif - - gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); - if (!retval) { - g_message ("pgm_getaddrinfo: %s", - (err && err->message) ? err->message : "(null)"); - } - fail_unless (TRUE == retval, "pgm_getaddrinfo failed"); - fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); - fail_unless (match_default_group (mock_family, &res->ai_recv_addrs[0]), "receive address not match default group"); - fail_unless (match_default_interface (mock_family, &res->ai_recv_addrs[0]), "receive address not match default interface"); - fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); - fail_unless (match_default_group (mock_family, &res->ai_send_addrs[0]), "send address not match default group"); - fail_unless (match_default_interface (mock_family, &res->ai_send_addrs[0]), "send address not match default interface"); -} -END_TEST - -/* asymmetric groups - */ - -START_TEST (test_parse_transport_pass_004) -{ - fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); - - const char* s = (mock_family == AF_INET6) ? ";ff08::1;ff08::2" - /* AF_INET */: ";239.192.56.1;239.192.56.2"; - struct pgm_addrinfo_t hints = { - .ai_family = mock_family - }, *res = NULL; - pgm_error_t* err = NULL; - struct sockaddr_storage addr; - - fail_unless (TRUE == pgm_getaddrinfo (s, &hints, &res, &err), "get_transport_info failed"); - fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); - fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); - if (mock_family == AF_INET6) - { - inet_pton (AF_INET6, "ff08::1", &((struct sockaddr_in6*)&addr)->sin6_addr); - ((struct sockaddr*)&addr)->sa_family = mock_family; - ((struct sockaddr_in6*)&addr)->sin6_port = 0; - ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; - ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; - fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); - inet_pton (AF_INET6, "ff08::2", &((struct sockaddr_in6*)&addr)->sin6_addr); - ((struct sockaddr*)&addr)->sa_family = mock_family; - ((struct sockaddr_in6*)&addr)->sin6_port = 0; - ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; - ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; - fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); - } else { - inet_pton (AF_INET, "239.192.56.1", &((struct sockaddr_in*)&addr)->sin_addr); - ((struct sockaddr*)&addr)->sa_family = AF_INET; - fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); - inet_pton (AF_INET, "239.192.56.2", &((struct sockaddr_in*)&addr)->sin_addr); - ((struct sockaddr*)&addr)->sa_family = AF_INET; - fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); - } - fail_unless (match_default_source (mock_family, &res->ai_recv_addrs[0]), "source not match"); - fail_unless (match_default_source (mock_family, &res->ai_send_addrs[0]), "source not match"); -} -END_TEST - -/* multiple receive groups and asymmetric sending - */ - -START_TEST (test_parse_transport_pass_005) -{ - fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); - - const char* s = (mock_family == AF_INET6) ? ";ff08::1,ff08::2;ff08::3" - /* AF_INET */: ";239.192.56.1,239.192.56.2;239.192.56.3"; - struct pgm_addrinfo_t hints = { - .ai_family = mock_family - }, *res = NULL; - pgm_error_t* err = NULL; - struct sockaddr_storage addr; - - fail_unless (TRUE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); - fail_unless (2 == res->ai_recv_addrs_len, "not exactly one receive address"); - fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); - if (mock_family == AF_INET6) - { - inet_pton (AF_INET6, "ff08::1", &((struct sockaddr_in6*)&addr)->sin6_addr); - ((struct sockaddr*)&addr)->sa_family = mock_family; - ((struct sockaddr_in6*)&addr)->sin6_port = 0; - ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; - ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; - fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); - inet_pton (AF_INET6, "ff08::2", &((struct sockaddr_in6*)&addr)->sin6_addr); - ((struct sockaddr*)&addr)->sa_family = mock_family; - ((struct sockaddr_in6*)&addr)->sin6_port = 0; - ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; - ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; - fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[1].gsr_group, (struct sockaddr*)&addr), "group not match"); - inet_pton (AF_INET6, "ff08::3", &((struct sockaddr_in6*)&addr)->sin6_addr); - ((struct sockaddr*)&addr)->sa_family = mock_family; - ((struct sockaddr_in6*)&addr)->sin6_port = 0; - ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; - ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; - fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); - } else { - inet_pton (AF_INET, "239.192.56.1", &((struct sockaddr_in*)&addr)->sin_addr); - ((struct sockaddr*)&addr)->sa_family = AF_INET; - fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); - inet_pton (AF_INET, "239.192.56.2", &((struct sockaddr_in*)&addr)->sin_addr); - ((struct sockaddr*)&addr)->sa_family = AF_INET; - fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[1].gsr_group, (struct sockaddr*)&addr), "group not match"); - inet_pton (AF_INET, "239.192.56.3", &((struct sockaddr_in*)&addr)->sin_addr); - ((struct sockaddr*)&addr)->sa_family = AF_INET; - fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); - } - fail_unless (match_default_source (mock_family, &res->ai_recv_addrs[0]), "source not match"); - fail_unless (match_default_source (mock_family, &res->ai_send_addrs[0]), "source not match"); -} -END_TEST - - -/* too many interfaces - */ -START_TEST (test_parse_transport_fail_001) -{ - const char* s = "eth0,lo;;;"; - struct pgm_addrinfo_t hints = { - .ai_family = AF_UNSPEC - }, *res = NULL; - pgm_error_t* err = NULL; - - fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); - fail_unless (NULL == res, "unexpected result"); -} -END_TEST - -/* invalid characters, or simply just bogus - */ -START_TEST (test_parse_transport_fail_002) -{ - const char* s = "!@#$%^&*()"; - struct pgm_addrinfo_t hints = { - .ai_family = AF_UNSPEC - }, *res = NULL; - pgm_error_t* err = NULL; - - fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); - fail_unless (NULL == res, "unexpected result"); -} -END_TEST - -/* too many groups - */ -START_TEST (test_parse_transport_fail_003) -{ - const char* s = ";239.192.0.1,239.192.0.2,239.192.0.3,239.192.0.4,239.192.0.5,239.192.0.6,239.192.0.7,239.192.0.8,239.192.0.9,239.192.0.10,239.192.0.11,239.192.0.12,239.192.0.13,239.192.0.14,239.192.0.15,239.192.0.16,239.192.0.17,239.192.0.18,239.192.0.19,239.192.0.20;239.192.0.21"; - struct pgm_addrinfo_t hints = { - .ai_family = AF_UNSPEC - }, *res = NULL; - pgm_error_t* err = NULL; - - fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); - fail_unless (NULL == res, "unexpected result"); -} -END_TEST - -/* too many receiver groups in asymmetric pairing - */ -START_TEST (test_parse_transport_fail_004) -{ - const char* s = ";239.192.0.1,239.192.0.2,239.192.0.3,239.192.0.4,239.192.0.5,239.192.0.6,239.192.0.7,239.192.0.8,239.192.0.9,239.192.0.10,239.192.0.11,239.192.0.12,239.192.0.13,239.192.0.14,239.192.0.15,239.192.0.16,239.192.0.17,239.192.0.18,239.192.0.19,239.192.0.20,239.192.0.21;239.192.0.22"; - struct pgm_addrinfo_t hints = { - .ai_family = AF_UNSPEC - }, *res = NULL; - pgm_error_t* err = NULL; - - fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); - fail_unless (NULL == res, "unexpected result"); -} -END_TEST - -/* null string - */ -START_TEST (test_parse_transport_fail_005) -{ - const char* s = NULL; - struct pgm_addrinfo_t hints = { - .ai_family = AF_UNSPEC - }, *res = NULL; - pgm_error_t* err = NULL; - - fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); - fail_unless (NULL == res, "unexpected result"); -} -END_TEST - -/* invalid address family - */ -START_TEST (test_parse_transport_fail_006) -{ - const char* s = ";"; - struct pgm_addrinfo_t hints = { - .ai_family = AF_IPX - }, *res = NULL; - pgm_error_t* err = NULL; - - fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); - fail_unless (NULL == res, "unexpected result"); -} -END_TEST - -/* invalid transport info pointer - */ -START_TEST (test_parse_transport_fail_007) -{ - const char* s = ";"; - pgm_error_t* err = NULL; - - fail_unless (FALSE == pgm_getaddrinfo (s, NULL, NULL, &err), "pgm_getaddrinfo failed"); -} -END_TEST - -/* invalid interface - */ -START_TEST (test_parse_transport_fail_008) -{ - const char* s = "qe0;"; - struct pgm_addrinfo_t hints = { - .ai_family = AF_UNSPEC - }, *res = NULL; - pgm_error_t* err = NULL; - - gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); - if (!retval) { - g_message ("pgm_getaddrinfo: %s", err ? err->message : "(null)"); - } - fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); - fail_unless (NULL == res, "unexpected result"); -} -END_TEST - -/* non-existing interface IP address - */ -START_TEST (test_parse_transport_fail_009) -{ - const char* s = "172.16.90.1;"; - struct pgm_addrinfo_t hints = { - .ai_family = AF_UNSPEC - }, *res = NULL; - pgm_error_t* err = NULL; - - gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); - if (!retval) { - g_message ("pgm_getaddrinfo: %s", - (err && err->message) ? err->message : "(null)"); - } - fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); - fail_unless (NULL == res, "unexpected result"); -} -END_TEST - -/* non-existing network name address - */ -START_TEST (test_parse_transport_fail_010) -{ - const char* s = "private2;"; - struct pgm_addrinfo_t hints = { - .ai_family = AF_UNSPEC - }, *res = NULL; - pgm_error_t* err = NULL; - - gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); - if (!retval) { - g_message ("pgm_getaddrinfo: %s", - (err && err->message) ? err->message : "(null)"); - } - fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); - fail_unless (NULL == res, "unexpected result"); -} -END_TEST - -/* non-existing host name interface - */ -START_TEST (test_parse_transport_fail_011) -{ - const char* s = "mi-hee.ko.miru.hk;"; - struct pgm_addrinfo_t hints = { - .ai_family = AF_UNSPEC - }, *res = NULL; - pgm_error_t* err = NULL; - - gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); - if (!retval) { - g_message ("pgm_getaddrinfo: %s", - (err && err->message) ? err->message : "(null)"); - } - fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); - fail_unless (NULL == res, "unexpected result"); -} -END_TEST - -/* target: - * pgm_if_print_all (void) - */ - -START_TEST (test_print_all_pass_001) -{ - pgm_if_print_all (); -} -END_TEST - - -/* target: - * bool - * is_in_net ( - * const struct in_addr* addr, -- in host byte order - * const struct in_addr* netaddr, - * const struct in_addr* netmask - * ) - */ - -struct test_case_net_t { - const char* addr; - const char* netaddr; - const char* netmask; - const gboolean answer; -}; - -static const struct test_case_net_t cases_004[] = { - { "127.0.0.1", "127.0.0.1", "255.0.0.0", TRUE }, - { "127.0.0.1", "127.0.0.1", "255.255.0.0", TRUE }, - { "127.0.0.1", "127.0.0.1", "255.255.255.0", TRUE }, - { "127.0.0.1", "127.0.0.1", "255.255.255.255", TRUE }, - { "127.0.0.1", "127.0.0.0", "255.0.0.0", TRUE }, - { "127.0.0.1", "127.0.0.0", "255.255.0.0", TRUE }, - { "127.0.0.1", "127.0.0.0", "255.255.255.0", TRUE }, - { "127.0.0.1", "127.0.0.0", "255.255.255.255", FALSE }, - { "172.15.1.1", "172.16.0.0", "255.240.0.0", FALSE }, - { "172.16.1.1", "172.16.0.0", "255.240.0.0", TRUE }, - { "172.18.1.1", "172.16.0.0", "255.240.0.0", TRUE }, - { "172.31.1.1", "172.16.0.0", "255.240.0.0", TRUE }, - { "172.32.1.1", "172.16.0.0", "255.240.0.0", FALSE }, -}; - -START_TEST (test_is_in_net_pass_001) -{ - struct in_addr addr, netaddr, netmask; - fail_unless (pgm_inet_pton (AF_INET, cases_004[_i].addr, &addr)); - fail_unless (pgm_inet_pton (AF_INET, cases_004[_i].netaddr, &netaddr)); - fail_unless (pgm_inet_pton (AF_INET, cases_004[_i].netmask, &netmask)); - const gboolean answer = cases_004[_i].answer; - - addr.s_addr = g_ntohl (addr.s_addr); - netaddr.s_addr = g_ntohl (netaddr.s_addr); - netmask.s_addr = g_ntohl (netmask.s_addr); - gboolean result = is_in_net (&addr, &netaddr, &netmask); - - g_message ("result %s (%s)", - result ? "TRUE" : "FALSE", - answer ? "TRUE" : "FALSE"); - - fail_unless (answer == result); -} -END_TEST - -static const struct test_case_net_t cases_005[] = { - { "::1", "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", TRUE }, - { "fe80::203:baff:fe4e:6cc8", "fe80::", "ffff:0000:0000:0000:0000:0000:0000:0000", TRUE }, - { "2002:dec8:d28e::36", "2002:dec8:d28e::", "ffff:ffff:ffff:0000:0000:0000:0000:0000", TRUE }, - { "2002:dec8:d28e::36", "2002:dafa:939:0::", "ffff:ffff:ffff:ffff:0000:0000:0000:0000", FALSE }, -}; - -START_TEST (test_is_in_net6_pass_001) -{ - struct in6_addr addr, netaddr, netmask; - fail_unless (pgm_inet_pton (AF_INET6, cases_005[_i].addr, &addr)); - fail_unless (pgm_inet_pton (AF_INET6, cases_005[_i].netaddr, &netaddr)); - fail_unless (pgm_inet_pton (AF_INET6, cases_005[_i].netmask, &netmask)); - const gboolean answer = cases_005[_i].answer; - - gboolean result = is_in_net6 (&addr, &netaddr, &netmask); - - g_message ("result %s (%s)", - result ? "TRUE" : "FALSE", - answer ? "TRUE" : "FALSE"); - - fail_unless (answer == result); -} -END_TEST - - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_is_in_net = tcase_create ("is_in_net"); - suite_add_tcase (s, tc_is_in_net); - tcase_add_checked_fixture (tc_is_in_net, mock_setup_net, mock_teardown_net); - tcase_add_checked_fixture (tc_is_in_net, mock_setup_unspec, NULL); - tcase_add_loop_test (tc_is_in_net, test_is_in_net_pass_001, 0, G_N_ELEMENTS(cases_004)); - - TCase* tc_is_in_net6 = tcase_create ("is_in_net6"); - suite_add_tcase (s, tc_is_in_net6); - tcase_add_checked_fixture (tc_is_in_net6, mock_setup_net, mock_teardown_net); - tcase_add_checked_fixture (tc_is_in_net6, mock_setup_unspec, NULL); - tcase_add_loop_test (tc_is_in_net6, test_is_in_net6_pass_001, 0, G_N_ELEMENTS(cases_005)); - -/* three variations of all parse-transport tests, one for each valid - * address family value: AF_UNSPEC, AF_INET, AF_INET6. - */ - -/* unspecified address family, ai_family == AF_UNSPEC */ - TCase* tc_parse_transport_unspec = tcase_create ("parse_transport/unspec"); - suite_add_tcase (s, tc_parse_transport_unspec); - tcase_add_checked_fixture (tc_parse_transport_unspec, mock_setup_net, mock_teardown_net); - tcase_add_checked_fixture (tc_parse_transport_unspec, mock_setup_unspec, NULL); - tcase_add_loop_test (tc_parse_transport_unspec, test_parse_transport_pass_001, 0, G_N_ELEMENTS(cases_001)); - tcase_add_loop_test (tc_parse_transport_unspec, test_parse_transport_pass_002, 0, G_N_ELEMENTS(cases_002)); - tcase_add_loop_test (tc_parse_transport_unspec, test_parse_transport_pass_003, 0, G_N_ELEMENTS(cases_003)); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_pass_004); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_pass_005); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_001); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_002); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_003); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_004); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_005); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_006); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_007); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_008); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_009); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_010); - tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_011); - -/* IP version 4, ai_family = AF_INET */ - TCase* tc_parse_transport_ip4 = tcase_create ("parse_transport/af_inet"); - suite_add_tcase (s, tc_parse_transport_ip4); - tcase_add_checked_fixture (tc_parse_transport_ip4, mock_setup_net, mock_teardown_net); - tcase_add_checked_fixture (tc_parse_transport_ip4, mock_setup_ip4, NULL); - tcase_add_loop_test (tc_parse_transport_ip4, test_parse_transport_pass_001, 0, G_N_ELEMENTS(cases_001)); - tcase_add_loop_test (tc_parse_transport_ip4, test_parse_transport_pass_002, 0, G_N_ELEMENTS(cases_002)); - tcase_add_loop_test (tc_parse_transport_ip4, test_parse_transport_pass_003, 0, G_N_ELEMENTS(cases_003)); - tcase_add_test (tc_parse_transport_ip4, test_parse_transport_pass_004); - tcase_add_test (tc_parse_transport_ip4, test_parse_transport_pass_005); - -/* IP version 6, ai_family = AF_INET6 */ - TCase* tc_parse_transport_ip6 = tcase_create ("parse_transport/af_inet6"); - suite_add_tcase (s, tc_parse_transport_ip6); - tcase_add_checked_fixture (tc_parse_transport_ip6, mock_setup_net, mock_teardown_net); - tcase_add_checked_fixture (tc_parse_transport_ip6, mock_setup_ip6, NULL); - tcase_add_loop_test (tc_parse_transport_ip6, test_parse_transport_pass_001, 0, G_N_ELEMENTS(cases_001)); - tcase_add_loop_test (tc_parse_transport_ip6, test_parse_transport_pass_002, 0, G_N_ELEMENTS(cases_002)); - tcase_add_loop_test (tc_parse_transport_ip6, test_parse_transport_pass_003, 0, G_N_ELEMENTS(cases_003)); - tcase_add_test (tc_parse_transport_ip6, test_parse_transport_pass_004); - tcase_add_test (tc_parse_transport_ip6, test_parse_transport_pass_005); - - TCase* tc_print_all = tcase_create ("print-all"); - tcase_add_checked_fixture (tc_print_all, mock_setup_net, mock_teardown_net); - suite_add_tcase (s, tc_print_all); - tcase_add_test (tc_print_all, test_print_all_pass_001); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/checksum.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/checksum.h deleted file mode 100644 index 67f71a6..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/checksum.h +++ /dev/null @@ -1,75 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM checksum routines - * - * Copyright (c) 2006-2008 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_CHECKSUM_H__ -#define __PGM_IMPL_CHECKSUM_H__ - -#include - -PGM_BEGIN_DECLS - -uint16_t pgm_inet_checksum (const void*, uint16_t, uint16_t); -uint16_t pgm_csum_fold (uint32_t) PGM_GNUC_CONST; -uint32_t pgm_csum_block_add (uint32_t, uint32_t, const uint16_t) PGM_GNUC_CONST; -uint32_t pgm_compat_csum_partial (const void*, uint16_t, uint32_t); -uint32_t pgm_compat_csum_partial_copy (const void*restrict, void*restrict, uint16_t, uint32_t); - -static inline uint32_t add32_with_carry (uint32_t, uint32_t) PGM_GNUC_CONST; - -#if defined(__x86_64__) || defined(__i386__) || defined(__i386) || defined(__amd64) -static inline uint32_t add32_with_carry (uint32_t a, uint32_t b) -{ - asm("addl %2, %0 \n\t" - "adcl $0, %0" - : "=r" (a) /* output operands */ - : "0" (a), "r" (b)); /* input operands */ - return a; -} -#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv9) -static inline uint32_t add32_with_carry (uint32_t a, uint32_t b) -{ - asm("addcc %2, %0, %0 \n\t" - "addx %0, %%g0, %0" - : "=r" (a) /* output operands */ - : "0" (a), "r" (b) /* input operands */ - : "cc"); /* list of clobbered registers */ - return a; -} -#else -static inline uint32_t add32_with_carry (uint32_t a, uint32_t b) -{ - a += b; - a = (a >> 16) + (a & 0xffff); - return a; -} -#endif - -# define pgm_csum_partial pgm_compat_csum_partial -# define pgm_csum_partial_copy pgm_compat_csum_partial_copy - -PGM_END_DECLS - -#endif /* __PGM_IMPL_CHECKSUM_H__ */ - diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/engine.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/engine.h deleted file mode 100644 index eeacbe7..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/engine.h +++ /dev/null @@ -1,43 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM engine. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_ENGINE_H__ -#define __PGM_IMPL_ENGINE_H__ - -#ifdef _WIN32 -# include -# include -#endif -#include - -PGM_BEGIN_DECLS - -#ifdef _WIN32 -extern LPFN_WSARECVMSG pgm_WSARecvMsg; -#endif - -#ifdef PGM_DEBUG -extern unsigned pgm_loss_rate; -#endif - -PGM_END_DECLS - -#endif /* __PGM_IMPL_ENGINE_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/features.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/features.h deleted file mode 100644 index a8dadf7..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/features.h +++ /dev/null @@ -1,42 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Compiler feature flags. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_FEATURES_H__ -#define __PGM_IMPL_FEATURES_H__ - -#if defined(_POSIX_C_SOURCE) || defined(__POSIX_VISIBLE) -# if (_POSIX_C_SOURCE - 0) >= 200112L || (__POSIX_VISIBLE - 0) >= 200112L -# define CONFIG_HAVE_FTIME 1 -# define CONFIG_HAVE_GETTIMEOFDAY 1 -# endif -# if (_POSIX_C_SOURCE - 0) >= 199309L || (__POSIX_VISIBLE - 0) >= 199309L -# define CONFIG_HAVE_CLOCK_GETTIME 1 -# endif -#endif -#if defined(_WIN32) -# define CONFIG_HAVE_FTIME -#endif - -#endif /* __PGM_IMPL_FEATURES_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/fixed.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/fixed.h deleted file mode 100644 index f84ef33..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/fixed.h +++ /dev/null @@ -1,140 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * 8-bit and 16-bit shift fixed point math - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_FIXED_H__ -#define __PGM_IMPL_FIXED_H__ - -#include - -PGM_BEGIN_DECLS - -static inline uint_fast32_t pgm_fp8 (unsigned) PGM_GNUC_CONST; -static inline uint_fast32_t pgm_fp16 (unsigned) PGM_GNUC_CONST; -static inline unsigned pgm_fp8tou (uint_fast32_t) PGM_GNUC_CONST; -static inline unsigned pgm_fp16tou (uint_fast32_t) PGM_GNUC_CONST; -static inline uint_fast32_t pgm_fp8mul (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST; -static inline uint_fast32_t pgm_fp16mul (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST; -static inline uint_fast32_t pgm_fp8div (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST; -static inline uint_fast32_t pgm_fp16div (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST; -static inline uint_fast32_t pgm_fp16pow (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST; - -static inline -uint_fast32_t -pgm_fp8 ( - unsigned v - ) -{ - return (uint32_t)(v << 8); -} - -static inline -uint_fast32_t -pgm_fp16 ( - unsigned v - ) -{ - return (uint_fast32_t)(v << 16); -} - -static inline -unsigned -pgm_fp8tou ( - uint_fast32_t f - ) -{ - return (f + (1 << 7)) >> 8; -} - -static inline -unsigned -pgm_fp16tou ( - uint_fast32_t f - ) -{ - return (f + (1 << 15)) >> 16; -} - -static inline -uint_fast32_t -pgm_fp8mul ( - uint_fast32_t a, - uint_fast32_t b - ) -{ - return ( a * b + 128 ) >> 8; -} - -static inline -uint_fast32_t -pgm_fp16mul ( - uint_fast32_t a, - uint_fast32_t b - ) -{ - return ( a * b + 32768 ) >> 16; -} - -static inline -uint_fast32_t -pgm_fp8div ( - uint_fast32_t a, - uint_fast32_t b - ) -{ - return ( ( (a << 9) / b ) + 1 ) / 2; -} - -static inline -uint_fast32_t -pgm_fp16div ( - uint_fast32_t a, - uint_fast32_t b - ) -{ - return ( ( (a << 17) / b ) + 1 ) / 2; -} - -static inline -uint_fast32_t -pgm_fp16pow ( - uint_fast32_t x, - uint_fast32_t y - ) -{ - uint_fast32_t result = pgm_fp16 (1); - for (uint_fast32_t i = x; - y; - y >>= 1) - { - if (y & 1) - result = (result * i + 32768) >> 16; - i = (i * i + 32768) >> 16; - } - return result; -} - -PGM_END_DECLS - -#endif /* __PGM_IMPL_FIXED_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/framework.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/framework.h deleted file mode 100644 index 951ad26..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/framework.h +++ /dev/null @@ -1,76 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Framework collection. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_FRAMEWORK_H__ -#define __PGM_IMPL_FRAMEWORK_H__ - -#define __PGM_IMPL_FRAMEWORK_H_INSIDE__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef __PGM_IMPL_FRAMEWORK_H_INSIDE__ - -#endif /* __PGM_IMPL_FRAMEWORK_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/galois.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/galois.h deleted file mode 100644 index 2f008ed..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/galois.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Galois field maths. - * - * Copyright (c) 2006-2008 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_GALOIS_H__ -#define __PGM_IMPL_GALOIS_H__ - -#include - -PGM_BEGIN_DECLS - -/* 8 bit wide galois field integer: GF(2⁸) */ -typedef uint8_t __attribute__((__may_alias__)) pgm_gf8_t; - -/* E denotes the encoding symbol length in bytes. - * S denotes the symbol size in units of m-bit elements. When m = 8, - * then S and E are equal. - */ -#define PGM_GF_ELEMENT_BYTES sizeof(pgm_gf8_t) - -/* m defines the length of the elements in the finite field, in bits. - * m belongs to {2..16}. - */ -#define PGM_GF_ELEMENT_BITS ( 8 * PGM_GF_ELEMENT_BYTES ) - -/* q defines the number of elements in the finite field. - */ -#define PGM_GF_NO_ELEMENTS ( 1 << PGM_GF_ELEMENT_BITS ) -#define PGM_GF_MAX ( PGM_GF_NO_ELEMENTS - 1 ) - - -extern const pgm_gf8_t pgm_gflog[PGM_GF_NO_ELEMENTS]; -extern const pgm_gf8_t pgm_gfantilog[PGM_GF_NO_ELEMENTS]; - -#ifdef CONFIG_GALOIS_MUL_LUT -extern const pgm_gf8_t pgm_gftable[PGM_GF_NO_ELEMENTS * PGM_GF_NO_ELEMENTS]; -#endif - -/* In a finite field with characteristic 2, addition and subtraction are - * identical, and are accomplished using the XOR operator. - */ -static inline -pgm_gf8_t -pgm_gfadd ( - pgm_gf8_t a, - pgm_gf8_t b - ) -{ - return a ^ b; -} - -static inline -pgm_gf8_t -pgm_gfadd_equals ( - pgm_gf8_t a, - pgm_gf8_t b - ) -{ - return a ^= b; -} - -static inline -pgm_gf8_t -pgm_gfsub ( - pgm_gf8_t a, - pgm_gf8_t b - ) -{ - return pgm_gfadd (a, b); -} - -static inline -pgm_gf8_t -pgm_gfsub_equals ( - pgm_gf8_t a, - pgm_gf8_t b - ) -{ - return pgm_gfadd_equals (a, b); -} - -static inline -pgm_gf8_t -pgm_gfmul ( - pgm_gf8_t a, - pgm_gf8_t b - ) -{ - if (PGM_UNLIKELY( !(a && b) )) { - return 0; - } - -#ifdef CONFIG_GALOIS_MUL_LUT - return pgm_gftable[ (uint16_t)a << 8 | (uint16_t)b ]; -#else - unsigned sum = pgm_gflog[ a ] + pgm_gflog[ b ]; - return sum >= PGM_GF_MAX ? pgm_gfantilog[ sum - PGM_GF_MAX ] : pgm_gfantilog[ sum ]; -#endif -} - -static inline -pgm_gf8_t -pgm_gfdiv ( - pgm_gf8_t a, - pgm_gf8_t b - ) -{ - if (PGM_UNLIKELY( !a )) { - return 0; - } - - int sum = pgm_gflog[ a ] - pgm_gflog[ b ]; - return sum < 0 ? pgm_gfantilog[ sum + PGM_GF_MAX ] : pgm_gfantilog[ sum ]; -} - -PGM_END_DECLS - -#endif /* __PGM_IMPL_GALOIS_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/getifaddrs.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/getifaddrs.h deleted file mode 100644 index 4732a21..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/getifaddrs.h +++ /dev/null @@ -1,73 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable getifaddrs - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_GETIFADDRS_H__ -#define __PGM_IMPL_GETIFADDRS_H__ - -#ifndef _WIN32 -# include -# include -# include -#else -# include -#endif - -struct pgm_ifaddrs_t; - -#include -#include - -PGM_BEGIN_DECLS - -#ifndef IF_NAMESIZE -# ifdef IFNAMSIZ -# define IF_NAMESIZE IFNAMSIZ -# elif defined(_WIN32) -# define IF_NAMESIZE 40 -# else -# define IF_NAMESIZE 16 -# endif -#endif - -struct pgm_ifaddrs_t -{ - struct pgm_ifaddrs_t* ifa_next; /* Pointer to the next structure. */ - - char* ifa_name; /* Name of this network interface. */ - unsigned int ifa_flags; /* Flags as from SIOCGIFFLAGS ioctl. */ - -#ifdef ifa_addr -# undef ifa_addr -#endif - struct sockaddr* ifa_addr; /* Network address of this interface. */ - struct sockaddr* ifa_netmask; /* Netmask of this interface. */ -}; - -bool pgm_getifaddrs (struct pgm_ifaddrs_t**restrict, pgm_error_t**restrict); -void pgm_freeifaddrs (struct pgm_ifaddrs_t*); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_GETIFADDRS_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/getnodeaddr.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/getnodeaddr.h deleted file mode 100644 index befcf35..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/getnodeaddr.h +++ /dev/null @@ -1,41 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable function to return node IP address. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_GETNODEADDR_H__ -#define __PGM_IMPL_GETNODEADDR_H__ - -#ifndef _WIN32 -# include -#endif -#include -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL bool pgm_if_getnodeaddr (const sa_family_t, struct sockaddr*restrict, const socklen_t, pgm_error_t**restrict); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_GETNODEADDR_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/hashtable.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/hashtable.h deleted file mode 100644 index 4271cb6..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/hashtable.h +++ /dev/null @@ -1,58 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable hash table. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_HASHTABLE_H__ -#define __PGM_IMPL_HASHTABLE_H__ - -#include - -PGM_BEGIN_DECLS - -typedef struct pgm_hashtable_t pgm_hashtable_t; -typedef uint_fast32_t pgm_hash_t; - -typedef pgm_hash_t (*pgm_hashfunc_t) (const void*); -typedef bool (*pgm_equalfunc_t) (const void*restrict, const void*restrict); - -PGM_GNUC_INTERNAL pgm_hashtable_t* pgm_hashtable_new (pgm_hashfunc_t, pgm_equalfunc_t); -PGM_GNUC_INTERNAL void pgm_hashtable_destroy (pgm_hashtable_t*); -PGM_GNUC_INTERNAL void pgm_hashtable_insert (pgm_hashtable_t*restrict, const void*restrict, void*restrict); -PGM_GNUC_INTERNAL bool pgm_hashtable_remove (pgm_hashtable_t*restrict, const void*restrict); -PGM_GNUC_INTERNAL void pgm_hashtable_remove_all (pgm_hashtable_t*); -PGM_GNUC_INTERNAL void* pgm_hashtable_lookup (const pgm_hashtable_t*restrict, const void*restrict); -PGM_GNUC_INTERNAL void* pgm_hashtable_lookup_extended (const pgm_hashtable_t*restrict, const void*restrict, void*restrict); -PGM_GNUC_INTERNAL void pgm_hashtable_unref (pgm_hashtable_t*); - -/* Hash Functions - */ - -PGM_GNUC_INTERNAL bool pgm_str_equal (const void*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL pgm_hash_t pgm_str_hash (const void*) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_int_equal (const void*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL pgm_hash_t pgm_int_hash (const void*) PGM_GNUC_WARN_UNUSED_RESULT; - -PGM_END_DECLS - -#endif /* __PGM_IMPL_HASHTABLE_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/histogram.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/histogram.h deleted file mode 100644 index 92ddeb9..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/histogram.h +++ /dev/null @@ -1,129 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * histograms. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_HISTOGRAM_H__ -#define __PGM_IMPL_HISTOGRAM_H__ - -#include -#include -#include -#include - -PGM_BEGIN_DECLS - -typedef int pgm_sample_t; -typedef int pgm_count_t; - -struct pgm_sample_set_t { - pgm_count_t* counts; - unsigned counts_len; - int64_t sum; - int64_t square_sum; -}; - -typedef struct pgm_sample_set_t pgm_sample_set_t; - -struct pgm_histogram_t { - const char* restrict histogram_name; - unsigned bucket_count; - pgm_sample_t declared_min; - pgm_sample_t declared_max; - pgm_sample_t* restrict ranges; - pgm_sample_set_t sample; - bool is_registered; - pgm_slist_t histograms_link; -}; - -typedef struct pgm_histogram_t pgm_histogram_t; - -#define PGM_HISTOGRAM_DEFINE(name, minimum, maximum, count) \ - static pgm_count_t counts[ (count) ]; \ - static pgm_sample_t ranges[ (count) + 1 ]; \ - static pgm_histogram_t counter = { \ - .histogram_name = (name), \ - .bucket_count = (count), \ - .declared_min = (minimum), \ - .declared_max = (maximum), \ - .ranges = ranges, \ - .sample = { \ - .counts = counts, \ - .counts_len = (count), \ - .sum = 0, \ - .square_sum = 0 \ - }, \ - .is_registered = FALSE \ - } - -#ifdef CONFIG_HISTOGRAMS - -# define PGM_HISTOGRAM_TIMES(name, sample) do { \ - PGM_HISTOGRAM_DEFINE(name, pgm_msecs(1), pgm_secs(10), 50); \ - if (!counter.is_registered) { \ - memset (counts, 0, sizeof(counts)); \ - memset (ranges, 0, sizeof(ranges)); \ - pgm_histogram_init (&counter); \ - } \ - pgm_histogram_add_time (&counter, sample); \ - } while (0) - -# define PGM_HISTOGRAM_COUNTS(name, sample) do { \ - PGM_HISTOGRAM_DEFINE(name, 1, 1000000, 50); \ - if (!counter.is_registered) { \ - memset (counts, 0, sizeof(counts)); \ - memset (ranges, 0, sizeof(ranges)); \ - pgm_histogram_init (&counter); \ - } \ - pgm_histogram_add (&counter, (sample)); \ - } while (0) - -#else /* !CONFIG_HISTOGRAMS */ - -# define PGM_HISTOGRAM_TIMES(name, sample) -# define PGM_HISTOGRAM_COUNTS(name, sample) - -#endif /* !CONFIG_HISTOGRAMS */ - - -extern pgm_slist_t* pgm_histograms; - -void pgm_histogram_init (pgm_histogram_t*); -void pgm_histogram_add (pgm_histogram_t*, int); -void pgm_histogram_write_html_graph_all (pgm_string_t*); - -static inline -void -pgm_histogram_add_time ( - pgm_histogram_t*const histogram, - pgm_time_t sample_time - ) -{ - pgm_histogram_add (histogram, (int)pgm_to_msecs (sample_time)); -} - -PGM_END_DECLS - -#endif /* __PGM_IMPL_HISTOGRAM_H__ */ - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/i18n.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/i18n.h deleted file mode 100644 index c97f3de..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/i18n.h +++ /dev/null @@ -1,32 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * i18n & l10n support - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_I18N_H__ -#define __PGM_IMPL_I18N_H__ - -#ifdef CONFIG_HAVE_GETTEXT -# include -# define _(String) dgettext (GETTEXT_PACKAGE, String) -#else -# define _(String) (String) -#endif - -#endif /* __PGM_IMPL_I18N_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/indextoaddr.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/indextoaddr.h deleted file mode 100644 index 6c6599e..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/indextoaddr.h +++ /dev/null @@ -1,41 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable interface index to socket address function. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_INDEXTOADDR_H__ -#define __PGM_IMPL_INDEXTOADDR_H__ - -#ifndef _WIN32 -# include -#endif -#include -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL bool pgm_if_indextoaddr (unsigned, sa_family_t, uint32_t, struct sockaddr*restrict, pgm_error_t**restrict); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_INDEXTOADDR_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/indextoname.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/indextoname.h deleted file mode 100644 index d5d7964..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/indextoname.h +++ /dev/null @@ -1,37 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Windows interface index to interface name function. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_INDEXTONAME_H__ -#define __PGM_IMPL_INDEXTONAME_H__ - -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL char* pgm_if_indextoname (unsigned, char*); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_INDEXTONAME_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/inet_network.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/inet_network.h deleted file mode 100644 index 64c43fb..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/inet_network.h +++ /dev/null @@ -1,41 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable implementations of inet_network and inet_network6. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_INET_NETWORK_H__ -#define __PGM_IMPL_INET_NETWORK_H__ - -#ifndef _WIN32 -# include -#endif -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL int pgm_inet_network (const char*restrict, struct in_addr*restrict); -PGM_GNUC_INTERNAL int pgm_inet6_network (const char*restrict, struct in6_addr*restrict); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_INET_NETWORK_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/ip.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/ip.h deleted file mode 100644 index 8f18775..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/ip.h +++ /dev/null @@ -1,150 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Internet header for protocol version 4, RFC 791. - * - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Copyright (c) 1996-1999 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_IP_H__ -#define __PGM_IMPL_IP_H__ - -#ifndef _WIN32 -# include -#endif -#include -#include - -PGM_BEGIN_DECLS - -/* Byte alignment for packet memory maps. - * NB: Solaris and OpenSolaris don't support #pragma pack(push) even on x86. - */ -#if defined( __GNUC__ ) && !defined( sun ) -# pragma pack(push) -#endif -#pragma pack(1) - -/* RFC 791 */ - -/* nb: first four bytes are forced bitfields for win32 "feature" */ -struct pgm_ip -{ -#if (defined( sun ) && defined( _BIT_FIELDS_LTOH )) || (!defined( sun ) && __BYTE_ORDER == __LITTLE_ENDIAN) - unsigned ip_hl:4; /* header length */ - unsigned ip_v:4; /* version */ -#else - unsigned ip_v:4; /* version */ - unsigned ip_hl:4; /* header length */ -#endif - unsigned ip_tos:8; /* type of service */ - unsigned ip_len:16; /* total length */ - uint16_t ip_id; /* identification */ - uint16_t ip_off; /* fragment offset field */ - uint8_t ip_ttl; /* time to live */ - uint8_t ip_p; /* protocol */ - uint16_t ip_sum; /* checksum */ - struct in_addr ip_src, ip_dst; /* source and dest address */ -}; - -PGM_STATIC_ASSERT(sizeof(struct pgm_ip) == 20); - -/* RFC 2460 */ -#ifdef ip6_vfc -# undef ip6_vfc -#endif -#ifdef ip6_plen -# undef ip6_plen -#endif -#ifdef ip6_nxt -# undef ip6_nxt -#endif -#ifdef ip6_hops -# undef ip6_hops -#endif -struct pgm_ip6_hdr -{ - uint32_t ip6_vfc; /* version:4, traffic class:8, flow label:20 */ - uint16_t ip6_plen; /* payload length: packet length - 40 */ - uint8_t ip6_nxt; /* next header type */ - uint8_t ip6_hops; /* hop limit */ - struct in6_addr ip6_src, ip6_dst; /* source and dest address */ -}; - -PGM_STATIC_ASSERT(sizeof(struct pgm_ip6_hdr) == 40); - -#define PGM_IPOPT_EOL 0 /* end of option list */ -#define PGM_IPOPT_NOP 1 /* no operation */ -#define PGM_IPOPT_RR 7 /* record packet route */ -#define PGM_IPOPT_TS 68 /* timestamp */ -#define PGM_IPOPT_SECURITY 130 /* provide s, c, h, tcc */ -#define PGM_IPOPT_LSRR 131 /* loose source route */ -#define PGM_IPOPT_ESO 133 -#define PGM_IPOPT_CIPSO 134 -#define PGM_IPOPT_SATID 136 /* satnet id */ -#define PGM_IPOPT_SSRR 137 /* strict source route */ -#define PGM_IPOPT_RA 148 /* router alert */ - -/* RFC 768 */ -struct pgm_udphdr -{ - uint16_t uh_sport; /* source port */ - uint16_t uh_dport; /* destination port */ - uint16_t uh_ulen; /* udp length */ - uint16_t uh_sum; /* udp checksum */ -}; - -PGM_STATIC_ASSERT(sizeof(struct pgm_udphdr) == 8); - -#if defined( __GNUC__ ) && !defined( sun ) -# pragma pack(pop) -#else -# pragma pack() -#endif - -PGM_END_DECLS - -#endif /* __PGM_IMPL_IP_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/list.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/list.h deleted file mode 100644 index 91a3ed3..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/list.h +++ /dev/null @@ -1,43 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable doubly-linked list. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_LIST_H__ -#define __PGM_IMPL_LIST_H__ - -#include -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL pgm_list_t* pgm_list_append (pgm_list_t*restrict, void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL pgm_list_t* pgm_list_prepend_link (pgm_list_t*restrict, pgm_list_t*restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL pgm_list_t* pgm_list_remove_link (pgm_list_t*, pgm_list_t*) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL pgm_list_t* pgm_list_delete_link (pgm_list_t*, pgm_list_t*) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL pgm_list_t* pgm_list_last (pgm_list_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL unsigned pgm_list_length (pgm_list_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; - -PGM_END_DECLS - -#endif /* __PGM_IMPL_LIST_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/math.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/math.h deleted file mode 100644 index 8c7c2ba..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/math.h +++ /dev/null @@ -1,75 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Shared math routines. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_MATH_H__ -#define __PGM_IMPL_MATH_H__ - -#include - -PGM_BEGIN_DECLS - -/* fast log base 2 of power of 2 - */ - -static inline unsigned pgm_power2_log2 (unsigned) PGM_GNUC_CONST; - -static inline -unsigned -pgm_power2_log2 ( - unsigned v - ) -{ - static const unsigned int b[] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 }; - unsigned int r = (v & b[0]) != 0; - for (unsigned i = 4; i > 0; i--) { - r |= ((v & b[i]) != 0) << i; - } - return r; -} - -/* nearest power of 2 - */ - -static inline size_t pgm_nearest_power (size_t, size_t) PGM_GNUC_CONST; - -static inline -size_t -pgm_nearest_power ( - size_t b, - size_t v - ) -{ - if (v > (SIZE_MAX/2)) - return SIZE_MAX; - while (b < v) - b <<= 1; - return b; -} - -unsigned pgm_spaced_primes_closest (unsigned) PGM_GNUC_PURE; - -PGM_END_DECLS - -#endif /* __PGM_IMPL_MATH_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/md5.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/md5.h deleted file mode 100644 index b28ab7d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/md5.h +++ /dev/null @@ -1,61 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * MD5 hashing algorithm. - * - * MD5 original source GNU C Library: - * Includes functions to compute MD5 message digest of files or memory blocks - * according to the definition of MD5 in RFC 1321 from April 1992. - * - * Copyright (C) 1995, 1996, 2001, 2003 Free Software Foundation, Inc. - * - * This file is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this file; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_MD5_H__ -#define __PGM_IMPL_MD5_H__ - -struct pgm_md5_t; - -#include - -PGM_BEGIN_DECLS - -struct pgm_md5_t -{ - uint32_t A; - uint32_t B; - uint32_t C; - uint32_t D; - - uint32_t total[2]; - uint32_t buflen; - char buffer[128] -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) - __attribute__ ((__aligned__ (__alignof__ (uint32_t)))) -#endif - ; -}; - -PGM_GNUC_INTERNAL void pgm_md5_init_ctx (struct pgm_md5_t*); -PGM_GNUC_INTERNAL void pgm_md5_process_bytes (struct pgm_md5_t*restrict, const void*restrict, size_t); -PGM_GNUC_INTERNAL void* pgm_md5_finish_ctx (struct pgm_md5_t*, void*); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_MD5_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/mem.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/mem.h deleted file mode 100644 index 9377ced..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/mem.h +++ /dev/null @@ -1,34 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable fail fast memory allocation. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_MEM_H__ -#define __PGM_IMPL_MEM_H__ - -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL void pgm_mem_init (void); -PGM_GNUC_INTERNAL void pgm_mem_shutdown (void); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_MEM_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/messages.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/messages.h deleted file mode 100644 index e7065b0..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/messages.h +++ /dev/null @@ -1,352 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * basic message reporting. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_MESSAGES_H__ -#define __PGM_IMPL_MESSAGES_H__ - -#include -#include -#include -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL void pgm__log (const int, const char*, ...) PGM_GNUC_PRINTF (2, 3); -PGM_GNUC_INTERNAL void pgm__logv (const int, const char*, va_list) PGM_GNUC_PRINTF (2, 0); - -#ifdef CONFIG_HAVE_ISO_VARARGS - -/* debug trace level only valid in debug mode */ -# ifdef PGM_DEBUG -# define pgm_debug(...) \ - do { \ - if (pgm_min_log_level == PGM_LOG_LEVEL_DEBUG) \ - pgm__log (PGM_LOG_LEVEL_DEBUG, __VA_ARGS__); \ - } while (0) -# else -# define pgm_debug(...) while (0) -# endif /* !PGM_DEBUG */ - -# define pgm_trace(r,...) \ - do { \ - if (pgm_min_log_level <= PGM_LOG_LEVEL_TRACE && pgm_log_mask & (r)) \ - pgm__log (PGM_LOG_LEVEL_TRACE, __VA_ARGS__); \ - } while (0) -# define pgm_minor(...) \ - do { \ - if (pgm_min_log_level <= PGM_LOG_LEVEL_MINOR) \ - pgm__log (PGM_LOG_LEVEL_MINOR, __VA_ARGS__); \ - } while (0) -# define pgm_info(...) \ - do { \ - if (pgm_min_log_level <= PGM_LOG_LEVEL_NORMAL) \ - pgm__log (PGM_LOG_LEVEL_NORMAL, __VA_ARGS__); \ - } while (0) -# define pgm_warn(...) \ - do { \ - if (pgm_min_log_level <= PGM_LOG_LEVEL_WARNING) \ - pgm__log (PGM_LOG_LEVEL_WARNING, __VA_ARGS__); \ - } while (0) -# define pgm_error(...) \ - do { \ - if (pgm_min_log_level <= PGM_LOG_LEVEL_ERROR) \ - pgm__log (PGM_LOG_LEVEL_ERROR, __VA_ARGS__); \ - } while (0) -# define pgm_fatal(...) \ - do { \ - pgm__log (PGM_LOG_LEVEL_FATAL, __VA_ARGS__); \ - } while (0) - -#elif defined(CONFIG_HAVE_GNUC_VARARGS) - -# ifdef PGM_DEBUG -# define pgm_debug(f...) \ - do { \ - if (pgm_min_log_level == PGM_LOG_LEVEL_DEBUG) \ - pgm__log (PGM_LOG_LEVEL_DEBUG, f); \ - } while (0) -# else -# define pgm_debug(f...) while (0) -# endif /* !PGM_DEBUG */ - -# define pgm_trace(r,f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_TRACE && pgm_log_mask & (r)) \ - pgm__log (PGM_LOG_LEVEL_TRACE, f) -# define pgm_minor(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_MINOR) pgm__log (PGM_LOG_LEVEL_MINOR, f) -# define pgm_info(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_NORMAL) pgm__log (PGM_LOG_LEVEL_NORMAL, f) -# define pgm_warn(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_WARNING) pgm__log (PGM_LOG_LEVEL_WARNING, f) -# define pgm_error(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_ERROR) pgm__log (PGM_LOG_LEVEL_ERROR, f) -# define pgm_fatal(f...) pgm__log (PGM_LOG_LEVEL_FATAL, f) - -#else /* no varargs macros */ - -/* declare for GCC attributes */ -static inline void pgm_debug (const char*, ...) PGM_GNUC_PRINTF (1, 2); -static inline void pgm_trace (const int, const char*, ...) PGM_GNUC_PRINTF (2, 3); -static inline void pgm_minor (const char*, ...) PGM_GNUC_PRINTF (1, 2); -static inline void pgm_info (const char*, ...) PGM_GNUC_PRINTF (1, 2); -static inline void pgm_warn (const char*, ...) PGM_GNUC_PRINTF (1, 2); -static inline void pgm_error (const char*, ...) PGM_GNUC_PRINTF (1, 2); -static inline void pgm_fatal (const char*, ...) PGM_GNUC_PRINTF (1, 2); - -static inline void pgm_debug (const char* format, ...) { - if (PGM_LOG_LEVEL_DEBUG == pgm_min_log_level) { - va_list args; - va_start (args, format); - pgm__logv (PGM_LOG_LEVEL_DEBUG, format, args); - va_end (args); - } -} - -static inline void pgm_trace (const int role, const char* format, ...) { - if (PGM_LOG_LEVEL_TRACE >= pgm_min_log_level && pgm_log_mask & role) { - va_list args; - va_start (args, format); - pgm__logv (PGM_LOG_LEVEL_TRACE, format, args); - va_end (args); - } -} - -static inline void pgm_minor (const char* format, ...) { - if (PGM_LOG_LEVEL_MINOR >= pgm_min_log_level) { - va_list args; - va_start (args, format); - pgm__logv (PGM_LOG_LEVEL_MINOR, format, args); - va_end (args); - } -} - -static inline void pgm_info (const char* format, ...) { - if (PGM_LOG_LEVEL_NORMAL >= pgm_min_log_level) { - va_list args; - va_start (args, format); - pgm__logv (PGM_LOG_LEVEL_NORMAL, format, args); - va_end (args); - } -} - -static inline void pgm_warn (const char* format, ...) { - if (PGM_LOG_LEVEL_WARNING >= pgm_min_log_level) { - va_list args; - va_start (args, format); - pgm__logv (PGM_LOG_LEVEL_WARNING, format, args); - va_end (args); - } -} - -static inline void pgm_error (const char* format, ...) { - if (PGM_LOG_LEVEL_ERROR >= pgm_min_log_level) { - va_list args; - va_start (args, format); - pgm__logv (PGM_LOG_LEVEL_WARNING, format, args); - va_end (args); - } -} - -static inline void pgm_fatal (const char* format, ...) { - va_list args; - va_start (args, format); - pgm__logv (PGM_LOG_LEVEL_FATAL, format, args); - va_end (args); -} - -#endif /* varargs */ - -#define pgm_warn_if_reached() \ - do { \ - pgm_warn ("file %s: line %d (%s): code should not be reached", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - } while (0) -#define pgm_warn_if_fail(expr) \ - do { \ - if (PGM_LIKELY (expr)); \ - else \ - pgm_warn ("file %s: line %d (%s): runtime check failed: (%s)", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \ - } while (0) - - -#ifdef PGM_DISABLE_ASSERT - -# define pgm_assert(expr) while (0) -# define pgm_assert_not_reached() while (0) -# define pgm_assert_cmpint(n1, cmp, n2) while (0) -# define pgm_assert_cmpuint(n1, cmp, n2) while (0) - -#elif defined(__GNUC__) - -# define pgm_assert(expr) \ - do { \ - if (PGM_LIKELY(expr)); \ - else { \ - pgm_fatal ("file %s: line %d (%s): assertion failed: (%s)", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \ - abort (); \ - } \ - } while (0) -# define pgm_assert_not_reached() \ - do { \ - pgm_fatal ("file %s: line %d (%s): should not be reached", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - abort (); \ - } while (0) -# define pgm_assert_cmpint(n1, cmp, n2) \ - do { \ - const int _n1 = (n1), _n2 = (n2); \ - if (PGM_LIKELY(_n1 cmp _n2)); \ - else { \ - pgm_fatal ("file %s: line %d (%s): assertion failed (%s): (%u %s %u)", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \ - abort (); \ - } \ - } while (0) -# define pgm_assert_cmpuint(n1, cmp, n2) \ - do { \ - const unsigned _n1 = (n1), _n2 = (n2); \ - if (PGM_LIKELY(_n1 cmp _n2)); \ - else { \ - pgm_fatal ("file %s: line %d (%s): assertion failed (%s): (%u %s %u)", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \ - abort (); \ - } \ - } while (0) - -#else - -# define pgm_assert(expr) \ - do { \ - if (PGM_LIKELY(expr)); \ - else { \ - pgm_fatal ("file %s: line %d: assertion failed: (%s)", \ - __FILE__, __LINE__, #expr); \ - abort (); \ - } \ - } while (0) -# define pgm_assert_not_reached() \ - do { \ - pgm_fatal ("file %s: line %d: assertion failed: (%s)", \ - __FILE__, __LINE__); \ - abort (); \ - } while (0) -# define pgm_assert_cmpint(n1, cmp, n2) \ - do { \ - const int _n1 = (n1), _n2 = (n2); \ - if (PGM_LIKELY(_n1 cmp _n2)); \ - else { \ - pgm_fatal ("file %s: line %d: assertion failed (%s): (%u %s %u)", \ - __FILE__, __LINE__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \ - abort (); \ - } \ - } while (0) -# define pgm_assert_cmpuint(n1, cmp, n2) \ - do { \ - const unsigned _n1 = (n1), _n2 = (n2); \ - if (PGM_LIKELY(_n1 cmp _n2)); \ - else { \ - pgm_fatal ("file %s: line %d: assertion failed (%s): (%u %s %u)", \ - __FILE__, __LINE__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \ - abort (); \ - } \ - } while (0) - -#endif /* !PGM_DISABLE_ASSERT */ - -#ifdef PGM_DISABLE_CHECKS - -# define pgm_return_if_fail(expr) while (0) -# define pgm_return_val_if_fail(expr, val) while (0) -# define pgm_return_if_reached() return -# define pgm_return_val_if_reached(val) return (val) - -#elif defined(__GNUC__) - -# define pgm_return_if_fail(expr) \ - do { \ - if (PGM_LIKELY(expr)); \ - else { \ - pgm_warn ("file %s: line %d (%s): assertion `%s' failed", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \ - return; \ - } \ - } while (0) -# define pgm_return_val_if_fail(expr, val) \ - do { \ - if (PGM_LIKELY(expr)); \ - else { \ - pgm_warn ("file %s: line %d (%s): assertion `%s' failed", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \ - return (val); \ - } \ - } while (0) -# define pgm_return_if_reached() \ - do { \ - pgm_warn ("file %s: line %d (%s): should not be reached", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - return; \ - } while (0) -# define pgm_return_val_if_reached(val) \ - do { \ - pgm_warn ("file %s: line %d (%s): should not be reached", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - return (val); \ - } while (0) - -#else - -# define pgm_return_if_fail(expr) \ - do { \ - if (PGM_LIKELY(expr)); \ - else { \ - pgm_warn ("file %s: line %d: assertion `%s' failed", \ - __FILE__, __LINE__, #expr); \ - return; \ - } \ - } while (0) -# define pgm_return_val_if_fail(expr, val) \ - do { \ - if (PGM_LIKELY(expr)); \ - else { \ - pgm_warn ("file %s: line %d: assertion `%s' failed", \ - __FILE__, __LINE__, #expr); \ - return (val); \ - } \ - } while (0) -# define pgm_return_if_reached() \ - do { \ - pgm_warn ("file %s: line %d): should not be reached", \ - __FILE__, __LINE__); \ - return; \ - } while (0) -# define pgm_return_val_if_reached(val) \ - do { \ - pgm_warn ("file %s: line %d: should not be reached", \ - __FILE__, __LINE__); \ - return (val); \ - } while (0) - -#endif /* !PGM_DISABLE_CHECKS */ - -PGM_END_DECLS - -#endif /* __PGM_IMPL_MESSAGES_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/nametoindex.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/nametoindex.h deleted file mode 100644 index a25bd89..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/nametoindex.h +++ /dev/null @@ -1,40 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Windows interface name to interface index function. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_NAMETOINDEX_H__ -#define __PGM_IMPL_NAMETOINDEX_H__ - -#ifndef _WIN32 -# include -#endif -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL unsigned pgm_if_nametoindex (const sa_family_t, const char*); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_NAMETOINDEX_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/net.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/net.h deleted file mode 100644 index aa9beaf..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/net.h +++ /dev/null @@ -1,38 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * network send wrapper. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_NET_H__ -#define __PGM_IMPL_NET_H__ - -#ifndef _WIN32 -# include -#endif -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL ssize_t pgm_sendto (pgm_sock_t*restrict, bool, bool, const void*restrict, size_t, const struct sockaddr*restrict, socklen_t); -PGM_GNUC_INTERNAL int pgm_set_nonblocking (int fd[2]); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_NET_H__ */ - diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/notify.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/notify.h deleted file mode 100644 index 1db4475..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/notify.h +++ /dev/null @@ -1,298 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Low kernel overhead event notify mechanism, or standard pipes. - * - * Copyright (c) 2008 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_NOTIFY_H__ -#define __PGM_IMPL_NOTIFY_H__ - -typedef struct pgm_notify_t pgm_notify_t; - -#ifndef _WIN32 -# include -# include -# ifdef CONFIG_HAVE_EVENTFD -# include -# endif -#else /* _WIN32 */ -# include -# include -#endif -#include -#include - -PGM_BEGIN_DECLS - -struct pgm_notify_t { -#if defined(CONFIG_HAVE_EVENTFD) - int eventfd; -#elif !defined(_WIN32) - int pipefd[2]; -#else - SOCKET s[2]; -#endif /* _WIN32 */ -}; - -#if defined(CONFIG_HAVE_EVENTFD) -# define PGM_NOTIFY_INIT { -1 } -#elif !defined(_WIN32) -# define PGM_NOTIFY_INIT { { -1, -1 } } -#else -# define PGM_NOTIFY_INIT { { INVALID_SOCKET, INVALID_SOCKET } } -#endif - - -static inline -bool -pgm_notify_is_valid ( - pgm_notify_t* notify - ) -{ - if (PGM_UNLIKELY(NULL == notify)) - return FALSE; -#if defined(CONFIG_HAVE_EVENTFD) - if (PGM_UNLIKELY(-1 == notify->eventfd)) - return FALSE; -#elif !defined(_WIN32) - if (PGM_UNLIKELY(-1 == notify->pipefd[0] || -1 == notify->pipefd[1])) - return FALSE; -#else - if (PGM_UNLIKELY(INVALID_SOCKET == notify->s[0] || INVALID_SOCKET == notify->s[1])) - return FALSE; -#endif /* _WIN32 */ - return TRUE; -} - -static inline -int -pgm_notify_init ( - pgm_notify_t* notify - ) -{ - pgm_assert (NULL != notify); - -#if defined(CONFIG_HAVE_EVENTFD) - notify->eventfd = -1; - int retval = eventfd (0, 0); - if (-1 == retval) - return retval; - notify->eventfd = retval; - const int fd_flags = fcntl (notify->eventfd, F_GETFL); - if (-1 != fd_flags) - retval = fcntl (notify->eventfd, F_SETFL, fd_flags | O_NONBLOCK); - return 0; -#elif !defined(_WIN32) - notify->pipefd[0] = notify->pipefd[1] = -1; - int retval = pipe (notify->pipefd); - pgm_assert (0 == retval); -/* set non-blocking */ -/* write-end */ - int fd_flags = fcntl (notify->pipefd[1], F_GETFL); - if (fd_flags != -1) - retval = fcntl (notify->pipefd[1], F_SETFL, fd_flags | O_NONBLOCK); - pgm_assert (notify->pipefd[1]); -/* read-end */ - fd_flags = fcntl (notify->pipefd[0], F_GETFL); - if (fd_flags != -1) - retval = fcntl (notify->pipefd[0], F_SETFL, fd_flags | O_NONBLOCK); - pgm_assert (notify->pipefd[0]); - return retval; -#else -/* use loopback sockets to simulate a pipe suitable for win32/select() */ - struct sockaddr_in addr; - SOCKET listener; - int addrlen = sizeof (addr); - - notify->s[0] = notify->s[1] = INVALID_SOCKET; - - listener = socket (AF_INET, SOCK_STREAM, 0); - pgm_assert (listener != INVALID_SOCKET); - - memset (&addr, 0, sizeof (addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr ("127.0.0.1"); - pgm_assert (addr.sin_addr.s_addr != INADDR_NONE); - - int rc = bind (listener, (const struct sockaddr*)&addr, sizeof (addr)); - pgm_assert (rc != SOCKET_ERROR); - - rc = getsockname (listener, (struct sockaddr*)&addr, &addrlen); - pgm_assert (rc != SOCKET_ERROR); - -// Listen for incoming connections. - rc = listen (listener, 1); - pgm_assert (rc != SOCKET_ERROR); - -// Create the socket. - notify->s[1] = WSASocket (AF_INET, SOCK_STREAM, 0, NULL, 0, 0); - pgm_assert (notify->s[1] != INVALID_SOCKET); - -// Connect to the remote peer. - rc = connect (notify->s[1], (struct sockaddr*)&addr, addrlen); - pgm_assert (rc != SOCKET_ERROR); - -// Accept connection. - notify->s[0] = accept (listener, NULL, NULL); - pgm_assert (notify->s[0] != INVALID_SOCKET); - -// Set read-end to non-blocking mode - const unsigned long one = 1; - rc = ioctlsocket (notify->s[0], FIONBIO, &one); - pgm_assert (rc != SOCKET_ERROR); - -// We don't need the listening socket anymore. Close it. - rc = closesocket (listener); - pgm_assert (rc != SOCKET_ERROR); - - return 0; -#endif -} - -static inline -int -pgm_notify_destroy ( - pgm_notify_t* notify - ) -{ - pgm_assert (NULL != notify); - -#if defined(CONFIG_HAVE_EVENTFD) - if (-1 != notify->eventfd) { - close (notify->eventfd); - notify->eventfd = -1; - } -#elif !defined(_WIN32) - if (-1 != notify->pipefd[0]) { - close (notify->pipefd[0]); - notify->pipefd[0] = -1; - } - if (-1 != notify->pipefd[1]) { - close (notify->pipefd[1]); - notify->pipefd[1] = -1; - } -#else - if (INVALID_SOCKET != notify->s[0]) { - closesocket (notify->s[0]); - notify->s[0] = INVALID_SOCKET; - } - if (INVALID_SOCKET != notify->s[1]) { - closesocket (notify->s[1]); - notify->s[1] = INVALID_SOCKET; - } -#endif - return 0; -} - -static inline -int -pgm_notify_send ( - pgm_notify_t* notify - ) -{ - pgm_assert (NULL != notify); - -#if defined(CONFIG_HAVE_EVENTFD) - pgm_assert (-1 != notify->eventfd); - uint64_t u = 1; - ssize_t s = write (notify->eventfd, &u, sizeof(u)); - return (s == sizeof(u)); -#elif !defined(_WIN32) - pgm_assert (-1 != notify->pipefd[1]); - const char one = '1'; - return (1 == write (notify->pipefd[1], &one, sizeof(one))); -#else - pgm_assert (INVALID_SOCKET != notify->s[1]); - const char one = '1'; - return (1 == send (notify->s[1], &one, sizeof(one), 0)); -#endif -} - -static inline -int -pgm_notify_read ( - pgm_notify_t* notify - ) -{ - pgm_assert (NULL != notify); - -#if defined(CONFIG_HAVE_EVENTFD) - pgm_assert (-1 != notify->eventfd); - uint64_t u; - return (sizeof(u) == read (notify->eventfd, &u, sizeof(u))); -#elif !defined(_WIN32) - pgm_assert (-1 != notify->pipefd[0]); - char buf; - return (sizeof(buf) == read (notify->pipefd[0], &buf, sizeof(buf))); -#else - pgm_assert (INVALID_SOCKET != notify->s[0]); - char buf; - return (sizeof(buf) == recv (notify->s[0], &buf, sizeof(buf), 0)); -#endif -} - -static inline -void -pgm_notify_clear ( - pgm_notify_t* notify - ) -{ - pgm_assert (NULL != notify); - -#if defined(CONFIG_HAVE_EVENTFD) - pgm_assert (-1 != notify->eventfd); - uint64_t u; - while (sizeof(u) == read (notify->eventfd, &u, sizeof(u))); -#elif !defined(_WIN32) - pgm_assert (-1 != notify->pipefd[0]); - char buf; - while (sizeof(buf) == read (notify->pipefd[0], &buf, sizeof(buf))); -#else - pgm_assert (INVALID_SOCKET != notify->s[0]); - char buf; - while (sizeof(buf) == recv (notify->s[0], &buf, sizeof(buf), 0)); -#endif -} - -static inline -int -pgm_notify_get_fd ( - pgm_notify_t* notify - ) -{ - pgm_assert (NULL != notify); - -#if defined(CONFIG_HAVE_EVENTFD) - pgm_assert (-1 != notify->eventfd); - return notify->eventfd; -#elif !defined(_WIN32) - pgm_assert (-1 != notify->pipefd[0]); - return notify->pipefd[0]; -#else - pgm_assert (INVALID_SOCKET != notify->s[0]); - return notify->s[0]; -#endif -} - -PGM_END_DECLS - -#endif /* __PGM_IMPL_NOTIFY_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/packet_parse.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/packet_parse.h deleted file mode 100644 index 4416e21..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/packet_parse.h +++ /dev/null @@ -1,45 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM packet formats, RFC 3208. - * - * Copyright (c) 2006 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_PACKET_PARSE_H__ -#define __PGM_IMPL_PACKET_PARSE_H__ - -#ifndef _WIN32 -# include -#endif -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL bool pgm_parse_raw (struct pgm_sk_buff_t*const restrict, struct sockaddr*const restrict, pgm_error_t**restrict); -PGM_GNUC_INTERNAL bool pgm_parse_udp_encap (struct pgm_sk_buff_t*const restrict, pgm_error_t**restrict); -PGM_GNUC_INTERNAL bool pgm_verify_spm (const struct pgm_sk_buff_t* const); -PGM_GNUC_INTERNAL bool pgm_verify_spmr (const struct pgm_sk_buff_t* const); -PGM_GNUC_INTERNAL bool pgm_verify_nak (const struct pgm_sk_buff_t* const); -PGM_GNUC_INTERNAL bool pgm_verify_nnak (const struct pgm_sk_buff_t* const); -PGM_GNUC_INTERNAL bool pgm_verify_ncf (const struct pgm_sk_buff_t* const); -PGM_GNUC_INTERNAL bool pgm_verify_poll (const struct pgm_sk_buff_t* const); -PGM_GNUC_INTERNAL bool pgm_verify_polr (const struct pgm_sk_buff_t* const); -PGM_GNUC_INTERNAL bool pgm_verify_ack (const struct pgm_sk_buff_t* const); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_PACKET_PARSE_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/packet_test.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/packet_test.h deleted file mode 100644 index 1b39006..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/packet_test.h +++ /dev/null @@ -1,40 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM packet formats, RFC 3208. - * - * Copyright (c) 2006 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_PACKET_TEST_H__ -#define __PGM_IMPL_PACKET_TEST_H__ - -#ifndef _WIN32 -# include -#endif -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL bool pgm_print_packet (const void*, size_t); -PGM_GNUC_INTERNAL const char* pgm_type_string (uint8_t) PGM_GNUC_WARN_UNUSED_RESULT PGM_GNUC_CONST; -PGM_GNUC_INTERNAL const char* pgm_udpport_string (uint16_t) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL const char* pgm_gethostbyaddr (const struct in_addr*) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_ipopt_print (const void*, size_t); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_PACKET_TEST_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB.h deleted file mode 100644 index 6f80271..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Note: this file originally auto-generated by mib2c using - * : mib2c.notify.conf,v 5.3 2004/04/15 12:29:19 dts12 Exp $ - */ - -#ifndef __PGM_IMPL_MIB_H__ -#define __PGM_IMPL_MIB_H__ - -#include - -PGM_BEGIN_DECLS - -/* function declarations */ -PGM_GNUC_INTERNAL bool pgm_mib_init (pgm_error_t**); - -PGM_GNUC_INTERNAL int send_pgmStart_trap(void); -PGM_GNUC_INTERNAL int send_pgmStop_trap(void); -PGM_GNUC_INTERNAL int send_pgmNewSourceTrap_trap(void); -PGM_GNUC_INTERNAL int send_pgmClosedSourceTrap_trap(void); -PGM_GNUC_INTERNAL int send_pgmNewReceiverTrap_trap(void); -PGM_GNUC_INTERNAL int send_pgmClosedReceiverTrap_trap(void); -PGM_GNUC_INTERNAL int send_pgmNakFailuresTrap_trap(void); -PGM_GNUC_INTERNAL int send_pgmNewDlrSourceTrap_trap(void); -PGM_GNUC_INTERNAL int send_pgmClosedDlrSourceTrap_trap(void); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_MIB_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB_columns.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB_columns.h deleted file mode 100644 index 545e519..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB_columns.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Note: this file originally auto-generated by mib2c using - * : mib2c.column_defines.conf,v 5.1 2002/05/08 05:42:47 hardaker Exp $ - */ -#ifndef PGMMIB_COLUMNS_H -#define PGMMIB_COLUMNS_H - -/* column number definitions for table pgmNeIfConfigTable */ - #define COLUMN_PGMNEIFCONFIGINDEX 1 - #define COLUMN_PGMNEIFPGMENABLE 2 - #define COLUMN_PGMNEIFNAKRPTINTERVAL 3 - #define COLUMN_PGMNEIFNAKRPTRATE 4 - #define COLUMN_PGMNEIFNAKRDATAINTERVAL 5 - #define COLUMN_PGMNEIFNAKELIMINATEINTERVAL 6 - -/* column number definitions for table pgmNeIfPerformanceTable */ - #define COLUMN_PGMNEIFPERFORMANCEINDEX 1 - #define COLUMN_PGMNEIFREXMITSTATES 2 - #define COLUMN_PGMNEIFREXMITTIMEDOUT 3 - #define COLUMN_PGMNEIFINSPMS 4 - #define COLUMN_PGMNEIFOUTSPMS 5 - #define COLUMN_PGMNEIFINPARITYSPMS 6 - #define COLUMN_PGMNEIFOUTPARITYSPMS 7 - #define COLUMN_PGMNEIFINRDATA 8 - #define COLUMN_PGMNEIFOUTRDATA 9 - #define COLUMN_PGMNEIFINPARITYRDATA 10 - #define COLUMN_PGMNEIFOUTPARITYRDATA 11 - #define COLUMN_PGMNEIFINRDATANOSESSIONERRORS 12 - #define COLUMN_PGMNEIFUNIQUENAKS 13 - #define COLUMN_PGMNEIFINNAKS 14 - #define COLUMN_PGMNEIFOUTNAKS 15 - #define COLUMN_PGMNEIFUNIQUEPARITYNAKS 16 - #define COLUMN_PGMNEIFINPARITYNAKS 17 - #define COLUMN_PGMNEIFOUTPARITYNAKS 18 - #define COLUMN_PGMNEIFINNAKNOSESSIONERRORS 19 - #define COLUMN_PGMNEIFINNAKSEQERRORS 20 - #define COLUMN_PGMNEIFINPARITYNAKTGERRORS 21 - #define COLUMN_PGMNEIFINNNAKS 22 - #define COLUMN_PGMNEIFOUTNNAKS 23 - #define COLUMN_PGMNEIFINPARITYNNAKS 24 - #define COLUMN_PGMNEIFOUTPARITYNNAKS 25 - #define COLUMN_PGMNEIFINNNAKNOSESSIONERRORS 26 - #define COLUMN_PGMNEIFINNCFS 27 - #define COLUMN_PGMNEIFOUTNCFS 28 - #define COLUMN_PGMNEIFINPARITYNCFS 29 - #define COLUMN_PGMNEIFOUTPARITYNCFS 30 - #define COLUMN_PGMNEIFINNCFNOSESSIONERRORS 31 - #define COLUMN_PGMNEIFINREDIRECTNCFS 32 - #define COLUMN_PGMNEIFMALFORMED 33 - #define COLUMN_PGMNEIFSPMFROMSOURCE 34 - #define COLUMN_PGMNEIFSPMBADSQN 35 - #define COLUMN_PGMNEIFSPMERROR 36 - #define COLUMN_PGMNEIFPOLLRANDOMIGNORE 37 - #define COLUMN_PGMNEIFPOLLTSISTATEERROR 38 - #define COLUMN_PGMNEIFPOLLPARENTERROR 39 - #define COLUMN_PGMNEIFPOLLTYPEERROR 40 - #define COLUMN_PGMNEIFPOLLERROR 41 - #define COLUMN_PGMNEIFPOLLSUCCESS 42 - #define COLUMN_PGMNEIFPOLLORIGINATED 43 - #define COLUMN_PGMNEIFPOLRNOSTATE 44 - #define COLUMN_PGMNEIFPOLRERROR 45 - #define COLUMN_PGMNEIFPOLRPARITYERROR 46 - #define COLUMN_PGMNEIFPOLRSUCCESS 47 - #define COLUMN_PGMNEIFPOLRORIGINATED 48 - #define COLUMN_PGMNEIFNCFERROR 49 - #define COLUMN_PGMNEIFNCFPARITYERROR 50 - #define COLUMN_PGMNEIFNCFPARTIALPARITY 51 - #define COLUMN_PGMNEIFNCFRECEIVED 52 - #define COLUMN_PGMNEIFNCFANTICIPATED 53 - #define COLUMN_PGMNEIFNCFREDIRECTING 54 - #define COLUMN_PGMNEIFNAKELIMINATED 55 - #define COLUMN_PGMNEIFNAKERROR 56 - #define COLUMN_PGMNEIFNAKPARITYERROR 57 - #define COLUMN_PGMNEIFNNAKELIMINATED 58 - #define COLUMN_PGMNEIFNNAKERROR 59 - #define COLUMN_PGMNEIFNNAKPARITYERROR 60 - #define COLUMN_PGMNEIFNNAKCONGESTIONREPORTS 61 - #define COLUMN_PGMNEIFNAKRETRYEXPIRED 62 - #define COLUMN_PGMNEIFNAKRETRYEXPIREDDLR 63 - #define COLUMN_PGMNEIFNAKFORWARDEDDLR 64 - #define COLUMN_PGMNEIFNAKRETRANSMITTED 65 - #define COLUMN_PGMNEIFRDATAELIMINATEDOIF 66 - #define COLUMN_PGMNEIFRDATAELIMINATEDSQN 67 - #define COLUMN_PGMNEIFINRDATAFRAGMENTS 68 - #define COLUMN_PGMNEIFRDATAFRAGMENTSNOSESSIONERRORS 69 - #define COLUMN_PGMNEIFRDATAFRAGMENTSELIMINATEDOIF 70 - #define COLUMN_PGMNEIFRDATAFRAGMENTSELIMINATEDSQN 71 - #define COLUMN_PGMNEIFOUTRDATAFRAGMENTS 72 - -/* column number definitions for table pgmNeTsiTable */ - #define COLUMN_PGMNETSIGLOBALID 1 - #define COLUMN_PGMNETSIDATASOURCEPORT 2 - #define COLUMN_PGMNETSISTATEBITS 3 - #define COLUMN_PGMNETSIDATADESTINATIONPORT 4 - #define COLUMN_PGMNETSISOURCEADDRESS 5 - #define COLUMN_PGMNETSIGROUPADDRESS 6 - #define COLUMN_PGMNETSIUPSTREAMADDRESS 7 - #define COLUMN_PGMNETSIUPSTREAMIFINDEX 8 - #define COLUMN_PGMNETSIDLRADDRESS 9 - -/* column number definitions for table pgmNeTsiPerformanceTable */ - #define COLUMN_PGMNETSIPERFORMANCEGLOBALID 1 - #define COLUMN_PGMNETSIPERFORMANCEDATASOURCEPORT 2 - #define COLUMN_PGMNETSISESSIONTRAILEDGESEQ 3 - #define COLUMN_PGMNETSISESSIONINCRSEQ 4 - #define COLUMN_PGMNETSILEADEDGESEQ 5 - #define COLUMN_PGMNETSIINSPMS 6 - #define COLUMN_PGMNETSIOUTSPMS 7 - #define COLUMN_PGMNETSIINPARITYSPMS 8 - #define COLUMN_PGMNETSIOUTPARITYSPMS 9 - #define COLUMN_PGMNETSITOTALREXMITSTATES 10 - #define COLUMN_PGMNETSITOTALREXMITTIMEDOUT 11 - #define COLUMN_PGMNETSIINRDATA 12 - #define COLUMN_PGMNETSIOUTRDATA 13 - #define COLUMN_PGMNETSIINPARITYRDATA 14 - #define COLUMN_PGMNETSIOUTPARITYRDATA 15 - #define COLUMN_PGMNETSIINRDATANOSTATEERRORS 16 - #define COLUMN_PGMNETSIUNIQUENAKS 17 - #define COLUMN_PGMNETSIINNAKS 18 - #define COLUMN_PGMNETSIOUTNAKS 19 - #define COLUMN_PGMNETSIUNIQUEPARITYNAKS 20 - #define COLUMN_PGMNETSIINPARITYNAKS 21 - #define COLUMN_PGMNETSIOUTPARITYNAKS 22 - #define COLUMN_PGMNETSIINNAKSEQERRORS 23 - #define COLUMN_PGMNETSIINNNAKS 24 - #define COLUMN_PGMNETSIOUTNNAKS 25 - #define COLUMN_PGMNETSIINPARITYNNAKS 26 - #define COLUMN_PGMNETSIOUTPARITYNNAKS 27 - #define COLUMN_PGMNETSIINNCFS 28 - #define COLUMN_PGMNETSIOUTNCFS 29 - #define COLUMN_PGMNETSIINPARITYNCFS 30 - #define COLUMN_PGMNETSIOUTPARITYNCFS 31 - #define COLUMN_PGMNETSISPMSEQUENCENUMBER 32 - #define COLUMN_PGMNETSITRANSMISSIONGROUPSIZE 33 - #define COLUMN_PGMNETSITIMEOUT 34 - #define COLUMN_PGMNETSILASTTTL 35 - #define COLUMN_PGMNETSILINKLOSSRATE 36 - #define COLUMN_PGMNETSIPATHLOSSRATE 37 - #define COLUMN_PGMNETSIRECEIVERLOSSRATE 38 - #define COLUMN_PGMNETSICONGESTIONREPORTLEAD 39 - #define COLUMN_PGMNETSICONGESTIONREPORTWORSTRECEIVER 40 - -/* column number definitions for table pgmNeTsiRtxTable */ - #define COLUMN_PGMNETSIRTXSEQUENCENUMBER 1 - #define COLUMN_PGMNETSIRTXSEQUENCENUMBERTYPE 2 - #define COLUMN_PGMNETSIRTXREQPARITYTGCOUNT 4 - #define COLUMN_PGMNETSIRTXTIMEOUT 5 - #define COLUMN_PGMNETSIRTXSTATEBITS 6 - -/* column number definitions for table pgmNeTsiRtxIfTable */ - #define COLUMN_PGMNETSIRTXIFINDEX 1 - #define COLUMN_PGMNETSIRTXIFPACKETCOUNT 2 - -/* column number definitions for table pgmNeTsiPolrTable */ - #define COLUMN_PGMNETSIPOLRSOURCE 1 - #define COLUMN_PGMNETSIPOLRSEQUENCENUMBER 2 - -/* column number definitions for table pgmNeTsiPollTable */ - #define COLUMN_PGMNETSIPOLLTYPE 1 - #define COLUMN_PGMNETSIPOLLSEQUENCE 2 - #define COLUMN_PGMNETSIPOLLCHILDBACKOFF 3 - #define COLUMN_PGMNETSIPOLLMASK 4 - #define COLUMN_PGMNETSIPOLLPERIOD 5 - #define COLUMN_PGMNETSIPOLLCOUNT 6 - #define COLUMN_PGMNETSIPOLLTIMEOUT 7 - -/* column number definitions for table pgmSourceTable */ - #define COLUMN_PGMSOURCEGLOBALID 1 - #define COLUMN_PGMSOURCESOURCEPORT 2 - #define COLUMN_PGMSOURCESOURCEADDRESS 3 - #define COLUMN_PGMSOURCEGROUPADDRESS 4 - #define COLUMN_PGMSOURCEDESTPORT 5 - #define COLUMN_PGMSOURCESOURCEGSI 6 - #define COLUMN_PGMSOURCESOURCEPORTNUMBER 7 - -/* column number definitions for table pgmSourceConfigTable */ - #define COLUMN_PGMSOURCECONFIGGLOBALID 1 - #define COLUMN_PGMSOURCECONFIGSOURCEPORT 2 - #define COLUMN_PGMSOURCETTL 3 - #define COLUMN_PGMSOURCEADVMODE 4 - #define COLUMN_PGMSOURCELATEJOIN 5 - #define COLUMN_PGMSOURCETXWMAXRTE 6 - #define COLUMN_PGMSOURCETXWSECS 7 - #define COLUMN_PGMSOURCETXWADVSECS 8 - #define COLUMN_PGMSOURCEADVIVL 9 - #define COLUMN_PGMSOURCESPMIVL 10 - #define COLUMN_PGMSOURCESPMHEARTBEATIVLMIN 11 - #define COLUMN_PGMSOURCESPMHEARTBEATIVLMAX 12 - #define COLUMN_PGMSOURCERDATABACKOFFIVL 13 - #define COLUMN_PGMSOURCEFEC 14 - #define COLUMN_PGMSOURCEFECTRANSMISSIONGRPSIZE 15 - #define COLUMN_PGMSOURCEFECPROACTIVEPARITYSIZE 16 - #define COLUMN_PGMSOURCESPMPATHADDRESS 17 - -/* column number definitions for table pgmSourcePerformanceTable */ - #define COLUMN_PGMSOURCEPERFORMANCEGLOBALID 1 - #define COLUMN_PGMSOURCEPERFORMANCESOURCEPORT 2 - #define COLUMN_PGMSOURCEDATABYTESSENT 3 - #define COLUMN_PGMSOURCEDATAMSGSSENT 4 - #define COLUMN_PGMSOURCEBYTESBUFFERED 5 - #define COLUMN_PGMSOURCEMSGSBUFFERED 6 - #define COLUMN_PGMSOURCEBYTESRETRANSMITTED 7 - #define COLUMN_PGMSOURCEMSGSRETRANSMITTED 8 - #define COLUMN_PGMSOURCEBYTESSENT 9 - #define COLUMN_PGMSOURCERAWNAKSRECEIVED 10 - #define COLUMN_PGMSOURCENAKSIGNORED 11 - #define COLUMN_PGMSOURCECKSUMERRORS 12 - #define COLUMN_PGMSOURCEMALFORMEDNAKS 13 - #define COLUMN_PGMSOURCEPACKETSDISCARDED 14 - #define COLUMN_PGMSOURCENAKSRCVD 15 - #define COLUMN_PGMSOURCEPARITYBYTESRETRANSMITTED 16 - #define COLUMN_PGMSOURCESELECTIVEBYTESRETRANSMITED 17 - #define COLUMN_PGMSOURCEPARITYMSGSRETRANSMITTED 18 - #define COLUMN_PGMSOURCESELECTIVEMSGSRETRANSMITTED 19 - #define COLUMN_PGMSOURCEBYTESADMIT 20 - #define COLUMN_PGMSOURCEMSGSADMIT 21 - #define COLUMN_PGMSOURCEPARITYNAKPACKETSRECEIVED 22 - #define COLUMN_PGMSOURCESELECTIVENAKPACKETSRECEIVED 23 - #define COLUMN_PGMSOURCEPARITYNAKSRECEIVED 24 - #define COLUMN_PGMSOURCESELECTIVENAKSRECEIVED 25 - #define COLUMN_PGMSOURCEPARITYNAKSIGNORED 26 - #define COLUMN_PGMSOURCESELECTIVENAKSIGNORED 27 - #define COLUMN_PGMSOURCEACKERRORS 28 - #define COLUMN_PGMSOURCEPGMCCACKER 29 - #define COLUMN_PGMSOURCETRANSMISSIONCURRENTRATE 30 - #define COLUMN_PGMSOURCEACKPACKETSRECEIVED 31 - #define COLUMN_PGMSOURCENNAKPACKETSRECEIVED 32 - #define COLUMN_PGMSOURCEPARITYNNAKPACKETSRECEIVED 33 - #define COLUMN_PGMSOURCESELECTIVENNAKPACKETSRECEIVED 34 - #define COLUMN_PGMSOURCENNAKSRECEIVED 35 - #define COLUMN_PGMSOURCEPARITYNNAKSRECEIVED 36 - #define COLUMN_PGMSOURCESELECTIVENNAKSRECEIVED 37 - #define COLUMN_PGMSOURCENNAKERRORS 38 - -/* column number definitions for table pgmReceiverTable */ - #define COLUMN_PGMRECEIVERGLOBALID 1 - #define COLUMN_PGMRECEIVERSOURCEPORT 2 - #define COLUMN_PGMRECEIVERINSTANCE 3 - #define COLUMN_PGMRECEIVERGROUPADDRESS 4 - #define COLUMN_PGMRECEIVERDESTPORT 5 - #define COLUMN_PGMRECEIVERSOURCEADDRESS 6 - #define COLUMN_PGMRECEIVERLASTHOP 7 - #define COLUMN_PGMRECEIVERSOURCEGSI 8 - #define COLUMN_PGMRECEIVERSOURCEPORTNUMBER 9 - #define COLUMN_PGMRECEIVERUNIQUEINSTANCE 10 - -/* column number definitions for table pgmReceiverConfigTable */ - #define COLUMN_PGMRECEIVERCONFIGGLOBALID 1 - #define COLUMN_PGMRECEIVERCONFIGSOURCEPORT 2 - #define COLUMN_PGMRECEIVERCONFIGINSTANCE 3 - #define COLUMN_PGMRECEIVERNAKBACKOFFIVL 4 - #define COLUMN_PGMRECEIVERNAKREPEATIVL 5 - #define COLUMN_PGMRECEIVERNAKNCFRETRIES 6 - #define COLUMN_PGMRECEIVERNAKRDATAIVL 7 - #define COLUMN_PGMRECEIVERNAKDATARETRIES 8 - #define COLUMN_PGMRECEIVERSENDNAKS 9 - #define COLUMN_PGMRECEIVERLATEJOIN 10 - #define COLUMN_PGMRECEIVERNAKTTL 11 - #define COLUMN_PGMRECEIVERDELIVERYORDER 12 - #define COLUMN_PGMRECEIVERMCASTNAKS 13 - #define COLUMN_PGMRECEIVERNAKFAILURETHRESHOLDTIMER 14 - #define COLUMN_PGMRECEIVERNAKFAILURETHRESHOLD 15 - -/* column number definitions for table pgmReceiverPerformanceTable */ - #define COLUMN_PGMRECEIVERPERFORMANCEGLOBALID 1 - #define COLUMN_PGMRECEIVERPERFORMANCESOURCEPORT 2 - #define COLUMN_PGMRECEIVERPERFORMANCEINSTANCE 3 - #define COLUMN_PGMRECEIVERDATABYTESRECEIVED 4 - #define COLUMN_PGMRECEIVERDATAMSGSRECEIVED 5 - #define COLUMN_PGMRECEIVERNAKSSENT 6 - #define COLUMN_PGMRECEIVERNAKSRETRANSMITTED 7 - #define COLUMN_PGMRECEIVERNAKFAILURES 8 - #define COLUMN_PGMRECEIVERBYTESRECEIVED 9 - #define COLUMN_PGMRECEIVERNAKSSUPPRESSED 10 - #define COLUMN_PGMRECEIVERCKSUMERRORS 11 - #define COLUMN_PGMRECEIVERMALFORMEDSPMS 12 - #define COLUMN_PGMRECEIVERMALFORMEDODATA 13 - #define COLUMN_PGMRECEIVERMALFORMEDRDATA 14 - #define COLUMN_PGMRECEIVERMALFORMEDNCFS 15 - #define COLUMN_PGMRECEIVERPACKETSDISCARDED 16 - #define COLUMN_PGMRECEIVERLOSSES 17 - #define COLUMN_PGMRECEIVERBYTESDELIVEREDTOAPP 18 - #define COLUMN_PGMRECEIVERMSGSDELIVEREDTOAPP 19 - #define COLUMN_PGMRECEIVERDUPSPMS 20 - #define COLUMN_PGMRECEIVERDUPDATAS 21 - #define COLUMN_PGMRECEIVERDUPPARITIES 22 - #define COLUMN_PGMRECEIVERNAKPACKETSSENT 23 - #define COLUMN_PGMRECEIVERPARITYNAKPACKETSSENT 24 - #define COLUMN_PGMRECEIVERSELECTIVENAKPACKETSSENT 25 - #define COLUMN_PGMRECEIVERPARITYNAKSSENT 26 - #define COLUMN_PGMRECEIVERSELECTIVENAKSSENT 27 - #define COLUMN_PGMRECEIVERPARITYNAKSRETRANSMITTED 28 - #define COLUMN_PGMRECEIVERSELECTIVENAKSRETRANSMITTED 29 - #define COLUMN_PGMRECEIVERNAKSFAILED 30 - #define COLUMN_PGMRECEIVERPARITYNAKSFAILED 31 - #define COLUMN_PGMRECEIVERSELECTIVENAKSFAILED 32 - #define COLUMN_PGMRECEIVERNAKSFAILEDRXWADVANCED 33 - #define COLUMN_PGMRECEIVERNAKSFALEDNCFRETRIESEXCEEDED 34 - #define COLUMN_PGMRECEIVERNAKSFAILEDDATARETRIESEXCEEDED 35 - #define COLUMN_PGMRECEIVERNAKSFAILEDGENEXPIRED 36 - #define COLUMN_PGMRECEIVERNAKFAILURESDELIVERED 37 - #define COLUMN_PGMRECEIVERPARITYNAKSSUPPRESSED 38 - #define COLUMN_PGMRECEIVERSELECTIVENAKSSUPPRESSED 39 - #define COLUMN_PGMRECEIVERNAKERRORS 40 - #define COLUMN_PGMRECEIVEROUTSTANDINGPARITYNAKS 41 - #define COLUMN_PGMRECEIVEROUTSTANDINGSELECTIVENAKS 42 - #define COLUMN_PGMRECEIVERLASTACTIVITY 43 - #define COLUMN_PGMRECEIVERNAKSVCTIMEMIN 44 - #define COLUMN_PGMRECEIVERNAKSVCTIMEMEAN 45 - #define COLUMN_PGMRECEIVERNAKSVCTIMEMAX 46 - #define COLUMN_PGMRECEIVERNAKFAILTIMEMIN 47 - #define COLUMN_PGMRECEIVERNAKFAILTIMEMEAN 48 - #define COLUMN_PGMRECEIVERNAKFAILTIMEMAX 49 - #define COLUMN_PGMRECEIVERNAKTRANSMITMIN 50 - #define COLUMN_PGMRECEIVERNAKTRANSMITMEAN 51 - #define COLUMN_PGMRECEIVERNAKTRANSMITMAX 52 - #define COLUMN_PGMRECEIVERACKSSENT 53 - #define COLUMN_PGMRECEIVERRXWTRAIL 54 - #define COLUMN_PGMRECEIVERRXWLEAD 55 - #define COLUMN_PGMRECEIVERNAKFAILURESLASTINTERVAL 56 - #define COLUMN_PGMRECEIVERLASTINTERVALNAKFAILURES 57 - -/* column number definitions for table pgmDlrSourceTable */ - #define COLUMN_PGMDLRSOURCEGLOBALID 1 - #define COLUMN_PGMDLRSOURCESOURCEPORT 2 - #define COLUMN_PGMDLRSOURCEGROUPADDRESS 3 - #define COLUMN_PGMDLRSOURCESOURCEGSI 4 - #define COLUMN_PGMDLRSOURCESOURCEPORTNUMBER 5 - -/* column number definitions for table pgmDlrSourceConfigTable */ - #define COLUMN_PGMDLRSOURCECONFIGGLOBALID 1 - #define COLUMN_PGMDLRSOURCECONFIGSOURCEPORT 2 - #define COLUMN_PGMDLRSOURCEGROUPTTL 3 - #define COLUMN_PGMDLRSOURCERDATABACKOFFIVL 4 - -/* column number definitions for table pgmDlrSourcePerformanceTable */ - #define COLUMN_PGMDLRSOURCEPERFORMANCEGLOBALID 1 - #define COLUMN_PGMDLRSOURCEPERFORMANCESOURCEPORT 2 - #define COLUMN_PGMDLRSOURCERDATAMSGSSENT 3 - #define COLUMN_PGMDLRSOURCERDATABYTESSENT 4 - #define COLUMN_PGMDLRSOURCEBYTESSENT 5 - #define COLUMN_PGMDLRSOURCENAKSRCVD 6 - #define COLUMN_PGMDLRSOURCENAKSIGNORED 7 - #define COLUMN_PGMDLRSOURCENAKERRORS 8 - #define COLUMN_PGMDLRSOURCEDISCARDS 9 - #define COLUMN_PGMDLRSOURCECKSUMERRORS 10 - #define COLUMN_PGMDLRSOURCENNAKSSENT 11 - #define COLUMN_PGMDLRSOURCEBYTESBUFFERED 12 - #define COLUMN_PGMDLRSOURCEMSGSBUFFERED 13 - #define COLUMN_PGMDLRSOURCEPARITYBYTESRETRANSMITTED 14 - #define COLUMN_PGMDLRSOURCESELECTIVEBYTESRETRANSMITED 15 - #define COLUMN_PGMDLRSOURCEPARITYMSGSRETRANSMITTED 16 - #define COLUMN_PGMDLRSOURCESELECTIVEMSGSRETRANSMITTED 17 - #define COLUMN_PGMDLRSOURCEBYTESADMIT 18 - #define COLUMN_PGMDLRSOURCEMSGSADMIT 19 - #define COLUMN_PGMDLRSOURCENAKPACKETSRECEIVED 20 - #define COLUMN_PGMDLRSOURCEPARITYNAKPACKETSRECEIVED 21 - #define COLUMN_PGMDLRSOURCESELECTIVENAKPACKETSRECEIVED 22 - #define COLUMN_PGMDLRSOURCEPARITYNAKSRECEIVED 23 - #define COLUMN_PGMDLRSOURCESELECTIVENAKSRECEIVED 24 - #define COLUMN_PGMDLRSOURCEPARITYNAKSIGNORED 25 - #define COLUMN_PGMDLRSOURCESELECTIVENAKSIGNORED 26 - #define COLUMN_PGMDLRSOURCEACKERRORS 27 - #define COLUMN_PGMDLRSOURCENNAKERRORS 28 - #define COLUMN_PGMDLRSOURCEACKPACKETSRECEIVED 29 - #define COLUMN_PGMDLRSOURCENNAKPACKETSRECEIVED 30 - #define COLUMN_PGMDLRSOURCEPARITYNNAKPACKETSRECEIVED 31 - #define COLUMN_PGMDLRSOURCESELECTIVENNAKPACKETSRECEIVED 32 - #define COLUMN_PGMDLRSOURCENNAKSRECEIVED 33 - #define COLUMN_PGMDLRSOURCEPARITYNNAKSRECEIVED 34 - #define COLUMN_PGMDLRSOURCESELECTIVENNAKSRECEIVED 35 -#endif /* PGMMIB_COLUMNS_H */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB_enums.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB_enums.h deleted file mode 100644 index 9ae5760..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/pgmMIB_enums.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Note: this file originally auto-generated by mib2c using - * : mib2c.column_enums.conf,v 5.2 2003/02/22 04:09:25 hardaker Exp $ - */ -#ifndef PGMMIB_ENUMS_H -#define PGMMIB_ENUMS_H - -/* enums for column pgmNeIfPgmEnable */ - #define PGMNEIFPGMENABLE_ENABLE 1 - #define PGMNEIFPGMENABLE_DISABLE 2 - -/* enums for column pgmNeTsiStateBits */ - #define PGMNETSISTATEBITS_INITIALISING 0 - #define PGMNETSISTATEBITS_SPMSQNSTATEVALID 1 - #define PGMNETSISTATEBITS_DLRCANPROVIDEPARITY 2 - -/* enums for column pgmNeTsiRtxSequenceNumberType */ - #define PGMNETSIRTXSEQUENCENUMBERTYPE_SELECTIVE 1 - #define PGMNETSIRTXSEQUENCENUMBERTYPE_TG 2 - -/* enums for column pgmNeTsiRtxStateBits */ - #define PGMNETSIRTXSTATEBITS_INITIALISING 0 - #define PGMNETSIRTXSTATEBITS_ELIMINATING 1 - #define PGMNETSIRTXSTATEBITS_REDIRECTING 2 - #define PGMNETSIRTXSTATEBITS_STATECREATEDBYNULLNAK 3 - #define PGMNETSIRTXSTATEBITS_LISTNAKENTRY 4 - #define PGMNETSIRTXSTATEBITS_PARITYSTATE 5 - -/* enums for column pgmNeTsiPollType */ - #define PGMNETSIPOLLTYPE_GENERAL 1 - #define PGMNETSIPOLLTYPE_DLR 2 - -/* enums for column pgmSourceAdvMode */ - #define PGMSOURCEADVMODE_DATA 1 - #define PGMSOURCEADVMODE_TIME 2 - #define PGMSOURCEADVMODE_APPLCTRL 3 - #define PGMSOURCEADVMODE_OTHER 4 - -/* enums for column pgmSourceLateJoin */ - #define PGMSOURCELATEJOIN_ENABLE 1 - #define PGMSOURCELATEJOIN_DISABLE 2 - -/* enums for column pgmSourceFEC */ - #define PGMSOURCEFEC_DISABLED 1 - #define PGMSOURCEFEC_ENABLEDFIXEDPACKETSIZE 2 - #define PGMSOURCEFEC_ENABLEDVARIABLEPACKETSIZE 3 - -/* enums for column pgmReceiverSendNaks */ - #define PGMRECEIVERSENDNAKS_ENABLED 1 - #define PGMRECEIVERSENDNAKS_DISABLED 2 - -/* enums for column pgmReceiverLateJoin */ - #define PGMRECEIVERLATEJOIN_ENABLED 1 - #define PGMRECEIVERLATEJOIN_DISABLED 2 - -/* enums for column pgmReceiverDeliveryOrder */ - #define PGMRECEIVERDELIVERYORDER_UNORDERED 1 - #define PGMRECEIVERDELIVERYORDER_ORDERED 2 - -/* enums for column pgmReceiverMcastNaks */ - #define PGMRECEIVERMCASTNAKS_ENABLED 1 - #define PGMRECEIVERMCASTNAKS_DISABLED 2 - -#endif /* PGMMIB_ENUMS_H */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/processor.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/processor.h deleted file mode 100644 index f7ee31a..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/processor.h +++ /dev/null @@ -1,61 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Processor macros for cross-platform, cross-compiler froyo. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_PROCESSOR_H__ -#define __PGM_IMPL_PROCESSOR_H__ - -/* Memory prefetch */ -#if defined( sun ) -static inline void pgm_prefetch (const void *x) -{ - asm volatile ( "prefetch [%0], #one_write" - : /* nil */ - : "r" (x)); -} -static inline void pgm_prefetchw (const void *x) -{ - asm volatile ( "prefetch [%0], #n_writes" - : /* nil */ - : "r" (x)); -} -#elif defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) -static inline void pgm_prefetch (const void *x) -{ - __builtin_prefetch (x, 0 /* read */, 0 /* no temporal locality */); -} -static inline void pgm_prefetchw (const void *x) -{ - __builtin_prefetch (x, 1 /* write */, 3 /* high temporal */); -} -#else -static inline void pgm_prefetch (PGM_GNUC_UNUSED const void *x) -{ -} -static inline void pgm_prefetchw (PGM_GNUC_UNUSED const void *x) -{ -} -#endif - -#endif /* __PGM_IMPL_PROCESSOR_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/queue.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/queue.h deleted file mode 100644 index c640e52..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/queue.h +++ /dev/null @@ -1,51 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable double-ended queue. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_QUEUE_H__ -#define __PGM_IMPL_QUEUE_H__ - -typedef struct pgm_queue_t pgm_queue_t; - -#include -#include - -PGM_BEGIN_DECLS - -struct pgm_queue_t -{ - pgm_list_t* head; /* head & tail equal on 1 element */ - pgm_list_t* tail; - unsigned length; -}; - -PGM_GNUC_INTERNAL bool pgm_queue_is_empty (const pgm_queue_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_queue_push_head_link (pgm_queue_t*restrict, pgm_list_t*restrict); -PGM_GNUC_INTERNAL pgm_list_t* pgm_queue_pop_tail_link (pgm_queue_t*); -PGM_GNUC_INTERNAL pgm_list_t* pgm_queue_peek_tail_link (pgm_queue_t*) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_queue_unlink (pgm_queue_t*restrict, pgm_list_t*restrict); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_QUEUE_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/rand.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/rand.h deleted file mode 100644 index 0adfd78..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/rand.h +++ /dev/null @@ -1,50 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable weak pseudo-random generator. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_RAND_H__ -#define __PGM_IMPL_RAND_H__ - -typedef struct pgm_rand_t pgm_rand_t; - -#include - -PGM_BEGIN_DECLS - -struct pgm_rand_t { - uint32_t seed; -}; - -PGM_GNUC_INTERNAL void pgm_rand_create (pgm_rand_t*); -PGM_GNUC_INTERNAL uint32_t pgm_rand_int (pgm_rand_t*); -PGM_GNUC_INTERNAL int32_t pgm_rand_int_range (pgm_rand_t*, int32_t, int32_t); -PGM_GNUC_INTERNAL uint32_t pgm_random_int (void); -PGM_GNUC_INTERNAL int32_t pgm_random_int_range (int32_t, int32_t); - -PGM_GNUC_INTERNAL void pgm_rand_init (void); -PGM_GNUC_INTERNAL void pgm_rand_shutdown (void); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_RAND_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/rate_control.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/rate_control.h deleted file mode 100644 index b27b266..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/rate_control.h +++ /dev/null @@ -1,54 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Rate regulation. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_RATE_CONTROL_H__ -#define __PGM_IMPL_RATE_CONTROL_H__ - -typedef struct pgm_rate_t pgm_rate_t; - -#include -#include -#include - -PGM_BEGIN_DECLS - -struct pgm_rate_t { - ssize_t rate_per_sec; - ssize_t rate_per_msec; - size_t iphdr_len; - - ssize_t rate_limit; /* signed for math */ - pgm_time_t last_rate_check; - pgm_spinlock_t spinlock; -}; - -PGM_GNUC_INTERNAL void pgm_rate_create (pgm_rate_t*, const ssize_t, const size_t, const uint16_t); -PGM_GNUC_INTERNAL void pgm_rate_destroy (pgm_rate_t*); -PGM_GNUC_INTERNAL bool pgm_rate_check (pgm_rate_t*, const size_t, const bool); -PGM_GNUC_INTERNAL pgm_time_t pgm_rate_remaining (pgm_rate_t*, const size_t); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_RATE_CONTROL_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/receiver.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/receiver.h deleted file mode 100644 index e9c3a75..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/receiver.h +++ /dev/null @@ -1,142 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM receiver socket. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_RECEIVER_H__ -#define __PGM_IMPL_RECEIVER_H__ - -typedef struct pgm_peer_t pgm_peer_t; - -#ifndef _WIN32 -# include -#endif -#include -#include - -PGM_BEGIN_DECLS - -/* Performance Counters */ - -enum { - PGM_PC_RECEIVER_DATA_BYTES_RECEIVED, - PGM_PC_RECEIVER_DATA_MSGS_RECEIVED, - PGM_PC_RECEIVER_NAK_FAILURES, - PGM_PC_RECEIVER_BYTES_RECEIVED, -/* PGM_PC_RECEIVER_CKSUM_ERRORS, */ /* inherently same as source */ - PGM_PC_RECEIVER_MALFORMED_SPMS, - PGM_PC_RECEIVER_MALFORMED_ODATA, - PGM_PC_RECEIVER_MALFORMED_RDATA, - PGM_PC_RECEIVER_MALFORMED_NCFS, - PGM_PC_RECEIVER_PACKETS_DISCARDED, - PGM_PC_RECEIVER_LOSSES, -/* PGM_PC_RECEIVER_BYTES_DELIVERED_TO_APP, */ -/* PGM_PC_RECEIVER_MSGS_DELIVERED_TO_APP, */ - PGM_PC_RECEIVER_DUP_SPMS, - PGM_PC_RECEIVER_DUP_DATAS, - PGM_PC_RECEIVER_PARITY_NAK_PACKETS_SENT, - PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT, - PGM_PC_RECEIVER_PARITY_NAKS_SENT, - PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT, - PGM_PC_RECEIVER_PARITY_NAKS_RETRANSMITTED, - PGM_PC_RECEIVER_SELECTIVE_NAKS_RETRANSMITTED, - PGM_PC_RECEIVER_PARITY_NAKS_FAILED, - PGM_PC_RECEIVER_SELECTIVE_NAKS_FAILED, - PGM_PC_RECEIVER_NAKS_FAILED_RXW_ADVANCED, - PGM_PC_RECEIVER_NAKS_FAILED_NCF_RETRIES_EXCEEDED, - PGM_PC_RECEIVER_NAKS_FAILED_DATA_RETRIES_EXCEEDED, -/* PGM_PC_RECEIVER_NAKS_FAILED_GEN_EXPIRED */ - PGM_PC_RECEIVER_NAK_FAILURES_DELIVERED, - PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED, - PGM_PC_RECEIVER_NAK_ERRORS, -/* PGM_PC_RECEIVER_LAST_ACTIVITY, */ -/* PGM_PC_RECEIVER_NAK_SVC_TIME_MIN, */ - PGM_PC_RECEIVER_NAK_SVC_TIME_MEAN, -/* PGM_PC_RECEIVER_NAK_SVC_TIME_MAX, */ -/* PGM_PC_RECEIVER_NAK_FAIL_TIME_MIN, */ - PGM_PC_RECEIVER_NAK_FAIL_TIME_MEAN, -/* PGM_PC_RECEIVER_NAK_FAIL_TIME_MAX, */ -/* PGM_PC_RECEIVER_TRANSMIT_MIN, */ - PGM_PC_RECEIVER_TRANSMIT_MEAN, -/* PGM_PC_RECEIVER_TRANSMIT_MAX, */ - PGM_PC_RECEIVER_ACKS_SENT, - -/* marker */ - PGM_PC_RECEIVER_MAX -}; - -struct pgm_peer_t { - volatile uint32_t ref_count; /* atomic integer */ - - pgm_tsi_t tsi; - struct sockaddr_storage group_nla; - struct sockaddr_storage nla, local_nla; /* nla = advertised, local_nla = from packet */ - struct sockaddr_storage poll_nla; /* from parent to direct poll-response */ - struct sockaddr_storage redirect_nla; /* from dlr */ - pgm_time_t polr_expiry; - pgm_time_t spmr_expiry; - pgm_time_t spmr_tstamp; - - pgm_rxw_t* restrict window; - pgm_sock_t* restrict sock; - pgm_list_t peers_link; - pgm_slist_t pending_link; - - unsigned is_fec_enabled:1; - unsigned has_proactive_parity:1; /* indicating availability from this source */ - unsigned has_ondemand_parity:1; - - uint32_t spm_sqn; - pgm_time_t expiry; - - pgm_time_t ack_rb_expiry; /* 0 = no ACK pending */ - pgm_time_t ack_last_tstamp; /* in source time reference */ - pgm_list_t ack_link; - - uint32_t last_poll_sqn; - uint16_t last_poll_round; - pgm_time_t last_packet; - pgm_time_t last_data_tstamp; /* local timestamp of ack_last_tstamp */ - unsigned last_commit; - uint32_t lost_count; - uint32_t last_cumulative_losses; - volatile uint32_t cumulative_stats[PGM_PC_RECEIVER_MAX]; - uint32_t snap_stats[PGM_PC_RECEIVER_MAX]; - - uint32_t min_fail_time; - uint32_t max_fail_time; -}; - -PGM_GNUC_INTERNAL pgm_peer_t* pgm_new_peer (pgm_sock_t*const restrict, const pgm_tsi_t*const restrict, const struct sockaddr*const restrict, const socklen_t, const struct sockaddr*const restrict, const socklen_t, const pgm_time_t); -PGM_GNUC_INTERNAL void pgm_peer_unref (pgm_peer_t*); -PGM_GNUC_INTERNAL int pgm_flush_peers_pending (pgm_sock_t*const restrict, struct pgm_msgv_t**restrict, const struct pgm_msgv_t*const, size_t*const restrict, unsigned*const restrict); -PGM_GNUC_INTERNAL bool pgm_peer_has_pending (pgm_peer_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_peer_set_pending (pgm_sock_t*const, pgm_peer_t*const); -PGM_GNUC_INTERNAL bool pgm_check_peer_state (pgm_sock_t*const, const pgm_time_t); -PGM_GNUC_INTERNAL void pgm_set_reset_error (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_msgv_t*const restrict); -PGM_GNUC_INTERNAL pgm_time_t pgm_min_receiver_expiry (pgm_time_t, pgm_sock_t*) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_on_peer_nak (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_on_data (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_on_ncf (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_on_spm (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_on_poll (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; - -PGM_END_DECLS - -#endif /* __PGM_IMPL_RECEIVER_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/reed_solomon.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/reed_solomon.h deleted file mode 100644 index 98f6734..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/reed_solomon.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Reed-Solomon forward error correction based on Vandermonde matrices - * - * Copyright (c) 2006-2008 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_REED_SOLOMON_H__ -#define __PGM_IMPL_REED_SOLOMON_H__ - -typedef struct pgm_rs_t pgm_rs_t; - -#include -#include - -PGM_BEGIN_DECLS - -struct pgm_rs_t { - uint8_t n, k; /* RS(n, k) */ - pgm_gf8_t* GM; - pgm_gf8_t* RM; -}; - -#define PGM_RS_DEFAULT_N 255 - -PGM_GNUC_INTERNAL void pgm_rs_create (pgm_rs_t*, const uint8_t, const uint8_t); -PGM_GNUC_INTERNAL void pgm_rs_destroy (pgm_rs_t*); -PGM_GNUC_INTERNAL void pgm_rs_encode (pgm_rs_t*restrict, const pgm_gf8_t**restrict, const uint8_t, pgm_gf8_t*restrict, const uint16_t); -PGM_GNUC_INTERNAL void pgm_rs_decode_parity_inline (pgm_rs_t*restrict, pgm_gf8_t**restrict, const uint8_t*restrict, const uint16_t); -PGM_GNUC_INTERNAL void pgm_rs_decode_parity_appended (pgm_rs_t*restrict, pgm_gf8_t**restrict, const uint8_t*restrict, const uint16_t); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_REED_SOLOMON_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/rxw.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/rxw.h deleted file mode 100644 index 89a8921..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/rxw.h +++ /dev/null @@ -1,220 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * basic receive window. - * - * Copyright (c) 2006-2008 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_RXW_H__ -#define __PGM_IMPL_RXW_H__ - -typedef struct pgm_rxw_state_t pgm_rxw_state_t; -typedef struct pgm_rxw_t pgm_rxw_t; - -#include - -PGM_BEGIN_DECLS - -enum -{ - PGM_PKT_STATE_ERROR = 0, - PGM_PKT_STATE_BACK_OFF, /* PGM protocol recovery states */ - PGM_PKT_STATE_WAIT_NCF, - PGM_PKT_STATE_WAIT_DATA, - PGM_PKT_STATE_HAVE_DATA, /* data received waiting to commit to application layer */ - PGM_PKT_STATE_HAVE_PARITY, /* contains parity information not original data */ - PGM_PKT_STATE_COMMIT_DATA, /* commited data waiting for purging */ - PGM_PKT_STATE_LOST_DATA /* if recovery fails, but packet has not yet been commited */ -}; - -enum -{ - PGM_RXW_OK = 0, - PGM_RXW_INSERTED, - PGM_RXW_APPENDED, - PGM_RXW_UPDATED, - PGM_RXW_MISSING, - PGM_RXW_DUPLICATE, - PGM_RXW_MALFORMED, - PGM_RXW_BOUNDS, - PGM_RXW_SLOW_CONSUMER, - PGM_RXW_UNKNOWN -}; - -/* must be smaller than PGM skbuff control buffer */ -struct pgm_rxw_state_t { - pgm_time_t timer_expiry; - int pkt_state; - - uint8_t nak_transmit_count; /* 8-bit for size constraints */ - uint8_t ncf_retry_count; - uint8_t data_retry_count; - -/* only valid on tg_sqn::pkt_sqn = 0 */ - unsigned is_contiguous:1; /* transmission group */ -}; - -struct pgm_rxw_t { - const pgm_tsi_t* tsi; - - pgm_queue_t ack_backoff_queue; - pgm_queue_t nak_backoff_queue; - pgm_queue_t wait_ncf_queue; - pgm_queue_t wait_data_queue; -/* window context counters */ - uint32_t lost_count; /* failed to repair */ - uint32_t fragment_count; /* incomplete apdu */ - uint32_t parity_count; /* parity for repairs */ - uint32_t committed_count; /* but still in window */ - - uint16_t max_tpdu; /* maximum packet size */ - uint32_t lead, trail; - uint32_t rxw_trail, rxw_trail_init; - uint32_t commit_lead; - unsigned is_constrained:1; - unsigned is_defined:1; - unsigned has_event:1; /* edge triggered */ - unsigned is_fec_available:1; - pgm_rs_t rs; - uint32_t tg_size; /* transmission group size for parity recovery */ - uint8_t tg_sqn_shift; - - uint32_t bitmap; /* receive status of last 32 packets */ - uint32_t data_loss; /* p */ - uint32_t ack_c_p; /* constant Cᵨ */ - -/* counters all guint32 */ - uint32_t min_fill_time; /* restricted from pgm_time_t */ - uint32_t max_fill_time; - uint32_t min_nak_transmit_count; - uint32_t max_nak_transmit_count; - uint32_t cumulative_losses; - uint32_t bytes_delivered; - uint32_t msgs_delivered; - - size_t size; /* in bytes */ - unsigned alloc; /* in pkts */ -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - struct pgm_sk_buff_t* pdata[]; -#elif defined(__cplusplus) - struct pgm_sk_buff_t* pdata[1]; -#else - struct pgm_sk_buff_t* pdata[0]; -#endif -}; - - -PGM_GNUC_INTERNAL pgm_rxw_t* pgm_rxw_create (const pgm_tsi_t*const, const uint16_t, const unsigned, const unsigned, const ssize_t, const uint32_t) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_rxw_destroy (pgm_rxw_t*const); -PGM_GNUC_INTERNAL int pgm_rxw_add (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict, const pgm_time_t, const pgm_time_t) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_rxw_add_ack (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict, const pgm_time_t); -PGM_GNUC_INTERNAL void pgm_rxw_remove_ack (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict); -PGM_GNUC_INTERNAL void pgm_rxw_remove_commit (pgm_rxw_t*const); -PGM_GNUC_INTERNAL ssize_t pgm_rxw_readv (pgm_rxw_t*const restrict, struct pgm_msgv_t** restrict, const unsigned) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL unsigned pgm_rxw_remove_trail (pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL unsigned pgm_rxw_update (pgm_rxw_t*const, const uint32_t, const uint32_t, const pgm_time_t, const pgm_time_t) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_rxw_update_fec (pgm_rxw_t*const, const uint8_t); -PGM_GNUC_INTERNAL int pgm_rxw_confirm (pgm_rxw_t*const, uint32_t, pgm_time_t, pgm_time_t, pgm_time_t) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_rxw_lost (pgm_rxw_t*const, const uint32_t); -PGM_GNUC_INTERNAL void pgm_rxw_state (pgm_rxw_t* restrict, struct pgm_sk_buff_t*restrict, const int); -PGM_GNUC_INTERNAL struct pgm_sk_buff_t* pgm_rxw_peek (pgm_rxw_t*const, const uint32_t) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL const char* pgm_pkt_state_string (const int) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL const char* pgm_rxw_returns_string (const int) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_rxw_dump (const pgm_rxw_t*const); - -/* declare for GCC attributes */ -static inline unsigned pgm_rxw_max_length (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline uint32_t pgm_rxw_length (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline size_t pgm_rxw_size (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline bool pgm_rxw_is_empty (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline bool pgm_rxw_is_full (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline uint32_t pgm_rxw_lead (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline uint32_t pgm_rxw_next_lead (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; - -static inline -unsigned -pgm_rxw_max_length ( - const pgm_rxw_t* const window - ) -{ - pgm_assert (NULL != window); - return window->alloc; -} - -static inline -uint32_t -pgm_rxw_length ( - const pgm_rxw_t* const window - ) -{ - pgm_assert (NULL != window); - return ( 1 + window->lead ) - window->trail; -} - -static inline -size_t -pgm_rxw_size ( - const pgm_rxw_t* const window - ) -{ - pgm_assert (NULL != window); - return window->size; -} - -static inline -bool -pgm_rxw_is_empty ( - const pgm_rxw_t* const window - ) -{ - pgm_assert (NULL != window); - return pgm_rxw_length (window) == 0; -} - -static inline -bool -pgm_rxw_is_full ( - const pgm_rxw_t* const window - ) -{ - pgm_assert (NULL != window); - return pgm_rxw_length (window) == pgm_rxw_max_length (window); -} - -static inline -uint32_t -pgm_rxw_lead ( - const pgm_rxw_t* const window - ) -{ - pgm_assert (NULL != window); - return window->lead; -} - -static inline -uint32_t -pgm_rxw_next_lead ( - const pgm_rxw_t* const window - ) -{ - pgm_assert (NULL != window); - return (uint32_t)(pgm_rxw_lead (window) + 1); -} - -PGM_END_DECLS - -#endif /* __PGM_IMPL_RXW_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/slist.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/slist.h deleted file mode 100644 index e71b15d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/slist.h +++ /dev/null @@ -1,52 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable singly-linked list. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_SLIST_H__ -#define __PGM_IMPL_SLIST_H__ - -typedef struct pgm_slist_t pgm_slist_t; - -#include - -PGM_BEGIN_DECLS - -struct pgm_slist_t -{ - void* restrict data; - struct pgm_slist_t* restrict next; -}; - -PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_append (pgm_slist_t*restrict, void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_prepend (pgm_slist_t*restrict, void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_prepend_link (pgm_slist_t*restrict, pgm_slist_t*restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_remove (pgm_slist_t*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_remove_first (pgm_slist_t*) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_slist_free (pgm_slist_t*); -PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_last (pgm_slist_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL unsigned pgm_slist_length (pgm_slist_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; - -PGM_END_DECLS - -#endif /* __PGM_IMPL_SLIST_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/sn.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/sn.h deleted file mode 100644 index 667db0b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/sn.h +++ /dev/null @@ -1,186 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * serial number arithmetic: rfc 1982 - * - * Copyright (c) 2006-2007 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_SN_H__ -#define __PGM_IMPL_SN_H__ - -#include -#include - -PGM_BEGIN_DECLS - -#define PGM_UINT32_SIGN_BIT (1UL<<31) -#define PGM_UINT64_SIGN_BIT (1ULL<<63) - -/* declare for GCC attributes */ -static inline bool pgm_uint32_lt (const uint32_t, const uint32_t) PGM_GNUC_CONST; -static inline bool pgm_uint32_lte (const uint32_t, const uint32_t) PGM_GNUC_CONST; -static inline bool pgm_uint32_gt (const uint32_t, const uint32_t) PGM_GNUC_CONST; -static inline bool pgm_uint32_gte (const uint32_t, const uint32_t) PGM_GNUC_CONST; -static inline bool pgm_uint64_lt (const uint64_t, const uint64_t) PGM_GNUC_CONST; -static inline bool pgm_uint64_lte (const uint64_t, const uint64_t) PGM_GNUC_CONST; -static inline bool pgm_uint64_gt (const uint64_t, const uint64_t) PGM_GNUC_CONST; -static inline bool pgm_uint64_gte (const uint64_t, const uint64_t) PGM_GNUC_CONST; - -/* 32 bit */ -static inline -bool pgm_uint32_lt ( - const uint32_t s, - const uint32_t t - ) -{ - pgm_assert (sizeof(int) >= 4); - return ( ((s) - (t)) & PGM_UINT32_SIGN_BIT ); -} - -static inline -bool -pgm_uint32_lte ( - const uint32_t s, - const uint32_t t - ) -{ - pgm_assert (sizeof(int) >= 4); - return ( ((s) == (t)) || ( ((s) - (t)) & PGM_UINT32_SIGN_BIT ) ); -} - -static inline -bool -pgm_uint32_gt ( - const uint32_t s, - const uint32_t t - ) -{ - pgm_assert (sizeof(int) >= 4); - return ( ((t) - (s)) & PGM_UINT32_SIGN_BIT ); -} - -static inline -bool -pgm_uint32_gte ( - const uint32_t s, - const uint32_t t - ) -{ - pgm_assert (sizeof(int) >= 4); - return ( ((s) == (t)) || ( ((t) - (s)) & PGM_UINT32_SIGN_BIT ) ); -} - -/* 64 bit */ -static inline -bool -pgm_uint64_lt ( - const uint64_t s, - const uint64_t t - ) -{ - if (sizeof(int) == 4) - { - return ( - ( ((s) - (t)) & PGM_UINT64_SIGN_BIT ) - > 0 /* need to force boolean conversion when int = 32bits */ - ); - } - else - { - pgm_assert (sizeof(int) >= 8); - return ( ((s) - (t)) & PGM_UINT64_SIGN_BIT ); - } -} - -static inline -bool -pgm_uint64_lte ( - const uint64_t s, - const uint64_t t - ) -{ - if (sizeof(int) == 4) - { - return ( - ( (s) == (t) ) - || - ( - ( ((s) - (t)) & PGM_UINT64_SIGN_BIT ) - > 0 /* need to force boolean conversion when int = 32bits */ - ) - ); - } - else - { - pgm_assert (sizeof(int) >= 8); - return ( ((s) == (t)) || ( ((s) - (t)) & PGM_UINT64_SIGN_BIT ) ); - } -} - -static inline -bool -pgm_uint64_gt ( - const uint64_t s, - const uint64_t t - ) -{ - if (sizeof(int) == 4) - { - return ( - ( ((t) - (s)) & PGM_UINT64_SIGN_BIT ) - > 0 /* need to force boolean conversion when int = 32bits */ - ); - } - else - { - pgm_assert (sizeof(int) >= 8); - return ( ((t) - (s)) & PGM_UINT64_SIGN_BIT ); - } -} - -static inline -bool -pgm_uint64_gte ( - const uint64_t s, - const uint64_t t - ) -{ - if (sizeof(int) == 4) - { - return ( - ( (s) == (t) ) - || - ( - ( ((t) - (s)) & PGM_UINT64_SIGN_BIT ) - > 0 /* need to force boolean conversion when int = 32bits */ - ) - ); - } - else - { - pgm_assert (sizeof(int) >= 8); - return ( ((s) == (t)) || ( ((t) - (s)) & PGM_UINT64_SIGN_BIT ) ); - } -} - -PGM_END_DECLS - -#endif /* __PGM_IMPL_SN_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/sockaddr.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/sockaddr.h deleted file mode 100644 index cea84c9..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/sockaddr.h +++ /dev/null @@ -1,105 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * struct sockaddr functions independent of in or in6. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_SOCKADDR_H__ -#define __PGM_IMPL_SOCKADDR_H__ - -#ifndef _WIN32 -# include -#endif -#include - -PGM_BEGIN_DECLS - -/* fallback values where not directly supported */ -#ifndef MSG_DONTWAIT -# define MSG_DONTWAIT 0 -#endif -#ifndef MSG_ERRQUEUE -# define MSG_ERRQUEUE 0x2000 -#endif -#if !defined(EAFNOSUPPORT) && defined(WSAEAFNOSUPPORT) -# define EAFNOSUPPORT WSAEAFNOSUPPORT -#endif - -#ifndef _WIN32 -# define PGM_INVALID_SOCKET -1 -# define PGM_SOCKET_ERROR -1 -# define pgm_closesocket close -# define pgm_sock_errno() (errno) -# define pgm_sock_strerror(e) strerror(e) -# define pgm_error_from_sock_errno pgm_error_from_errno -#else -# define PGM_INVALID_SOCKET INVALID_SOCKET -# define PGM_SOCKET_ERROR SOCKET_ERROR -# define pgm_closesocket closesocket -# define pgm_sock_errno() WSAGetLastError() -# define pgm_sock_strerror(e) pgm_wsastrerror(e) -# define pgm_error_from_sock_errno pgm_error_from_wsa_errno -#endif - -PGM_GNUC_INTERNAL sa_family_t pgm_sockaddr_family (const struct sockaddr* sa); -PGM_GNUC_INTERNAL uint16_t pgm_sockaddr_port (const struct sockaddr* sa); -PGM_GNUC_INTERNAL socklen_t pgm_sockaddr_len (const struct sockaddr* sa); -PGM_GNUC_INTERNAL socklen_t pgm_sockaddr_storage_len (const struct sockaddr_storage* ss); -PGM_GNUC_INTERNAL uint32_t pgm_sockaddr_scope_id (const struct sockaddr* sa); -PGM_GNUC_INTERNAL int pgm_sockaddr_ntop (const struct sockaddr*restrict sa, char*restrict dst, size_t ulen); -PGM_GNUC_INTERNAL int pgm_sockaddr_pton (const char*restrict src, struct sockaddr*restrict dst); -PGM_GNUC_INTERNAL int pgm_sockaddr_is_addr_multicast (const struct sockaddr* sa); -PGM_GNUC_INTERNAL int pgm_sockaddr_is_addr_unspecified (const struct sockaddr* sa); -PGM_GNUC_INTERNAL int pgm_sockaddr_cmp (const struct sockaddr*restrict sa1, const struct sockaddr*restrict sa2); -PGM_GNUC_INTERNAL int pgm_sockaddr_hdrincl (const int s, const sa_family_t sa_family, const bool v); -PGM_GNUC_INTERNAL int pgm_sockaddr_pktinfo (const int s, const sa_family_t sa_family, const bool v); -PGM_GNUC_INTERNAL int pgm_sockaddr_router_alert (const int s, const sa_family_t sa_family, const bool v); -PGM_GNUC_INTERNAL int pgm_sockaddr_tos (const int s, const sa_family_t sa_family, const int tos); -PGM_GNUC_INTERNAL int pgm_sockaddr_join_group (const int s, const sa_family_t sa_family, const struct group_req* gr); -PGM_GNUC_INTERNAL int pgm_sockaddr_leave_group (const int s, const sa_family_t sa_family, const struct group_req* gr); -PGM_GNUC_INTERNAL int pgm_sockaddr_block_source (const int s, const sa_family_t sa_family, const struct group_source_req* gsr); -PGM_GNUC_INTERNAL int pgm_sockaddr_unblock_source (const int s, const sa_family_t sa_family, const struct group_source_req* gsr); -PGM_GNUC_INTERNAL int pgm_sockaddr_join_source_group (const int s, const sa_family_t sa_family, const struct group_source_req* gsr); -PGM_GNUC_INTERNAL int pgm_sockaddr_leave_source_group (const int s, const sa_family_t sa_family, const struct group_source_req* gsr); -#if defined(MCAST_MSFILTER) || defined(SIOCSMSFILTER) -# ifndef GROUP_FILTER_SIZE -# define GROUP_FILTER_SIZE(numsrc) (sizeof (struct group_filter) \ - - sizeof (struct sockaddr_storage) \ - + ((numsrc) \ - * sizeof (struct sockaddr_storage))) -# endif -PGM_GNUC_INTERNAL int pgm_sockaddr_msfilter (const int s, const sa_family_t sa_family, const struct group_filter* gf_list); -#endif -PGM_GNUC_INTERNAL int pgm_sockaddr_multicast_if (int s, const struct sockaddr* address, unsigned ifindex); -PGM_GNUC_INTERNAL int pgm_sockaddr_multicast_loop (const int s, const sa_family_t sa_family, const bool v); -PGM_GNUC_INTERNAL int pgm_sockaddr_multicast_hops (const int s, const sa_family_t sa_family, const unsigned hops); -PGM_GNUC_INTERNAL void pgm_sockaddr_nonblocking (const int s, const bool v); - -PGM_GNUC_INTERNAL const char* pgm_inet_ntop (int af, const void*restrict src, char*restrict dst, socklen_t size); -PGM_GNUC_INTERNAL int pgm_inet_pton (int af, const char*restrict src, void*restrict dst); - -PGM_GNUC_INTERNAL int pgm_nla_to_sockaddr (const void*restrict nla, struct sockaddr*restrict sa); -PGM_GNUC_INTERNAL int pgm_sockaddr_to_nla (const struct sockaddr*restrict sa, void*restrict nla); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_SOCKADDR_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/socket.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/socket.h deleted file mode 100644 index ee175d8..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/socket.h +++ /dev/null @@ -1,182 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM socket. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_SOCKET_H__ -#define __PGM_IMPL_SOCKET_H__ - -struct pgm_sock_t; - -#include -#include -#include - -PGM_BEGIN_DECLS - -#ifndef IP_MAX_MEMBERSHIPS -# define IP_MAX_MEMBERSHIPS 20 -#endif - -struct pgm_sock_t { - sa_family_t family; /* communications domain */ - int socket_type; - int protocol; - pgm_tsi_t tsi; - uint16_t dport; - uint16_t udp_encap_ucast_port; - uint16_t udp_encap_mcast_port; - uint32_t rand_node_id; /* node identifier */ - - pgm_rwlock_t lock; /* running / destroyed */ - pgm_mutex_t receiver_mutex; /* receiver API */ - pgm_mutex_t source_mutex; /* source API */ - pgm_spinlock_t txw_spinlock; /* transmit window */ - pgm_mutex_t send_mutex; /* non-router alert socket */ - pgm_mutex_t timer_mutex; /* next timer expiration */ - - bool is_bound; - bool is_connected; - bool is_destroyed; - bool is_reset; - bool is_abort_on_reset; - - bool can_send_data; /* and SPMs */ - bool can_send_nak; /* muted receiver */ - bool can_recv_data; /* send-only */ - bool is_edge_triggered_recv; - bool is_nonblocking; - - struct group_source_req send_gsr; /* multicast */ - struct sockaddr_storage send_addr; /* unicast nla */ - int send_sock; - int send_with_router_alert_sock; - struct group_source_req recv_gsr[IP_MAX_MEMBERSHIPS]; /* sa_family = 0 terminated */ - unsigned recv_gsr_len; - int recv_sock; - - size_t max_apdu; - uint16_t max_tpdu; - uint16_t max_tsdu; /* excluding optional var_pktlen word */ - uint16_t max_tsdu_fragment; - size_t iphdr_len; - bool use_multicast_loop; /* and reuseaddr for UDP encapsulation */ - unsigned hops; - unsigned txw_sqns, txw_secs; - unsigned rxw_sqns, rxw_secs; - ssize_t txw_max_rte, rxw_max_rte; - size_t sndbuf, rcvbuf; /* setsockopt (SO_SNDBUF/SO_RCVBUF) */ - - pgm_txw_t* restrict window; - pgm_rate_t rate_control; - pgm_time_t adv_ivl; /* advancing with data */ - unsigned adv_mode; /* 0 = time, 1 = data */ - bool is_controlled_spm; - bool is_controlled_odata; - bool is_controlled_rdata; - - bool use_cr; /* congestion reports */ - bool use_pgmcc; /* congestion control */ - bool is_pending_crqst; - unsigned ack_c; /* constant C */ - unsigned ack_c_p; /* constant Cᵨ */ - uint32_t ssthresh; /* slow-start threshold */ - uint32_t tokens; - uint32_t cwnd_size; /* congestion window size */ - uint32_t ack_rx_max; - uint32_t ack_bitmap; - uint32_t acks_after_loss; - uint32_t suspended_sqn; - bool is_congested; - pgm_time_t ack_expiry; - pgm_time_t ack_expiry_ivl; - pgm_time_t next_crqst; - pgm_time_t crqst_ivl; - pgm_time_t ack_bo_ivl; - struct sockaddr_storage acker_nla; - uint64_t acker_loss; - - pgm_notify_t ack_notify; - pgm_notify_t rdata_notify; - - pgm_hash_t last_hash_key; - void* restrict last_hash_value; - unsigned last_commit; - size_t blocklen; /* length of buffer blocked */ - bool is_apdu_eagain; /* writer-lock on window_lock exists as send would block */ - bool is_spm_eagain; /* writer-lock in receiver */ - - struct { - size_t data_pkt_offset; - size_t data_bytes_offset; - uint32_t first_sqn; - struct pgm_sk_buff_t* skb; /* references external buffer */ - size_t tsdu_length; - uint32_t unfolded_odata; - size_t apdu_length; - unsigned vector_index; - size_t vector_offset; - bool is_rate_limited; - } pkt_dontwait_state; - - uint32_t spm_sqn; - unsigned spm_ambient_interval; /* microseconds */ - unsigned* restrict spm_heartbeat_interval; /* zero terminated, zero lead-pad */ - unsigned spm_heartbeat_state; /* indexof spm_heartbeat_interval */ - unsigned spm_heartbeat_len; - unsigned peer_expiry; /* from absence of SPMs */ - unsigned spmr_expiry; /* waiting for peer SPMRs */ - - pgm_rand_t rand_; /* for calculating nak_rb_ivl from nak_bo_ivl */ - unsigned nak_data_retries, nak_ncf_retries; - pgm_time_t nak_bo_ivl, nak_rpt_ivl, nak_rdata_ivl; - pgm_time_t next_heartbeat_spm, next_ambient_spm; - - bool use_proactive_parity; - bool use_ondemand_parity; - bool use_var_pktlen; - uint8_t rs_n; - uint8_t rs_k; - uint8_t rs_proactive_h; /* 0 <= proactive-h <= ( n - k ) */ - uint8_t tg_sqn_shift; - struct pgm_sk_buff_t* restrict rx_buffer; - - pgm_rwlock_t peers_lock; - pgm_hashtable_t* restrict peers_hashtable; /* fast lookup */ - pgm_list_t* restrict peers_list; /* easy iteration */ - pgm_slist_t* restrict peers_pending; /* rxw: have or lost data */ - pgm_notify_t pending_notify; /* timer to rx */ - bool is_pending_read; - pgm_time_t next_poll; - - uint32_t cumulative_stats[PGM_PC_SOURCE_MAX]; - uint32_t snap_stats[PGM_PC_SOURCE_MAX]; - pgm_time_t snap_time; -}; - - -/* global variables */ -extern pgm_rwlock_t pgm_sock_list_lock; -extern pgm_slist_t* pgm_sock_list; - -size_t pgm_pkt_offset (bool, sa_family_t); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_SOCKET_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/source.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/source.h deleted file mode 100644 index dae417a..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/source.h +++ /dev/null @@ -1,75 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM source socket. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_SOURCE_H__ -#define __PGM_IMPL_SOURCE_H__ - -#include -#include - -PGM_BEGIN_DECLS - -/* Performance Counters */ -enum { - PGM_PC_SOURCE_DATA_BYTES_SENT, - PGM_PC_SOURCE_DATA_MSGS_SENT, /* msgs = packets not APDUs */ -/* PGM_PC_SOURCE_BYTES_BUFFERED, */ /* tx window contents in bytes */ -/* PGM_PC_SOURCE_MSGS_BUFFERED, */ - PGM_PC_SOURCE_BYTES_SENT, -/* PGM_PC_SOURCE_RAW_NAKS_RECEIVED, */ - PGM_PC_SOURCE_CKSUM_ERRORS, - PGM_PC_SOURCE_MALFORMED_NAKS, - PGM_PC_SOURCE_PACKETS_DISCARDED, - PGM_PC_SOURCE_PARITY_BYTES_RETRANSMITTED, - PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED, - PGM_PC_SOURCE_PARITY_MSGS_RETRANSMITTED, - PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED, - PGM_PC_SOURCE_PARITY_NAK_PACKETS_RECEIVED, - PGM_PC_SOURCE_SELECTIVE_NAK_PACKETS_RECEIVED, /* total packets */ - PGM_PC_SOURCE_PARITY_NAKS_RECEIVED, - PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED, /* serial numbers */ - PGM_PC_SOURCE_PARITY_NAKS_IGNORED, - PGM_PC_SOURCE_SELECTIVE_NAKS_IGNORED, - PGM_PC_SOURCE_ACK_ERRORS, -/* PGM_PC_SOURCE_PGMCC_ACKER, */ - PGM_PC_SOURCE_TRANSMISSION_CURRENT_RATE, - PGM_PC_SOURCE_ACK_PACKETS_RECEIVED, - PGM_PC_SOURCE_PARITY_NNAK_PACKETS_RECEIVED, - PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED, - PGM_PC_SOURCE_PARITY_NNAKS_RECEIVED, - PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED, - PGM_PC_SOURCE_NNAK_ERRORS, - -/* marker */ - PGM_PC_SOURCE_MAX -}; - -PGM_GNUC_INTERNAL bool pgm_send_spm (pgm_sock_t*, int) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_on_deferred_nak (pgm_sock_t*const); -PGM_GNUC_INTERNAL bool pgm_on_spmr (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_on_nak (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_on_nnak (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_on_ack (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; - -PGM_END_DECLS - -#endif /* __PGM_IMPL_SOURCE_H__ */ - diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/sqn_list.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/sqn_list.h deleted file mode 100644 index 4d216ae..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/sqn_list.h +++ /dev/null @@ -1,38 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM sequence list. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_SQN_LIST_H__ -#define __PGM_IMPL_SQN_LIST_H__ - -struct pgm_sqn_list_t; - -#include - -PGM_BEGIN_DECLS - -struct pgm_sqn_list_t { - uint8_t len; - uint32_t sqn[63]; /* list of sequence numbers */ -}; - -PGM_END_DECLS - -#endif /* __PGM_IMPL_SQN_LIST_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/string.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/string.h deleted file mode 100644 index 8357c2a..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/string.h +++ /dev/null @@ -1,59 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable string manipulation functions. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_STRING_H__ -#define __PGM_IMPL_STRING_H__ - -typedef struct pgm_string_t pgm_string_t; - -#include -#include - -PGM_BEGIN_DECLS - -struct pgm_string_t { - char* str; - size_t len; - size_t allocated_len; -}; - -PGM_GNUC_INTERNAL char* pgm_strdup (const char*) PGM_GNUC_MALLOC; -PGM_GNUC_INTERNAL int pgm_printf_string_upper_bound (const char*, va_list) PGM_GNUC_PRINTF(1, 0); -PGM_GNUC_INTERNAL int pgm_vasprintf (char**restrict, char const*restrict, va_list args) PGM_GNUC_PRINTF(2, 0); -PGM_GNUC_INTERNAL char* pgm_strdup_vprintf (const char*, va_list) PGM_GNUC_PRINTF(1, 0) PGM_GNUC_MALLOC; -PGM_GNUC_INTERNAL char* pgm_strconcat (const char*, ...) PGM_GNUC_MALLOC PGM_GNUC_NULL_TERMINATED; -PGM_GNUC_INTERNAL char** pgm_strsplit (const char*restrict, const char*restrict, int) PGM_GNUC_MALLOC; -PGM_GNUC_INTERNAL void pgm_strfreev (char**); - -PGM_GNUC_INTERNAL pgm_string_t* pgm_string_new (const char*); -PGM_GNUC_INTERNAL char* pgm_string_free (pgm_string_t*, bool); -PGM_GNUC_INTERNAL void pgm_string_printf (pgm_string_t*restrict, const char*restrict, ...) PGM_GNUC_PRINTF(2, 3); -PGM_GNUC_INTERNAL pgm_string_t* pgm_string_append (pgm_string_t*restrict, const char*restrict); -PGM_GNUC_INTERNAL pgm_string_t* pgm_string_append_c (pgm_string_t*, char); -PGM_GNUC_INTERNAL void pgm_string_append_printf (pgm_string_t*restrict, const char*restrict, ...) PGM_GNUC_PRINTF(2, 3); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_STRING_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/thread.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/thread.h deleted file mode 100644 index e1484d2..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/thread.h +++ /dev/null @@ -1,210 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * mutexes and locks. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_THREAD_H__ -#define __PGM_IMPL_THREAD_H__ - -typedef struct pgm_mutex_t pgm_mutex_t; -typedef struct pgm_spinlock_t pgm_spinlock_t; -typedef struct pgm_cond_t pgm_cond_t; -typedef struct pgm_rwlock_t pgm_rwlock_t; - -#ifndef _WIN32 -# include -# include -#else -# define WIN32_LEAN_AND_MEAN -# include -#endif -#include - -PGM_BEGIN_DECLS - -struct pgm_mutex_t { -#ifndef _WIN32 - pthread_mutex_t pthread_mutex; -#else - HANDLE win32_mutex; -#endif /* !_WIN32 */ -}; - -struct pgm_spinlock_t { -#ifndef _WIN32 - pthread_spinlock_t pthread_spinlock; -#else - CRITICAL_SECTION win32_spinlock; -#endif -}; - -struct pgm_cond_t { -#ifndef _WIN32 - pthread_cond_t pthread_cond; -#elif defined(CONFIG_HAVE_WIN_COND) - CONDITION_VARIABLE win32_cond; -#else - CRITICAL_SECTION win32_spinlock; - size_t len; - size_t allocated_len; - HANDLE* phandle; -#endif /* !_WIN32 */ -}; - -struct pgm_rwlock_t { -#ifndef _WIN32 - pthread_rwlock_t pthread_rwlock; -#elif CONFIG_HAVE_WIN_SRW_LOCK - SRWLOCK win32_lock; - pthread_rwlock_t pthread_rwlock; -#else - CRITICAL_SECTION win32_spinlock; - pgm_cond_t read_cond; - pgm_cond_t write_cond; - unsigned read_counter; - bool have_writer; - unsigned want_to_read; - unsigned want_to_write; -#endif /* !CONFIG_HAVE_WIN_SRW_LOCK */ -}; - -PGM_GNUC_INTERNAL void pgm_mutex_init (pgm_mutex_t*); -PGM_GNUC_INTERNAL void pgm_mutex_free (pgm_mutex_t*); -PGM_GNUC_INTERNAL bool pgm_mutex_trylock (pgm_mutex_t*); - -static inline void pgm_mutex_lock (pgm_mutex_t* mutex) { -#ifndef _WIN32 - pthread_mutex_lock (&mutex->pthread_mutex); -#else - WaitForSingleObject (mutex->win32_mutex, INFINITE); -#endif /* !_WIN32 */ -} - -static inline void pgm_mutex_unlock (pgm_mutex_t* mutex) { -#ifndef _WIN32 - pthread_mutex_unlock (&mutex->pthread_mutex); -#else - ReleaseMutex (mutex->win32_mutex); -#endif /* !_WIN32 */ -} - -PGM_GNUC_INTERNAL void pgm_spinlock_init (pgm_spinlock_t*); -PGM_GNUC_INTERNAL void pgm_spinlock_free (pgm_spinlock_t*); -PGM_GNUC_INTERNAL bool pgm_spinlock_trylock (pgm_spinlock_t*); - -static inline void pgm_spinlock_lock (pgm_spinlock_t* spinlock) { -#ifndef _WIN32 - pthread_spin_lock (&spinlock->pthread_spinlock); -#else - EnterCriticalSection (&spinlock->win32_spinlock); -#endif /* !_WIN32 */ -} - -static inline void pgm_spinlock_unlock (pgm_spinlock_t* spinlock) { -#ifndef _WIN32 - pthread_spin_unlock (&spinlock->pthread_spinlock); -#else - LeaveCriticalSection (&spinlock->win32_spinlock); -#endif /* !_WIN32 */ -} - -PGM_GNUC_INTERNAL void pgm_cond_init (pgm_cond_t*); -PGM_GNUC_INTERNAL void pgm_cond_signal (pgm_cond_t*); -PGM_GNUC_INTERNAL void pgm_cond_broadcast (pgm_cond_t*); -#ifndef _WIN32 -PGM_GNUC_INTERNAL void pgm_cond_wait (pgm_cond_t*, pthread_mutex_t*); -#else -PGM_GNUC_INTERNAL void pgm_cond_wait (pgm_cond_t*, CRITICAL_SECTION*); -#endif -PGM_GNUC_INTERNAL void pgm_cond_free (pgm_cond_t*); - -#ifndef _WIN32 -static inline void pgm_rwlock_reader_lock (pgm_rwlock_t* rwlock) { - pthread_rwlock_rdlock (&rwlock->pthread_rwlock); -} -static inline bool pgm_rwlock_reader_trylock (pgm_rwlock_t* rwlock) { - return !pthread_rwlock_tryrdlock (&rwlock->pthread_rwlock); -} -static inline void pgm_rwlock_reader_unlock(pgm_rwlock_t* rwlock) { - pthread_rwlock_unlock (&rwlock->pthread_rwlock); -} -static inline void pgm_rwlock_writer_lock (pgm_rwlock_t* rwlock) { - pthread_rwlock_wrlock (&rwlock->pthread_rwlock); -} -static inline bool pgm_rwlock_writer_trylock (pgm_rwlock_t* rwlock) { - return !pthread_rwlock_trywrlock (&rwlock->pthread_rwlock); -} -static inline void pgm_rwlock_writer_unlock (pgm_rwlock_t* rwlock) { - pthread_rwlock_unlock (&rwlock->pthread_rwlock); -} -#elif defined(CONFIG_HAVE_WIN_SRW_LOCK) -static inline void pgm_rwlock_reader_lock (pgm_rwlock_t* rwlock) { - AcquireSRWLockShared (&rwlock->win32_lock); -} -static inline bool pgm_rwlock_reader_trylock (pgm_rwlock_t* rwlock) { - return TryAcquireSRWLockShared (&rwlock->win32_lock); -} -static inline void pgm_rwlock_reader_unlock(pgm_rwlock_t* rwlock) { - ReleaseSRWLockShared (&rwlock->win32_lock); -} -static inline void pgm_rwlock_writer_lock (pgm_rwlock_t* rwlock) { - AcquireSRWLockExclusive (&rwlock->win32_lock); -} -static inline bool pgm_rwlock_writer_trylock (pgm_rwlock_t* rwlock) { - return AcquireSRWLockExclusive (&rwlock->win32_lock); -} -static inline void pgm_rwlock_writer_unlock (pgm_rwlock_t* rwlock) { - ReleaseSRWLockExclusive (&rwlock->win32_lock); -} -#else -PGM_GNUC_INTERNAL void pgm_rwlock_init (pgm_rwlock_t*); -PGM_GNUC_INTERNAL void pgm_rwlock_free (pgm_rwlock_t*); -PGM_GNUC_INTERNAL void pgm_rwlock_reader_lock (pgm_rwlock_t*); -PGM_GNUC_INTERNAL bool pgm_rwlock_reader_trylock (pgm_rwlock_t*); -PGM_GNUC_INTERNAL void pgm_rwlock_reader_unlock(pgm_rwlock_t*); -PGM_GNUC_INTERNAL void pgm_rwlock_writer_lock (pgm_rwlock_t*); -PGM_GNUC_INTERNAL bool pgm_rwlock_writer_trylock (pgm_rwlock_t*); -PGM_GNUC_INTERNAL void pgm_rwlock_writer_unlock (pgm_rwlock_t*); -#endif - -PGM_GNUC_INTERNAL void pgm_thread_init (void); -PGM_GNUC_INTERNAL void pgm_thread_shutdown (void); - -static inline -void -pgm_thread_yield (void) -{ -#ifndef _WIN32 -# ifdef _POSIX_PRIORITY_SCHEDULING - sched_yield(); -# else - pthread_yield(); /* requires _GNU */ -# endif -#else - Sleep (0); /* If you specify 0 milliseconds, the thread will relinquish - * the remainder of its time slice but remain ready. - */ -#endif /* _WIN32 */ -} - -PGM_END_DECLS - -#endif /* __PGM_IMPL_THREAD_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/time.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/time.h deleted file mode 100644 index 70c0d37..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/time.h +++ /dev/null @@ -1,51 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * high resolution timers. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_TIME_H__ -#define __PGM_IMPL_TIME_H__ - -#include -#include -#include - -PGM_BEGIN_DECLS - -typedef pgm_time_t (*pgm_time_update_func)(void); - -#define pgm_time_after(a,b) ( (a) > (b) ) -#define pgm_time_before(a,b) ( pgm_time_after((b),(a)) ) - -#define pgm_time_after_eq(a,b) ( (a) >= (b) ) -#define pgm_time_before_eq(a,b) ( pgm_time_after_eq((b),(a)) ) - -extern pgm_time_update_func pgm_time_update_now; - -PGM_GNUC_INTERNAL bool pgm_time_init (pgm_error_t**) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_time_shutdown (void); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_TIME_H__ */ - diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/timer.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/timer.h deleted file mode 100644 index 4f900e4..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/timer.h +++ /dev/null @@ -1,58 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM timer thread. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_TIMER_H__ -#define __PGM_IMPL_TIMER_H__ - -#include -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL bool pgm_timer_prepare (pgm_sock_t*const); -PGM_GNUC_INTERNAL bool pgm_timer_check (pgm_sock_t*const); -PGM_GNUC_INTERNAL pgm_time_t pgm_timer_expiration (pgm_sock_t*const); -PGM_GNUC_INTERNAL bool pgm_timer_dispatch (pgm_sock_t*const); - -static inline -void -pgm_timer_lock ( - pgm_sock_t* const sock - ) -{ - if (sock->can_send_data) - pgm_mutex_lock (&sock->timer_mutex); -} - -static inline -void -pgm_timer_unlock ( - pgm_sock_t* const sock - ) -{ - if (sock->can_send_data) - pgm_mutex_unlock (&sock->timer_mutex); -} - -PGM_END_DECLS - -#endif /* __PGM_IMPL_TIMER_H__ */ - diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/tsi.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/tsi.h deleted file mode 100644 index be93e62..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/tsi.h +++ /dev/null @@ -1,39 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * transport session ID helper functions - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_TSI_H__ -#define __PGM_IMPL_TSI_H__ - -#include -#include -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_INTERNAL pgm_hash_t pgm_tsi_hash (const void*) PGM_GNUC_WARN_UNUSED_RESULT; - -PGM_END_DECLS - -#endif /* __PGM_IMPL_TSI_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/txw.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/txw.h deleted file mode 100644 index cf33eb5..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/txw.h +++ /dev/null @@ -1,204 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * basic transmit window. - * - * Copyright (c) 2006 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IMPL_TXW_H__ -#define __PGM_IMPL_TXW_H__ - -typedef struct pgm_txw_state_t pgm_txw_state_t; -typedef struct pgm_txw_t pgm_txw_t; - -#include - -PGM_BEGIN_DECLS - -/* must be smaller than PGM skbuff control buffer */ -struct pgm_txw_state_t { - uint32_t unfolded_checksum; /* first 32-bit word must be checksum */ - - unsigned waiting_retransmit:1; /* in retransmit queue */ - unsigned retransmit_count:15; - unsigned nak_elimination_count:16; - - uint8_t pkt_cnt_requested; /* # parity packets to send */ - uint8_t pkt_cnt_sent; /* # parity packets already sent */ -}; - -struct pgm_txw_t { - const pgm_tsi_t* restrict tsi; - -/* option: lockless atomics */ - volatile uint32_t lead; - volatile uint32_t trail; - - pgm_queue_t retransmit_queue; - - pgm_rs_t rs; - uint8_t tg_sqn_shift; - struct pgm_sk_buff_t* restrict parity_buffer; - -/* Advance with data */ - pgm_time_t adv_ivl_expiry; - unsigned increment_window_naks; - unsigned adv_secs; /* TXW_ADV_SECS */ - unsigned adv_sqns; /* TXW_ADV_SECS in sequences */ - - unsigned is_fec_enabled:1; - unsigned adv_mode:1; /* 0 = advance by time, 1 = advance by data */ - - size_t size; /* window content size in bytes */ - unsigned alloc; /* length of pdata[] */ -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - struct pgm_sk_buff_t* pdata[]; -#elif defined(__cplusplus) - struct pgm_sk_buff_t* pdata[1]; -#else - struct pgm_sk_buff_t* pdata[0]; -#endif -}; - -PGM_GNUC_INTERNAL pgm_txw_t* pgm_txw_create (const pgm_tsi_t*const, const uint16_t, const uint32_t, const unsigned, const ssize_t, const bool, const uint8_t, const uint8_t) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_txw_shutdown (pgm_txw_t*const); -PGM_GNUC_INTERNAL void pgm_txw_add (pgm_txw_t*const restrict, struct pgm_sk_buff_t*const restrict); -PGM_GNUC_INTERNAL struct pgm_sk_buff_t* pgm_txw_peek (const pgm_txw_t*const, const uint32_t) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL bool pgm_txw_retransmit_push (pgm_txw_t*const, const uint32_t, const bool, const uint8_t) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL struct pgm_sk_buff_t* pgm_txw_retransmit_try_peek (pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -PGM_GNUC_INTERNAL void pgm_txw_retransmit_remove_head (pgm_txw_t*const); -PGM_GNUC_INTERNAL uint32_t pgm_txw_get_unfolded_checksum (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE; -PGM_GNUC_INTERNAL void pgm_txw_set_unfolded_checksum (struct pgm_sk_buff_t*const, const uint32_t); -PGM_GNUC_INTERNAL void pgm_txw_inc_retransmit_count (struct pgm_sk_buff_t*const); -PGM_GNUC_INTERNAL bool pgm_txw_retransmit_is_empty (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; - -/* declare for GCC attributes */ -static inline size_t pgm_txw_max_length (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline uint32_t pgm_txw_length (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline size_t pgm_txw_size (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline bool pgm_txw_is_empty (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline bool pgm_txw_is_full (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline uint32_t pgm_txw_lead (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline uint32_t pgm_txw_lead_atomic (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline uint32_t pgm_txw_next_lead (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline uint32_t pgm_txw_trail (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; -static inline uint32_t pgm_txw_trail_atomic (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; - -static inline -size_t -pgm_txw_max_length ( - const pgm_txw_t*const window - ) -{ - pgm_assert (NULL != window); - return window->alloc; -} - -static inline -uint32_t -pgm_txw_length ( - const pgm_txw_t*const window - ) -{ - pgm_assert (NULL != window); - return ( 1 + window->lead ) - window->trail; -} - -static inline -size_t -pgm_txw_size ( - const pgm_txw_t*const window - ) -{ - pgm_assert (NULL != window); - return window->size; -} - -static inline -bool -pgm_txw_is_empty ( - const pgm_txw_t*const window - ) -{ - pgm_assert (NULL != window); - return (0 == pgm_txw_length (window)); -} - -static inline -bool -pgm_txw_is_full ( - const pgm_txw_t*const window - ) -{ - pgm_assert (NULL != window); - return (pgm_txw_length (window) == pgm_txw_max_length (window)); -} - -static inline -uint32_t -pgm_txw_lead ( - const pgm_txw_t*const window - ) -{ - pgm_assert (NULL != window); - return window->lead; -} - -/* atomics may rely on global variables and so cannot be defined __pure__ */ -static inline -uint32_t -pgm_txw_lead_atomic ( - const pgm_txw_t*const window - ) -{ - pgm_assert (NULL != window); - return pgm_atomic_read32 (&window->lead); -} - -static inline -uint32_t -pgm_txw_next_lead ( - const pgm_txw_t*const window - ) -{ - pgm_assert (NULL != window); - return (uint32_t)(pgm_txw_lead (window) + 1); -} - -static inline -uint32_t -pgm_txw_trail ( - const pgm_txw_t*const window - ) -{ - pgm_assert (NULL != window); - return window->trail; -} - -static inline -uint32_t -pgm_txw_trail_atomic ( - const pgm_txw_t*const window - ) -{ - pgm_assert (NULL != window); - return pgm_atomic_read32 (&window->trail); -} - -PGM_END_DECLS - -#endif /* __PGM_IMPL_TXW_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/impl/wsastrerror.h b/3rdparty/openpgm-svn-r1085/pgm/include/impl/wsastrerror.h deleted file mode 100644 index 1be4ef2..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/impl/wsastrerror.h +++ /dev/null @@ -1,37 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Winsock Error strings. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) -# error "Only can be included directly." -#endif - -#ifndef __PGM_IMPL_WSASTRERROR_H__ -#define __PGM_IMPL_WSASTRERROR_H__ - -#include - -PGM_BEGIN_DECLS - -char* pgm_wsastrerror (const int); -char* pgm_adapter_strerror (const int); -char* pgm_win_strerror (char*, size_t, const int); - -PGM_END_DECLS - -#endif /* __PGM_IMPL_WSASTRERROR_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/atomic.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/atomic.h deleted file mode 100644 index 15a5272..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/atomic.h +++ /dev/null @@ -1,140 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * 32-bit atomic operations. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_ATOMIC_H__ -#define __PGM_ATOMIC_H__ - -#ifdef sun -# include -#endif -#include - -static inline -uint32_t -pgm_atomic_exchange_and_add32 ( - volatile uint32_t* atomic, - const uint32_t val - ) -{ -#if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) - uint32_t result; - asm volatile ( "lock\n\t" - "xaddl %0, %1" - : "=r" (result), "=m" (*atomic) - : "0" (val), "m" (*atomic) - : "memory", "cc" ); - return result; -#elif defined( __SUNPRO_C ) && (defined( __i386 ) || defined( __amd64 )) - uint32_t result = val; - asm volatile ( "lock\n\t" - "xaddl %0, %1" - :: "r" (result), "m" (*atomic) ); - return result; -#elif defined( sun ) - const uint32_t nv = atomic_add_32_nv (atomic, (int32_t)val); - return nv - val; -#elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) - return __sync_fetch_and_add (atomic, val); -#elif defined( _WIN32 ) - return InterlockedExchangeAdd ((volatile LONG*)atomic, val); -#else -# error "No supported atomic operations for this platform." -#endif -} - -static inline -void -pgm_atomic_add32 ( - volatile uint32_t* atomic, - const uint32_t val - ) -{ -#if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) - asm volatile ( "lock\n\t" - "addl %1, %0" - : "=m" (*atomic) - : "ir" (val), "m" (*atomic) - : "memory", "cc" ); -#elif defined( __SUNPRO_C ) && (defined( __i386 ) || defined( __amd64 )) - asm volatile ( "lock\n\t" - "addl %1, %0" - :: "r" (val), "m" (*atomic) ); -#elif defined( sun ) - atomic_add_32 (atomic, (int32_t)val); -#elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) - __sync_fetch_and_add (atomic, val); -#elif defined( _WIN32 ) - InterlockedExchangeAdd ((volatile LONG*)atomic, val); -#endif -} - -static inline -void -pgm_atomic_inc32 ( - volatile uint32_t* atomic - ) -{ -#if (defined( __GNUC__ ) && (defined( __i386__ ) || defined( __x86_64__ ))) || (defined( __SUNPRO_C ) && (defined( __i386 ) || defined( __amd64 ))) - pgm_atomic_add32 (atomic, 1); -#elif defined( sun ) - atomic_inc_32 (atomic); -#elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) - pgm_atomic_add32 (atomic, 1); -#elif defined( _WIN32 ) - InterlockedIncrement ((volatile LONG*)atomic); -#endif -} - -static inline -void -pgm_atomic_dec32 ( - volatile uint32_t* atomic - ) -{ -#if (defined( __GNUC__ ) && (defined( __i386__ ) || defined( __x86_64__ ))) || (defined( __SUNPRO_C ) && (defined( __i386 ) || defined( __amd64 ))) - pgm_atomic_add32 (atomic, (uint32_t)-1); -#elif defined( sun ) - atomic_dec_32 (atomic); -#elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) - pgm_atomic_add32 (atomic, (uint32_t)-1); -#elif defined( _WIN32 ) - InterlockedDecrement ((volatile LONG*)atomic); -#endif -} - -static inline -uint32_t -pgm_atomic_read32 ( - const volatile uint32_t* atomic - ) -{ - return *atomic; -} - -static inline -void -pgm_atomic_write32 ( - volatile uint32_t* atomic, - const uint32_t val - ) -{ - *atomic = val; -} - -#endif /* __PGM_ATOMIC_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/backtrace.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/backtrace.h deleted file mode 100644 index 24f8469..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/backtrace.h +++ /dev/null @@ -1,33 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Dump back trace to stderr and try gdb. - * - * Copyright (c) 2006 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_BACKTRACE_H__ -#define __PGM_BACKTRACE_H__ - -#include - -PGM_BEGIN_DECLS - -PGM_GNUC_NORETURN void on_sigsegv (int); - -PGM_END_DECLS - -#endif /* __PGM_BACKTRACE_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/engine.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/engine.h deleted file mode 100644 index 43115e8..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/engine.h +++ /dev/null @@ -1,37 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM engine. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_ENGINE_H__ -#define __PGM_ENGINE_H__ - -#include -#include - -PGM_BEGIN_DECLS - -bool pgm_init (pgm_error_t**); -bool pgm_supported (void) PGM_GNUC_WARN_UNUSED_RESULT PGM_GNUC_PURE; -bool pgm_shutdown (void); -void pgm_drop_superuser (void); - -PGM_END_DECLS - -#endif /* __PGM_ENGINE_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/error.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/error.h deleted file mode 100644 index c87755c..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/error.h +++ /dev/null @@ -1,109 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable error reporting. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_ERROR_H__ -#define __PGM_ERROR_H__ - -typedef struct pgm_error_t pgm_error_t; - -#include - -PGM_BEGIN_DECLS - -/* error domains */ -enum -{ - PGM_ERROR_DOMAIN_IF, /* interface and host */ - PGM_ERROR_DOMAIN_PACKET, - PGM_ERROR_DOMAIN_RECV, - PGM_ERROR_DOMAIN_TIME, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_DOMAIN_ENGINE, - PGM_ERROR_DOMAIN_HTTP, - PGM_ERROR_DOMAIN_SNMP -}; - -/* error codes */ -enum -{ - /* Derived from errno, eai_errno, etc */ - PGM_ERROR_ADDRFAMILY, /* EAI_ADDRFAMILY */ - PGM_ERROR_AFNOSUPPORT, /* EAI_FAMILY */ - PGM_ERROR_AGAIN, - PGM_ERROR_BADE, /* ERROR_INVALID_DATA */ - PGM_ERROR_BADF, - PGM_ERROR_BOUNDS, /* sequence out-of-bounds */ - PGM_ERROR_CKSUM, /* pkt cksum incorrect */ - PGM_ERROR_CONNRESET, - PGM_ERROR_FAIL, /* EAI_FAIL */ - PGM_ERROR_FAULT, - PGM_ERROR_INPROGRESS, /* WSAEINPROGRESS */ - PGM_ERROR_INTR, - PGM_ERROR_INVAL, - PGM_ERROR_MFILE, - PGM_ERROR_NFILE, - PGM_ERROR_NOBUFS, /* ERROR_BUFFER_OVERFLOW */ - PGM_ERROR_NODATA, /* EAI_NODATA */ - PGM_ERROR_NODEV, - PGM_ERROR_NOENT, - PGM_ERROR_NOMEM, - PGM_ERROR_NONAME, /* EAI_NONAME */ - PGM_ERROR_NONET, - PGM_ERROR_NOPROTOOPT, - PGM_ERROR_NOSYS, /* ERROR_NOT_SUPPORTED */ - PGM_ERROR_NOTUNIQ, - PGM_ERROR_NXIO, - PGM_ERROR_PERM, - PGM_ERROR_PROCLIM, /* WSAEPROCLIM */ - PGM_ERROR_PROTO, - PGM_ERROR_RANGE, - PGM_ERROR_SERVICE, /* EAI_SERVICE */ - PGM_ERROR_SOCKTNOSUPPORT, /* EAI_SOCKTYPE */ - PGM_ERROR_SYSNOTAREADY, /* WSASYSNOTAREADY */ - PGM_ERROR_SYSTEM, /* EAI_SYSTEM */ - PGM_ERROR_VERNOTSUPPORTED, /* WSAVERNOTSUPPORTED */ - PGM_ERROR_XDEV, - - PGM_ERROR_FAILED /* generic error */ -}; - -struct pgm_error_t -{ - int domain; - int code; - char* message; -}; - -void pgm_error_free (pgm_error_t*); -void pgm_set_error (pgm_error_t**restrict, int, int, const char*restrict, ...) PGM_GNUC_PRINTF (4, 5); -void pgm_propagate_error (pgm_error_t**restrict, pgm_error_t*restrict); -void pgm_clear_error (pgm_error_t**); -void pgm_prefix_error (pgm_error_t**restrict, const char*restrict, ...) PGM_GNUC_PRINTF (2, 3); - -int pgm_error_from_errno (const int) PGM_GNUC_CONST; -int pgm_error_from_h_errno (const int) PGM_GNUC_CONST; -int pgm_error_from_eai_errno (const int, const int) PGM_GNUC_CONST; -int pgm_error_from_wsa_errno (const int) PGM_GNUC_CONST; -int pgm_error_from_win_errno (const int) PGM_GNUC_CONST; - -PGM_END_DECLS - -#endif /* __PGM_ERROR_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/gsi.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/gsi.h deleted file mode 100644 index 938214a..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/gsi.h +++ /dev/null @@ -1,49 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * global session ID helper functions - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_GSI_H__ -#define __PGM_GSI_H__ - -typedef struct pgm_gsi_t pgm_gsi_t; - -#include -#include - -PGM_BEGIN_DECLS - -#define PGM_GSISTRLEN (sizeof("000.000.000.000.000.000")) -#define PGM_GSI_INIT {{ 0, 0, 0, 0, 0, 0 }} - -struct pgm_gsi_t { - uint8_t identifier[6]; -}; - -bool pgm_gsi_create_from_hostname (pgm_gsi_t*restrict, pgm_error_t**restrict); -bool pgm_gsi_create_from_addr (pgm_gsi_t*restrict, pgm_error_t**restrict); -bool pgm_gsi_create_from_data (pgm_gsi_t*restrict, const uint8_t*restrict, const size_t); -bool pgm_gsi_create_from_string (pgm_gsi_t*restrict, const char*restrict, ssize_t); -int pgm_gsi_print_r (const pgm_gsi_t*restrict, char*restrict, const size_t); -char* pgm_gsi_print (const pgm_gsi_t*); -bool pgm_gsi_equal (const void*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; - -PGM_END_DECLS - -#endif /* __PGM_GSI_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/http.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/http.h deleted file mode 100644 index 5c65d15..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/http.h +++ /dev/null @@ -1,37 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * HTTP administrative interface - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_HTTP_H__ -#define __PGM_HTTP_H__ - -#include -#include - -PGM_BEGIN_DECLS - -#define PGM_HTTP_DEFAULT_SERVER_PORT 4968 - -bool pgm_http_init (uint16_t, pgm_error_t**) PGM_GNUC_WARN_UNUSED_RESULT; -bool pgm_http_shutdown (void); - -PGM_END_DECLS - -#endif /* __PGM_HTTP_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/if.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/if.h deleted file mode 100644 index 814d235..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/if.h +++ /dev/null @@ -1,33 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * network interface handling. - * - * Copyright (c) 2006 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IF_H__ -#define __PGM_IF_H__ - -#include - -PGM_BEGIN_DECLS - -void pgm_if_print_all (void); - -PGM_END_DECLS - -#endif /* __PGM_IF_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/ip/pgm.hh b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/ip/pgm.hh deleted file mode 100644 index a5e260f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/ip/pgm.hh +++ /dev/null @@ -1,100 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM protocol - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IP_PGM_HH__ -#define __PGM_IP_PGM_HH__ - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -namespace pgm { -#define restrict -#include -} - -namespace ip { - -class pgm -{ -public: - /// The type of a PGM endpoint. - typedef pgm_endpoint endpoint; - - /// Construct to represent PGM over IPv4. - static pgm v4() - { - return pgm (PF_INET); - } - - /// Construct to represent PGM over IPv6. - static pgm v6() - { - return pgm (PF_INET6); - } - - /// Obtain an identifier for the type of the protocol. - int type() const - { - return SOCK_SEQPACKET; - } - - /// Obtain an identifier for the protocol. - int protocol() const - { - return IPPROTO_PGM; - } - - /// Obtain an identifier for the protocol family. - int family() const - { - return family_; - } - - /// The PGM socket type. - typedef pgm_socket socket; - - /// Compare two protocols for equality. - friend bool operator== (const pgm& p1, const pgm& p2) - { - return p1.family_ == p2.family_; - } - - /// Compare two protocols for inequality. - friend bool operator!= (const pgm& p1, const pgm& p2) - { - return p1.family_ != p2.family_; - } - -private: - // Construct with a specific family. - explicit pgm (int family) - : family_ (family) - { - } - - int family_; -}; - -} // namespace ip - - -#endif /* __PGM_IP_PGM_HH__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/ip/pgm_endpoint.hh b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/ip/pgm_endpoint.hh deleted file mode 100644 index 1114719..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/ip/pgm_endpoint.hh +++ /dev/null @@ -1,171 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM endpoint - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_IP_PGM_ENDPOINT_HH__ -#define __PGM_IP_PGM_ENDPOINT_HH__ - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -namespace pgm { -#define restrict -#include -} - -namespace ip { - -template -class pgm_endpoint -{ -public: - /// The protocol type associated with the endpoint. - typedef InternetProtocol protocol_type; - - typedef struct cpgm::pgm_sockaddr_t data_type; - - /// Default constructor. - pgm_endpoint() - : data_() - { - data_.sa_port = 0; - cpgm::pgm_tsi_t tmp_addr = PGM_TSI_INIT; - data_.sa_addr = tmp_addr; - } - - /// Construct an endpoint using a port number, specified in host byte - /// order. The GSI will be generated from the node name. - /** - * @par examples - * To initialise a PGM endpoint for port 7500, use: - * @code - * ip::pgm::endpoint ep (7500); - * @endcode - */ - pgm_endpoint (unsigned short port_num) - : data_() - { - data_.sa_port = port_num; - data_.sa_addr.sport = 0; - pgm_gsi_create_from_hostname (&data_.sa_addr.gsi, NULL); - } - - /// Construct an endpoint using a port number and a TSI. - pgm_endpoint (const cpgm::pgm_tsi_t& tsi, unsigned short port_num) - : data_() - { - data_.sa_port = port_num; - data_.sa_addr = tsi; - } - - /// Construct an endpoint using a port number and a memory area. - pgm_endpoint (const void* src, std::size_t len, unsigned short port_num) - : data_() - { - data_.sa_port = port_num; - data_.sa_addr.sport = 0; - pgm_gsi_create_from_data (&data_.sa_addr.gsi, src, len); - } - - /// Copy constructor. - pgm_endpoint (const pgm_endpoint& other) - : data_ (other.data_) - { - } - - /// Assign from another endpoint. - pgm_endpoint& operator= (const pgm_endpoint& other) - { - data_ = other.data_; - return *this; - } - - /// Get the underlying endpoint in the native type. - const data_type* data() const - { - return &data_; - } - - /// Get the underlying size of the endpoint in the native type. - std::size_t size() const - { - return sizeof(data_type); - } - - /// Get the port associated with the endpoint. The port number is always in - /// the host's byte order. - unsigned short port() const - { - return data_.sa_port; - } - - /// Set the port associated with the endpoint. The port number is always in - /// the host's byte order. - void port (unsigned short port_num) - { - data_.sa_port = port_num; - } - - /// Get the TSI associated with the endpoint. - const cpgm::pgm_tsi_t* address() const - { - return &data_.sa_addr; - } - - /// Set the TSI associated with the endpoint. - void address (cpgm::pgm_tsi_t& addr) - { - data_.sa_addr = addr; - } - - /// Compare two endpoints for equality. - friend bool operator== (const pgm_endpoint& e1, - const pgm_endpoint& e2) - { - return e1.address() == e2.address() && e1.port() == e2.port(); - } - - /// Compare two endpoints for inequality. - friend bool operator!= (const pgm_endpoint& e1, - const pgm_endpoint& e2) - { - return e1.address() != e2.address() || e1.port() != e2.port(); - } - - /// Compare endpoints for ordering. - friend bool operator<(const pgm_endpoint& e1, - const pgm_endpoint& e2) - { - if (e1.address() < e2.address()) - return true; - if (e1.address() != e2.address()) - return false; - return e1.port() < e2.port(); - } - -private: - // The underlying PGM socket address. - data_type data_; -}; - -} // namespace ip - -#endif /* __PGM_IP_PGM_ENDPOINT_HH__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/list.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/list.h deleted file mode 100644 index b91abc9..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/list.h +++ /dev/null @@ -1,40 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable doubly-linked list. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_LIST_H__ -#define __PGM_LIST_H__ - -typedef struct pgm_list_t pgm_list_t; - -#include - -PGM_BEGIN_DECLS - -struct pgm_list_t -{ - void* data; - struct pgm_list_t* next; - struct pgm_list_t* prev; -}; - -PGM_END_DECLS - -#endif /* __PGM_LIST_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/log.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/log.h deleted file mode 100644 index 2b6c036..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/log.h +++ /dev/null @@ -1,33 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * basic logging. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_LOG_H__ -#define __PGM_LOG_H__ - -#include - -PGM_BEGIN_DECLS - -bool log_init (void); - -PGM_END_DECLS - -#endif /* __PGM_LOG_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/macros.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/macros.h deleted file mode 100644 index 8808ccb..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/macros.h +++ /dev/null @@ -1,171 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Pre-processor macros for cross-platform, cross-compiler ice cream. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_MACROS_H__ -#define __PGM_MACROS_H__ - -/* NULL, ptrdiff_t, and size_t - */ - -#include - - -/* GCC function attributes - * http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html - */ - -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) - -/* No side-effects except return value, may follow pointers and read globals */ -# define PGM_GNUC_PURE __attribute__((__pure__)) - -/* Returns new memory like malloc() */ -# define PGM_GNUC_MALLOC __attribute__((__malloc__)) - -# define PGM_GNUC_CACHELINE_ALIGNED __attribute__((__aligned__(SMP_CACHE_BYTES), \ - __section__((".data.cacheline_aligned"))) -# define PGM_GNUC_READ_MOSTLY __attribute__((__section__(".data.read_mostly"))) - -#else -# define PGM_GNUC_PURE -# define PGM_GNUC_MALLOC -# define PGM_GNUC_CACHELINE_ALIGNED -# define PGM_GNUC_READ_MOSTLY -#endif - -#if (__GNUC__ >= 4) - -/* Variable argument function with NULL terminated list */ -# define PGM_GNUC_NULL_TERMINATED __attribute__((__sentinel__)) -#else -# define PGM_GNUC_NULL_TERMINATED -#endif - -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) - -/* malloc() with xth parameter being size */ -# define PGM_GNUC_ALLOC_SIZE(x) __attribute__((__alloc_size__(x))) - -/* malloc() with xth*yth parameters being size */ -# define PGM_GNUC_ALLOC_SIZE2(x,y) __attribute__((__alloc_size__(x,y))) -#else -# define PGM_GNUC_ALLOC_SIZE(x) -# define PGM_GNUC_ALLOC_SIZE2(x,y) -#endif - -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) - -/* printf() like function */ -# define PGM_GNUC_PRINTF(format, args) __attribute__((__format__ (__printf__, format, args))) -# define PGM_GNUC_FORMAT(format) __attribute__((__format_arg__ (format))) - -/* Function will never return */ -# define PGM_GNUC_NORETURN __attribute__((__noreturn__)) - -/* No side-effects except return value, must not follow pointers or read globals */ -# define PGM_GNUC_CONST __attribute__((__const__)) - -/* Unused function */ -# define PGM_GNUC_UNUSED __attribute__((__unused__)) - -#else /* !__GNUC__ */ -# define PGM_GNUC_PRINTF(format, args) -# define PGM_GNUC_NORETURN -# define PGM_GNUC_CONST -# define PGM_GNUC_UNUSED -#endif /* !__GNUC__ */ - -#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) - -/* Raise compiler warning if caller ignores return value */ -# define PGM_GNUC_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) - -# ifdef CONFIG_HAVE_DSO_VISIBILITY -/* Hidden visibility */ -# define PGM_GNUC_INTERNAL __attribute__((visibility("hidden"))) -# else -# define PGM_GNUC_INTERNAL -# endif -#else /* !__GNUC__ */ -# define PGM_GNUC_WARN_UNUSED_RESULT -# if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) && defined(CONFIG_HAVE_DSO_VISIBILITY) -# define PGM_GNUC_INTERNAL __hidden -# else -# define PGM_GNUC_INTERNAL -# endif -#endif /* __GNUC__ */ - - -/* Compiler time assertions, must be on unique lines in the project */ -#define PGM_PASTE_ARGS(identifier1,identifier2) identifier1 ## identifier2 -#define PGM_PASTE(identifier1,identifier2) PGM_PASTE_ARGS (identifier1, identifier2) -#define PGM_STATIC_ASSERT(expr) typedef struct { char compile_time_assertion[(expr) ? 1 : -1]; } PGM_PASTE (_pgm_static_assert_, __LINE__) - -/* Function declaration wrappers for C++ */ -#ifdef __cplusplus -# define PGM_BEGIN_DECLS extern "C" { -# define PGM_END_DECLS } -#else -# define PGM_BEGIN_DECLS -# define PGM_END_DECLS -#endif - -/* Surprisingly still not defined in C99 */ -#ifndef FALSE -# define FALSE (0) -#endif - -#ifndef TRUE -# define TRUE (!FALSE) -#endif - -#undef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) - -#undef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - -#undef ABS -#define ABS(a) (((a) < 0) ? -(a) : (a)) - -#undef CLAMP -#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) - -/* Number of elements */ -#define PGM_N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0])) - -/* Structure offsets */ -#if defined(__GNUC__) && __GNUC__ >= 4 -# define PGM_OFFSETOF(struct_type, member) (offsetof (struct_type, member)) -#else -# define PGM_OFFSETOF(struct_type, member) ((size_t)((char*)&((struct_type*) 0)->member)) -#endif - -/* Branch prediction hint */ -#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) -# define PGM_LIKELY(expr) __builtin_expect ((expr), 1) -# define PGM_UNLIKELY(expr) __builtin_expect ((expr), 0) -#else -# define PGM_LIKELY(expr) (expr) -# define PGM_UNLIKELY(expr) (expr) -#endif - -#endif /* __PGM_MACROS_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/mem.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/mem.h deleted file mode 100644 index eea31fe..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/mem.h +++ /dev/null @@ -1,60 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable fail fast memory allocation. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_MEM_H__ -#define __PGM_MEM_H__ - -#ifdef CONFIG_HAVE_ALLOCA_H -# include -#elif defined(_WIN32) -# include -#else -# include -#endif -#include - -PGM_BEGIN_DECLS - -extern bool pgm_mem_gc_friendly; - -void* pgm_malloc (const size_t) PGM_GNUC_MALLOC PGM_GNUC_ALLOC_SIZE(1); -void* pgm_malloc_n (const size_t, const size_t) PGM_GNUC_MALLOC PGM_GNUC_ALLOC_SIZE2(1, 2); -void* pgm_malloc0 (const size_t) PGM_GNUC_MALLOC PGM_GNUC_ALLOC_SIZE(1); -void* pgm_malloc0_n (const size_t, const size_t) PGM_GNUC_MALLOC PGM_GNUC_ALLOC_SIZE2(1, 2); -void* pgm_memdup (const void*, const size_t) PGM_GNUC_MALLOC; -void* pgm_realloc (void*, const size_t) PGM_GNUC_WARN_UNUSED_RESULT; -void pgm_free (void*); - -/* Convenience memory allocators that wont work well above 32-bit sizes - */ -#define pgm_new(struct_type, n_structs) \ - ((struct_type*)pgm_malloc_n ((size_t)sizeof(struct_type), (size_t)(n_structs))) -#define pgm_new0(struct_type, n_structs) \ - ((struct_type*)pgm_malloc0_n ((size_t)sizeof(struct_type), (size_t)(n_structs))) - -#define pgm_alloca(size) \ - alloca (size) -#define pgm_newa(struct_type, n_structs) \ - ((struct_type*) pgm_alloca (sizeof(struct_type) * (size_t)(n_structs))) - -PGM_END_DECLS - -#endif /* __PGM_MEM_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/messages.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/messages.h deleted file mode 100644 index 6a00b8f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/messages.h +++ /dev/null @@ -1,66 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * basic message reporting. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_MESSAGES_H__ -#define __PGM_MESSAGES_H__ - -#include - -PGM_BEGIN_DECLS - -/* Set bitmask of log roles in environmental variable PGM_LOG_MASK, - * borrowed from SmartPGM. - */ -enum { - PGM_LOG_ROLE_MEMORY = 0x001, - PGM_LOG_ROLE_NETWORK = 0x002, - PGM_LOG_ROLE_CONFIGURATION = 0x004, - PGM_LOG_ROLE_SESSION = 0x010, - PGM_LOG_ROLE_NAK = 0x020, - PGM_LOG_ROLE_RATE_CONTROL = 0x040, - PGM_LOG_ROLE_TX_WINDOW = 0x080, - PGM_LOG_ROLE_RX_WINDOW = 0x100, - PGM_LOG_ROLE_FEC = 0x400, - PGM_LOG_ROLE_CONGESTION_CONTROL = 0x800 -}; - -enum { - PGM_LOG_LEVEL_DEBUG = 0, - PGM_LOG_LEVEL_TRACE = 1, - PGM_LOG_LEVEL_MINOR = 2, - PGM_LOG_LEVEL_NORMAL = 3, - PGM_LOG_LEVEL_WARNING = 4, - PGM_LOG_LEVEL_ERROR = 5, - PGM_LOG_LEVEL_FATAL = 6 -}; - -extern int pgm_log_mask; -extern int pgm_min_log_level; - -typedef void (*pgm_log_func_t) (const int, const char*restrict, void*restrict); - -pgm_log_func_t pgm_log_set_handler (pgm_log_func_t, void*); -void pgm_messages_init (void); -void pgm_messages_shutdown (void); - -PGM_END_DECLS - -#endif /* __PGM_MESSAGES_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/msgv.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/msgv.h deleted file mode 100644 index f5effcb..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/msgv.h +++ /dev/null @@ -1,54 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Vector message container - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_MSGV_H__ -#define __PGM_MSGV_H__ - -struct pgm_iovec; -struct pgm_msgv_t; - -#include -#include -#include - -PGM_BEGIN_DECLS - -/* struct for scatter/gather I/O */ -struct pgm_iovec { -#ifndef _WIN32 -/* match struct iovec */ - void* iov_base; - size_t iov_len; /* size of iov_base */ -#else -/* match WSABUF */ - u_long iov_len; - char* iov_base; -#endif /* _WIN32 */ -}; - -struct pgm_msgv_t { - uint32_t msgv_len; /* number of elements in skb */ - struct pgm_sk_buff_t* msgv_skb[PGM_MAX_FRAGMENTS]; /* PGM socket buffer array */ -}; - -PGM_END_DECLS - -#endif /* __PGM_MSGV_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/packet.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/packet.h deleted file mode 100644 index b1bb639..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/packet.h +++ /dev/null @@ -1,472 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM packet formats, RFC 3208. - * - * Copyright (c) 2006 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_PACKET_H__ -#define __PGM_PACKET_H__ - -#ifndef _WIN32 -# include -# include -# include -#endif -#include - -PGM_BEGIN_DECLS - -/* protocol number assigned by IANA */ -#ifndef IPPROTO_PGM -# define IPPROTO_PGM 113 -#endif - -/* read from /etc/protocols if available */ -extern int pgm_ipproto_pgm; - - -/* address family indicator, rfc 1700 (ADDRESS FAMILY NUMBERS) */ -#ifndef AFI_IP -# define AFI_IP 1 /* IP (IP version 4) */ -# define AFI_IP6 2 /* IP6 (IP version 6) */ -#endif - -/* UDP ports for UDP encapsulation, as per IBM WebSphere MQ */ -#define DEFAULT_UDP_ENCAP_UCAST_PORT 3055 -#define DEFAULT_UDP_ENCAP_MCAST_PORT 3056 - -/* PGM default ports */ -#define DEFAULT_DATA_DESTINATION_PORT 7500 -#define DEFAULT_DATA_SOURCE_PORT 0 /* random */ - -/* DoS limitation to protocol (MS08-036, KB950762) */ -#ifndef PGM_MAX_APDU -# define PGM_MAX_APDU UINT16_MAX -#endif - -/* Cisco default: 24 (max 8200), Juniper & H3C default: 16, SmartPGM: 64 */ -#ifndef PGM_MAX_FRAGMENTS -# define PGM_MAX_FRAGMENTS 16 -#endif - - -enum pgm_type_e { - PGM_SPM = 0x00, /* 8.1: source path message */ - PGM_POLL = 0x01, /* 14.7.1: poll request */ - PGM_POLR = 0x02, /* 14.7.2: poll response */ - PGM_ODATA = 0x04, /* 8.2: original data */ - PGM_RDATA = 0x05, /* 8.2: repair data */ - PGM_NAK = 0x08, /* 8.3: NAK or negative acknowledgement */ - PGM_NNAK = 0x09, /* 8.3: N-NAK or null negative acknowledgement */ - PGM_NCF = 0x0a, /* 8.3: NCF or NAK confirmation */ - PGM_SPMR = 0x0c, /* 13.6: SPM request */ - PGM_ACK = 0x0d, /* PGMCC: congestion control ACK */ - PGM_MAX = 0xff -}; - -#define PGM_OPT_LENGTH 0x00 /* options length */ -#define PGM_OPT_FRAGMENT 0x01 /* fragmentation */ -#define PGM_OPT_NAK_LIST 0x02 /* list of nak entries */ -#define PGM_OPT_JOIN 0x03 /* late joining */ -#define PGM_OPT_REDIRECT 0x07 /* redirect */ -#define PGM_OPT_SYN 0x0d /* synchronisation */ -#define PGM_OPT_FIN 0x0e /* session end */ -#define PGM_OPT_RST 0x0f /* session reset */ - -#define PGM_OPT_PARITY_PRM 0x08 /* forward error correction parameters */ -#define PGM_OPT_PARITY_GRP 0x09 /* group number */ -#define PGM_OPT_CURR_TGSIZE 0x0a /* group size */ - -#define PGM_OPT_CR 0x10 /* congestion report */ -#define PGM_OPT_CRQST 0x11 /* congestion report request */ - -#define PGM_OPT_PGMCC_DATA 0x12 -#define PGM_OPT_PGMCC_FEEDBACK 0x13 - -#define PGM_OPT_NAK_BO_IVL 0x04 /* nak back-off interval */ -#define PGM_OPT_NAK_BO_RNG 0x05 /* nak back-off range */ -#define PGM_OPT_NBR_UNREACH 0x0b /* neighbour unreachable */ -#define PGM_OPT_PATH_NLA 0x0c /* path nla */ - -#define PGM_OPT_INVALID 0x7f /* option invalidated */ - -/* byte alignment for packet memory maps */ -#if defined( __GNUC__ ) && !defined( sun ) -# pragma pack(push) -#endif -#pragma pack(1) - -/* 8. PGM header */ -struct pgm_header { - uint16_t pgm_sport; /* source port: tsi::sport or UDP port depending on direction */ - uint16_t pgm_dport; /* destination port */ - uint8_t pgm_type; /* version / packet type */ - uint8_t pgm_options; /* options */ -#define PGM_OPT_PARITY 0x80 /* parity packet */ -#define PGM_OPT_VAR_PKTLEN 0x40 /* + variable sized packets */ -#define PGM_OPT_NETWORK 0x02 /* network-significant: must be interpreted by network elements */ -#define PGM_OPT_PRESENT 0x01 /* option extension are present */ - uint16_t pgm_checksum; /* checksum */ - uint8_t pgm_gsi[6]; /* global source id */ - uint16_t pgm_tsdu_length; /* tsdu length */ - /* tpdu length = th length (header + options) + tsdu length */ -}; - -/* 8.1. Source Path Messages (SPM) */ -struct pgm_spm { - uint32_t spm_sqn; /* spm sequence number */ - uint32_t spm_trail; /* trailing edge sequence number */ - uint32_t spm_lead; /* leading edge sequence number */ - uint16_t spm_nla_afi; /* nla afi */ - uint16_t spm_reserved; /* reserved */ - struct in_addr spm_nla; /* path nla */ - /* ... option extensions */ -}; - -struct pgm_spm6 { - uint32_t spm6_sqn; /* spm sequence number */ - uint32_t spm6_trail; /* trailing edge sequence number */ - uint32_t spm6_lead; /* leading edge sequence number */ - uint16_t spm6_nla_afi; /* nla afi */ - uint16_t spm6_reserved; /* reserved */ - struct in6_addr spm6_nla; /* path nla */ - /* ... option extensions */ -}; - -/* 8.2. Data Packet */ -struct pgm_data { - uint32_t data_sqn; /* data packet sequence number */ - uint32_t data_trail; /* trailing edge sequence number */ - /* ... option extensions */ - /* ... data */ -}; - -/* 8.3. Negative Acknowledgments and Confirmations (NAK, N-NAK, & NCF) */ -struct pgm_nak { - uint32_t nak_sqn; /* requested sequence number */ - uint16_t nak_src_nla_afi; /* nla afi */ - uint16_t nak_reserved; /* reserved */ - struct in_addr nak_src_nla; /* source nla */ - uint16_t nak_grp_nla_afi; /* nla afi */ - uint16_t nak_reserved2; /* reserved */ - struct in_addr nak_grp_nla; /* multicast group nla */ - /* ... option extension */ -}; - -struct pgm_nak6 { - uint32_t nak6_sqn; /* requested sequence number */ - uint16_t nak6_src_nla_afi; /* nla afi */ - uint16_t nak6_reserved; /* reserved */ - struct in6_addr nak6_src_nla; /* source nla */ - uint16_t nak6_grp_nla_afi; /* nla afi */ - uint16_t nak6_reserved2; /* reserved */ - struct in6_addr nak6_grp_nla; /* multicast group nla */ - /* ... option extension */ -}; - -/* 9. Option header (max 16 per packet) */ -struct pgm_opt_header { - uint8_t opt_type; /* option type */ -#define PGM_OPT_MASK 0x7f -#define PGM_OPT_END 0x80 /* end of options flag */ - uint8_t opt_length; /* option length */ - uint8_t opt_reserved; -#define PGM_OP_ENCODED 0x8 /* F-bit */ -#define PGM_OPX_MASK 0x3 -#define PGM_OPX_IGNORE 0x0 /* extensibility bits */ -#define PGM_OPX_INVALIDATE 0x1 -#define PGM_OPX_DISCARD 0x2 -#define PGM_OP_ENCODED_NULL 0x80 /* U-bit */ -}; - -/* 9.1. Option extension length - OPT_LENGTH */ -struct pgm_opt_length { - uint8_t opt_type; /* include header as total length overwrites reserved/OPX bits */ - uint8_t opt_length; - uint16_t opt_total_length; /* total length of all options */ -}; - -/* 9.2. Option fragment - OPT_FRAGMENT */ -struct pgm_opt_fragment { - uint8_t opt_reserved; /* reserved */ - uint32_t opt_sqn; /* first sequence number */ - uint32_t opt_frag_off; /* offset */ - uint32_t opt_frag_len; /* length */ -}; - -/* 9.3.5. Option NAK List - OPT_NAK_LIST - * - * GNU C allows opt_sqn[0], ISO C89 requireqs opt_sqn[1], ISO C99 permits opt_sqn[] - */ -struct pgm_opt_nak_list { - uint8_t opt_reserved; /* reserved */ -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - uint32_t opt_sqn[]; /* requested sequence number [62] */ -#elif defined(__cplusplus) - uint32_t opt_sqn[1]; -#else - uint32_t opt_sqn[0]; -#endif -}; - -/* 9.4.2. Option Join - OPT_JOIN */ -struct pgm_opt_join { - uint8_t opt_reserved; /* reserved */ - uint32_t opt_join_min; /* minimum sequence number */ -}; - -/* 9.5.5. Option Redirect - OPT_REDIRECT */ -struct pgm_opt_redirect { - uint8_t opt_reserved; /* reserved */ - uint16_t opt_nla_afi; /* nla afi */ - uint16_t opt_reserved2; /* reserved */ - struct in_addr opt_nla; /* dlr nla */ -}; - -struct pgm_opt6_redirect { - uint8_t opt6_reserved; /* reserved */ - uint16_t opt6_nla_afi; /* nla afi */ - uint16_t opt6_reserved2; /* reserved */ - struct in6_addr opt6_nla; /* dlr nla */ -}; - -/* 9.6.2. Option Sources - OPT_SYN */ -struct pgm_opt_syn { - uint8_t opt_reserved; /* reserved */ -}; - -/* 9.7.4. Option End Session - OPT_FIN */ -struct pgm_opt_fin { - uint8_t opt_reserved; /* reserved */ -}; - -/* 9.8.4. Option Reset - OPT_RST */ -struct pgm_opt_rst { - uint8_t opt_reserved; /* reserved */ -}; - - -/* - * Forward Error Correction - FEC - */ - -/* 11.8.1. Option Parity - OPT_PARITY_PRM */ -struct pgm_opt_parity_prm { - uint8_t opt_reserved; /* reserved */ -#define PGM_PARITY_PRM_MASK 0x3 -#define PGM_PARITY_PRM_PRO 0x1 /* source provides pro-active parity packets */ -#define PGM_PARITY_PRM_OND 0x2 /* on-demand parity packets */ - uint32_t parity_prm_tgs; /* transmission group size */ -}; - -/* 11.8.2. Option Parity Group - OPT_PARITY_GRP */ -struct pgm_opt_parity_grp { - uint8_t opt_reserved; /* reserved */ - uint32_t prm_group; /* parity group number */ -}; - -/* 11.8.3. Option Current Transmission Group Size - OPT_CURR_TGSIZE */ -struct pgm_opt_curr_tgsize { - uint8_t opt_reserved; /* reserved */ - uint32_t prm_atgsize; /* actual transmission group size */ -}; - -/* - * Congestion Control - */ - -/* 12.7.1. Option Congestion Report - OPT_CR */ -struct pgm_opt_cr { - uint8_t opt_reserved; /* reserved */ -#define PGM_OPT_CR_NEL 0x0 /* OPT_CR_NE_WL report */ -#define PGM_OPT_CR_NEP 0x1 /* OPT_CR_NE_WP report */ -#define PGM_OPT_CR_RXP 0x2 /* OPT_CR_RX_WP report */ - uint32_t opt_cr_lead; /* congestion report reference sqn */ - uint16_t opt_cr_ne_wl; /* ne worst link */ - uint16_t opt_cr_ne_wp; /* ne worst path */ - uint16_t opt_cr_rx_wp; /* rcvr worst path */ - uint16_t opt_reserved2; /* reserved */ - uint16_t opt_nla_afi; /* nla afi */ - uint16_t opt_reserved3; /* reserved */ - uint32_t opt_cr_rcvr; /* worst receivers nla */ -}; - -/* 12.7.2. Option Congestion Report Request - OPT_CRQST */ -struct pgm_opt_crqst { - uint8_t opt_reserved; /* reserved */ -#define PGM_OPT_CRQST_NEL 0x0 /* request OPT_CR_NE_WL report */ -#define PGM_OPT_CRQST_NEP 0x1 /* request OPT_CR_NE_WP report */ -#define PGM_OPT_CRQST_RXP 0x2 /* request OPT_CR_RX_WP report */ -}; - -/* PGMCC. ACK Packet */ -struct pgm_ack { - uint32_t ack_rx_max; /* RX_MAX */ - uint32_t ack_bitmap; /* received packets */ - /* ... option extensions */ -}; - -/* PGMCC Options */ -struct pgm_opt_pgmcc_data { - uint8_t opt_reserved; /* reserved */ - uint32_t opt_tstamp; /* timestamp */ - uint16_t opt_nla_afi; /* nla afi */ - uint16_t opt_reserved2; /* reserved */ - struct in_addr opt_nla; /* ACKER nla */ -}; - -struct pgm_opt6_pgmcc_data { - uint8_t opt6_reserved; /* reserved */ - uint32_t opt6_tstamp; /* timestamp */ - uint16_t opt6_nla_afi; /* nla afi */ - uint16_t opt6_reserved2; /* reserved */ - struct in6_addr opt6_nla; /* ACKER nla */ -}; - -struct pgm_opt_pgmcc_feedback { - uint8_t opt_reserved; /* reserved */ - uint32_t opt_tstamp; /* timestamp */ - uint16_t opt_nla_afi; /* nla afi */ - uint16_t opt_loss_rate; /* loss rate */ - struct in_addr opt_nla; /* ACKER nla */ -}; - -struct pgm_opt6_pgmcc_feedback { - uint8_t opt6_reserved; /* reserved */ - uint32_t opt6_tstamp; /* timestamp */ - uint16_t opt6_nla_afi; /* nla afi */ - uint16_t opt6_loss_rate; /* loss rate */ - struct in6_addr opt6_nla; /* ACKER nla */ -}; - - -/* - * SPM Requests - */ - -/* 13.6. SPM Requests */ -#if 0 -struct pgm_spmr { - /* ... option extensions */ -}; -#endif - - -/* - * Poll Mechanism - */ - -/* 14.7.1. Poll Request */ -struct pgm_poll { - uint32_t poll_sqn; /* poll sequence number */ - uint16_t poll_round; /* poll round */ - uint16_t poll_s_type; /* poll sub-type */ -#define PGM_POLL_GENERAL 0x0 /* general poll */ -#define PGM_POLL_DLR 0x1 /* DLR poll */ - uint16_t poll_nla_afi; /* nla afi */ - uint16_t poll_reserved; /* reserved */ - struct in_addr poll_nla; /* path nla */ - uint32_t poll_bo_ivl; /* poll back-off interval */ - char poll_rand[4]; /* random string */ - uint32_t poll_mask; /* matching bit-mask */ - /* ... option extensions */ -}; - -struct pgm_poll6 { - uint32_t poll6_sqn; /* poll sequence number */ - uint16_t poll6_round; /* poll round */ - uint16_t poll6_s_type; /* poll sub-type */ - uint16_t poll6_nla_afi; /* nla afi */ - uint16_t poll6_reserved; /* reserved */ - struct in6_addr poll6_nla; /* path nla */ - uint32_t poll6_bo_ivl; /* poll back-off interval */ - char poll6_rand[4]; /* random string */ - uint32_t poll6_mask; /* matching bit-mask */ - /* ... option extensions */ -}; - -/* 14.7.2. Poll Response */ -struct pgm_polr { - uint32_t polr_sqn; /* polr sequence number */ - uint16_t polr_round; /* polr round */ - uint16_t polr_reserved; /* reserved */ - /* ... option extensions */ -}; - - -/* - * Implosion Prevention - */ - -/* 15.4.1. Option NAK Back-Off Interval - OPT_NAK_BO_IVL */ -struct pgm_opt_nak_bo_ivl { - uint8_t opt_reserved; /* reserved */ - uint32_t opt_nak_bo_ivl; /* nak back-off interval */ - uint32_t opt_nak_bo_ivl_sqn; /* nak back-off interval sqn */ -}; - -/* 15.4.2. Option NAK Back-Off Range - OPT_NAK_BO_RNG */ -struct pgm_opt_nak_bo_rng { - uint8_t opt_reserved; /* reserved */ - uint32_t opt_nak_max_bo_ivl; /* maximum nak back-off interval */ - uint32_t opt_nak_min_bo_ivl; /* minimum nak back-off interval */ -}; - -/* 15.4.3. Option Neighbour Unreachable - OPT_NBR_UNREACH */ -struct pgm_opt_nbr_unreach { - uint8_t opt_reserved; /* reserved */ -}; - -/* 15.4.4. Option Path - OPT_PATH_NLA */ -struct pgm_opt_path_nla { - uint8_t opt_reserved; /* reserved */ - struct in_addr opt_path_nla; /* path nla */ -}; - -struct pgm_opt6_path_nla { - uint8_t opt6_reserved; /* reserved */ - struct in6_addr opt6_path_nla; /* path nla */ -}; - - -#if defined( __GNUC__ ) && !defined( sun ) -# pragma pack(pop) -#else -# pragma pack() -#endif - -#define PGM_IS_UPSTREAM(t) \ - ((t) == PGM_NAK /* unicast */ \ - || (t) == PGM_NNAK /* unicast */ \ - || (t) == PGM_SPMR /* multicast + unicast */ \ - || (t) == PGM_POLR /* unicast */ \ - || (t) == PGM_ACK) /* unicast */ - -#define PGM_IS_PEER(t) \ - ((t) == PGM_SPMR) /* multicast */ - -#define PGM_IS_DOWNSTREAM(t) \ - ((t) == PGM_SPM /* all types are multicast */ \ - || (t) == PGM_ODATA \ - || (t) == PGM_RDATA \ - || (t) == PGM_POLL \ - || (t) == PGM_NCF) - -PGM_END_DECLS - -#endif /* __PGM_PACKET_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm.h deleted file mode 100644 index a122f48..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm.h +++ /dev/null @@ -1,42 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * OpenPGM, an implementation of the PGM network protocol. - * - * Copyright (c) 2006-2008 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_H__ -#define __PGM_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif /* __PGM_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm.hh b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm.hh deleted file mode 100644 index fc3476f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm.hh +++ /dev/null @@ -1,33 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * OpenPGM C++ wrapper. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_HH__ -#define __PGM_HH__ - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include -#include -#include - -#endif /* __PGM_HH__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm_socket.hh b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm_socket.hh deleted file mode 100644 index 9a3f11b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/pgm_socket.hh +++ /dev/null @@ -1,157 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM socket - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_SOCKET_HH__ -#define __PGM_SOCKET_HH__ - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include -#ifndef _WIN32 -# include -# include -#else -# include -#endif - -namespace cpgm { -#define restrict -#include -}; - -template -class pgm_socket -{ -public: - /// The protocol type. - typedef Protocol protocol_type; - - /// The endpoint type. - typedef typename Protocol::endpoint endpoint_type; - - /// The native socket type. - typedef struct cpgm::pgm_sock_t* native_type; - - /// Construct a pgm_socket without opening it. - pgm_socket() - { - } - - // Open a new PGM socket implementation. - bool open (::sa_family_t family, int sock_type, int protocol, cpgm::pgm_error_t** error) - { - return cpgm::pgm_socket (&this->native_type_, family, sock_type, protocol, error); - } - - /// Close a PGM socket implementation. - bool close (bool flush) - { - return pgm_close (this->native_type_, flush); - } - - /// Get the native socket implementation. - native_type native (void) - { - return this->native_type_; - } - - // Bind the datagram socket to the specified local endpoint. - bool bind (const endpoint_type& addr, cpgm::pgm_error_t** error) - { - return pgm_bind (this->native_type_, addr.data(), sizeof(addr.data()), error); - } - - /// Connect the PGM socket to the specified endpoint. - bool connect (cpgm::pgm_error_t** error) - { - return pgm_connect (this->native_type_, error); - } - - /// Set a socket option. - bool set_option (int optname, const void* optval, ::socklen_t optlen) - { - return pgm_setsockopt (this->native_type_, optname, optval, optlen); - } - - /// Get a socket option. - bool get_option (int optname, void* optval, ::socklen_t* optlen) - { - return pgm_getsockopt (this->native_type_, optname, optval, optlen); - } - - /// Get the local endpoint. - endpoint_type local_endpoint() const - { - endpoint_type endpoint; - pgm_getsockname (this->native_type_, &endpoint); - return endpoint; - } - - /// Disable sends or receives on the socket. - bool shutdown (int what) - { - int optname, v = 1; -#ifndef _WIN32 - if (SHUT_RD == what) optname = cpgm::PGM_SEND_ONLY; - else if (SHUT_WR == what) optname = cpgm::PGM_RECV_ONLY; -#else - if (SD_RECEIVE == what) optname = cpgm::PGM_SEND_ONLY; - else if (SD_SEND == what) optname = cpgm::PGM_RECV_ONLY; -#endif - else { - errno = EINVAL; - return false; - } - return pgm_setsockopt (this->native_type_, optname, v, sizeof(v)); - } - - /// Send some data on a connected socket. - int send (const void* buf, std::size_t len, std::size_t* bytes_sent) - { - return pgm_send (this->native_type_, buf, len, bytes_sent); - } - - /// Receive some data from the peer. - int receive (void* buf, std::size_t len, int flags, std::size_t* bytes_read, cpgm::pgm_error_t** error) - { - return pgm_recv (this->native_type_, buf, len, flags, bytes_read, error); - } - - /// Receive a datagram with the endpoint of the sender. - int receive_from (void* buf, std::size_t len, int flags, std::size_t* bytes_read, endpoint_type* from, cpgm::pgm_error_t** error) - { - int ec; - struct cpgm::pgm_sockaddr_t addr; - socklen_t addrlen = sizeof (addr); - ec = pgm_recvfrom (this->native_type_, buf, len, flags, bytes_read, &addr, &addrlen, error); - from->port (addr.sa_port); - from->address (addr.sa_addr); -/* TODO: set data-destination port */ - return ec; - } - -private: - native_type native_type_; -}; - -#endif /* __PGM_SOCKET_HH__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/signal.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/signal.h deleted file mode 100644 index 546fb7e..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/signal.h +++ /dev/null @@ -1,36 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Re-entrant safe signal handling. - * - * Copyright (c) 2006-2007 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_SIGNAL_H__ -#define __PGM_SIGNAL_H__ - -#include -#include - -typedef void (*pgm_sighandler_t)(int, gpointer); - -G_BEGIN_DECLS - -gboolean pgm_signal_install (int, pgm_sighandler_t, gpointer); - -G_END_DECLS - -#endif /* __PGM_SIGNAL_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/skbuff.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/skbuff.h deleted file mode 100644 index 0701dfb..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/skbuff.h +++ /dev/null @@ -1,243 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM socket buffers - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_SKBUFF_H__ -#define __PGM_SKBUFF_H__ - -#include - -struct pgm_sk_buff_t; - -#include -#include -#include -#include -#include -#include -#include -#include - -PGM_BEGIN_DECLS - -struct pgm_sk_buff_t { - pgm_list_t link_; - - pgm_sock_t* restrict sock; - pgm_time_t tstamp; - pgm_tsi_t tsi; - - uint32_t sequence; - uint32_t __padding; /* push alignment of pgm_sk_buff_t::cb to 8 bytes */ - - char cb[48]; /* control buffer */ - - uint16_t len; /* actual data */ - unsigned zero_padded:1; - - struct pgm_header* pgm_header; - struct pgm_opt_fragment* pgm_opt_fragment; -#define of_apdu_first_sqn pgm_opt_fragment->opt_sqn -#define of_frag_offset pgm_opt_fragment->opt_frag_off -#define of_apdu_len pgm_opt_fragment->opt_frag_len - struct pgm_opt_pgmcc_data* pgm_opt_pgmcc_data; - struct pgm_data* pgm_data; - - void *head, /* all may-alias */ - *data, - *tail, - *end; - uint32_t truesize; - volatile uint32_t users; /* atomic */ -}; - -void pgm_skb_over_panic (const struct pgm_sk_buff_t*const, const uint16_t) PGM_GNUC_NORETURN; -void pgm_skb_under_panic (const struct pgm_sk_buff_t*const, const uint16_t) PGM_GNUC_NORETURN; -bool pgm_skb_is_valid (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; - -/* attribute __pure__ only valid for platforms with atomic ops. - * attribute __malloc__ not used as only part of the memory should be aliased. - * attribute __alloc_size__ does not allow headroom. - */ -static inline struct pgm_sk_buff_t* pgm_alloc_skb (const uint16_t) PGM_GNUC_WARN_UNUSED_RESULT; - -static inline -struct pgm_sk_buff_t* -pgm_alloc_skb ( - const uint16_t size - ) -{ - struct pgm_sk_buff_t* skb; - - skb = (struct pgm_sk_buff_t*)pgm_malloc (size + sizeof(struct pgm_sk_buff_t)); - if (PGM_UNLIKELY(pgm_mem_gc_friendly)) { - memset (skb, 0, size + sizeof(struct pgm_sk_buff_t)); - skb->zero_padded = 1; - } else { - memset (skb, 0, sizeof(struct pgm_sk_buff_t)); - } - skb->truesize = size + sizeof(struct pgm_sk_buff_t); - pgm_atomic_write32 (&skb->users, 1); - skb->head = skb + 1; - skb->data = skb->tail = skb->head; - skb->end = (char*)skb->data + size; - return skb; -} - -/* increase reference count */ -static inline -struct pgm_sk_buff_t* -pgm_skb_get ( - struct pgm_sk_buff_t*const skb - ) -{ - pgm_atomic_inc32 (&skb->users); - return skb; -} - -static inline -void -pgm_free_skb ( - struct pgm_sk_buff_t*const skb - ) -{ - if (pgm_atomic_exchange_and_add32 (&skb->users, (uint32_t)-1) == 1) - pgm_free (skb); -} - -/* add data */ -static inline -void* -pgm_skb_put ( - struct pgm_sk_buff_t* const skb, - const uint16_t len - ) -{ - void* tmp = skb->tail; - skb->tail = (char*)skb->tail + len; - skb->len += len; - if (PGM_UNLIKELY(skb->tail > skb->end)) - pgm_skb_over_panic (skb, len); - return tmp; -} - -static inline -void* -__pgm_skb_pull ( - struct pgm_sk_buff_t*const skb, - const uint16_t len - ) -{ - skb->len -= len; - return skb->data = (char*)skb->data + len; -} - -/* remove data from start of buffer */ -static inline -void* -pgm_skb_pull ( - struct pgm_sk_buff_t*const skb, - const uint16_t len - ) -{ - return PGM_UNLIKELY(len > skb->len) ? NULL : __pgm_skb_pull (skb, len); -} - -static inline uint16_t pgm_skb_headroom (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; -static inline uint16_t pgm_skb_tailroom (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; - -static inline -uint16_t -pgm_skb_headroom ( - const struct pgm_sk_buff_t*const skb - ) -{ - return (char*)skb->data - (char*)skb->head; -} - -static inline -uint16_t -pgm_skb_tailroom ( - const struct pgm_sk_buff_t*const skb - ) -{ - return (char*)skb->end - (char*)skb->tail; -} - -/* reserve space to add data */ -static inline -void -pgm_skb_reserve ( - struct pgm_sk_buff_t*const skb, - const uint16_t len - ) -{ - skb->data = (char*)skb->data + len; - skb->tail = (char*)skb->tail + len; - if (PGM_UNLIKELY(skb->tail > skb->end)) - pgm_skb_over_panic (skb, len); - if (PGM_UNLIKELY(skb->data < skb->head)) - pgm_skb_under_panic (skb, len); -} - -static inline struct pgm_sk_buff_t* pgm_skb_copy (const struct pgm_sk_buff_t* const) PGM_GNUC_WARN_UNUSED_RESULT; - -static inline -struct pgm_sk_buff_t* -pgm_skb_copy ( - const struct pgm_sk_buff_t* const skb - ) -{ - struct pgm_sk_buff_t* newskb; - newskb = (struct pgm_sk_buff_t*)pgm_malloc (skb->truesize); - memcpy (newskb, skb, PGM_OFFSETOF(struct pgm_sk_buff_t, pgm_header)); - newskb->zero_padded = 0; - newskb->truesize = skb->truesize; - pgm_atomic_write32 (&newskb->users, 1); - newskb->head = newskb + 1; - newskb->end = (char*)newskb->head + ((char*)skb->end - (char*)skb->head); - newskb->data = (char*)newskb->head + ((char*)skb->data - (char*)skb->head); - newskb->tail = (char*)newskb->head + ((char*)skb->tail - (char*)skb->head); - newskb->pgm_header = skb->pgm_header ? (struct pgm_header*)((char*)newskb->head + ((char*)skb->pgm_header - (char*)skb->head)) : skb->pgm_header; - newskb->pgm_opt_fragment = skb->pgm_opt_fragment ? (struct pgm_opt_fragment*)((char*)newskb->head + ((char*)skb->pgm_opt_fragment - (char*)skb->head)) : skb->pgm_opt_fragment; - newskb->pgm_data = skb->pgm_data ? (struct pgm_data*)((char*)newskb->head + ((char*)skb->pgm_data - (char*)skb->head)) : skb->pgm_data; - memcpy (newskb->head, skb->head, (char*)skb->end - (char*)skb->head); - return newskb; -} - -static inline -void -pgm_skb_zero_pad ( - struct pgm_sk_buff_t* const skb, - const uint16_t len - ) -{ - if (skb->zero_padded) - return; - - const uint16_t tailroom = MIN(pgm_skb_tailroom (skb), len); - if (tailroom > 0) - memset (skb->tail, 0, tailroom); - skb->zero_padded = 1; -} - -PGM_END_DECLS - -#endif /* __PGM_SKBUFF_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/snmp.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/snmp.h deleted file mode 100644 index 922f4e2..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/snmp.h +++ /dev/null @@ -1,35 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * SNMP - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_SNMP_H__ -#define __PGM_SNMP_H__ - -#include -#include - -PGM_BEGIN_DECLS - -bool pgm_snmp_init (pgm_error_t**) PGM_GNUC_WARN_UNUSED_RESULT; -bool pgm_snmp_shutdown (void); - -PGM_END_DECLS - -#endif /* __PGM_SNMP_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/socket.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/socket.h deleted file mode 100644 index f3a2360..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/socket.h +++ /dev/null @@ -1,170 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * PGM socket. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_SOCKET_H__ -#define __PGM_SOCKET_H__ - -typedef struct pgm_sock_t pgm_sock_t; -struct pgm_sockaddr_t; -struct pgm_addrinfo_t; -struct pgm_fecinto_t; - -#ifdef CONFIG_HAVE_POLL -# include -#endif -#ifdef CONFIG_HAVE_EPOLL -# include -#endif -#ifndef _WIN32 -# include -# include -#endif -#include -#include -#include -#include - -PGM_BEGIN_DECLS - -struct pgm_sockaddr_t { - uint16_t sa_port; /* data-destination port */ - pgm_tsi_t sa_addr; -}; - -struct pgm_addrinfo_t { - sa_family_t ai_family; - uint32_t ai_recv_addrs_len; - struct group_source_req* restrict ai_recv_addrs; - uint32_t ai_send_addrs_len; - struct group_source_req* restrict ai_send_addrs; -}; - -struct pgm_interface_req_t { - uint32_t ir_interface; - uint32_t ir_scope_id; -}; - -struct pgm_fecinfo_t { - uint8_t block_size; - uint8_t proactive_packets; - uint8_t group_size; - bool ondemand_parity_enabled; - bool var_pktlen_enabled; -}; - -struct pgm_pgmccinfo_t { - uint32_t ack_bo_ivl; - uint32_t ack_c; - uint32_t ack_c_p; -}; - -/* socket options */ -enum { - PGM_RECV_SOCK, - PGM_REPAIR_SOCK, - PGM_PENDING_SOCK, - PGM_ACK_SOCK, - PGM_TIME_REMAIN, - PGM_RATE_REMAIN, - PGM_IP_ROUTER_ALERT, - PGM_MTU, - PGM_MULTICAST_LOOP, - PGM_MULTICAST_HOPS, - PGM_TOS, - PGM_SNDBUF, - PGM_RCVBUF, - PGM_AMBIENT_SPM, - PGM_HEARTBEAT_SPM, - PGM_TXW_SQNS, - PGM_TXW_SECS, - PGM_TXW_MAX_RTE, - PGM_PEER_EXPIRY, - PGM_SPMR_EXPIRY, - PGM_RXW_SQNS, - PGM_RXW_SECS, - PGM_RXW_MAX_RTE, - PGM_NAK_BO_IVL, - PGM_NAK_RPT_IVL, - PGM_NAK_RDATA_IVL, - PGM_NAK_DATA_RETRIES, - PGM_NAK_NCF_RETRIES, - PGM_USE_FEC, - PGM_USE_CR, - PGM_USE_PGMCC, - PGM_SEND_ONLY, - PGM_RECV_ONLY, - PGM_PASSIVE, - PGM_ABORT_ON_RESET, - PGM_NOBLOCK, - PGM_SEND_GROUP, - PGM_JOIN_GROUP, - PGM_LEAVE_GROUP, - PGM_BLOCK_SOURCE, - PGM_UNBLOCK_SOURCE, - PGM_JOIN_SOURCE_GROUP, - PGM_LEAVE_SOURCE_GROUP, - PGM_MSFILTER, - PGM_UDP_ENCAP_UCAST_PORT, - PGM_UDP_ENCAP_MCAST_PORT -}; - -/* IO status */ -enum { - PGM_IO_STATUS_ERROR, /* an error occurred */ - PGM_IO_STATUS_NORMAL, /* success */ - PGM_IO_STATUS_RESET, /* session reset */ - PGM_IO_STATUS_FIN, /* session finished */ - PGM_IO_STATUS_EOF, /* socket closed */ - PGM_IO_STATUS_WOULD_BLOCK, /* resource temporarily unavailable */ - PGM_IO_STATUS_RATE_LIMITED, /* would-block on rate limit, check timer */ - PGM_IO_STATUS_TIMER_PENDING, /* would-block with pending timer */ - PGM_IO_STATUS_CONGESTION /* would-block waiting on ACK or timeout */ -}; - -bool pgm_socket (pgm_sock_t**restrict, const sa_family_t, const int, const int, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; -bool pgm_bind (pgm_sock_t*restrict, const struct pgm_sockaddr_t*const restrict, const socklen_t, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; -bool pgm_bind3 (pgm_sock_t*restrict, const struct pgm_sockaddr_t*const restrict, const socklen_t, const struct pgm_interface_req_t*const, const socklen_t, const struct pgm_interface_req_t*const, const socklen_t, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; -bool pgm_connect (pgm_sock_t*restrict, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; -bool pgm_close (pgm_sock_t*, bool); -bool pgm_setsockopt (pgm_sock_t*const restrict, const int, const void*restrict, const socklen_t); -bool pgm_getsockopt (pgm_sock_t*const restrict, const int, void*restrict, socklen_t*restrict); -bool pgm_getaddrinfo (const char*restrict, const struct pgm_addrinfo_t*restrict, struct pgm_addrinfo_t**restrict, pgm_error_t**restrict); -void pgm_freeaddrinfo (struct pgm_addrinfo_t*); -int pgm_send (pgm_sock_t*const restrict, const void*restrict, const size_t, size_t*restrict); -int pgm_sendv (pgm_sock_t*const restrict, const struct pgm_iovec*const restrict, const unsigned, const bool, size_t*restrict); -int pgm_send_skbv (pgm_sock_t*const restrict, struct pgm_sk_buff_t**restrict, const unsigned, const bool, size_t*restrict); -int pgm_recvmsg (pgm_sock_t*const restrict, struct pgm_msgv_t*const restrict, const int, size_t*restrict, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; -int pgm_recvmsgv (pgm_sock_t*const restrict, struct pgm_msgv_t*const restrict, const size_t, const int, size_t*restrict, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; -int pgm_recv (pgm_sock_t*const restrict, void*restrict, const size_t, const int, size_t*const restrict, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; -int pgm_recvfrom (pgm_sock_t*const restrict, void*restrict, const size_t, const int, size_t*restrict, struct pgm_sockaddr_t*restrict, socklen_t*restrict, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; - -bool pgm_getsockname (pgm_sock_t*const restrict, struct pgm_sockaddr_t*restrict, socklen_t*restrict); -int pgm_select_info (pgm_sock_t*const restrict, fd_set*const restrict, fd_set*const restrict, int*const restrict); -#ifdef CONFIG_HAVE_POLL -int pgm_poll_info (pgm_sock_t*const restrict, struct pollfd*const restrict, int*const restrict, const int); -#endif -#ifdef CONFIG_HAVE_EPOLL -int pgm_epoll_ctl (pgm_sock_t*const, const int, const int, const int); -#endif - -PGM_END_DECLS - -#endif /* __PGM_SOCKET_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/time.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/time.h deleted file mode 100644 index 2fd3898..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/time.h +++ /dev/null @@ -1,54 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * high resolution timers. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_TIME_H__ -#define __PGM_TIME_H__ - -#include - -PGM_BEGIN_DECLS - -typedef uint64_t pgm_time_t; -typedef void (*pgm_time_since_epoch_func)(const pgm_time_t*const restrict, time_t*restrict); - -#define pgm_to_secs(t) ((uint64_t)( (t) / 1000000UL )) -#define pgm_to_msecs(t) ((uint64_t)( (t) / 1000UL )) -#define pgm_to_usecs(t) ( (t) ) -#define pgm_to_nsecs(t) ((uint64_t)( (t) * 1000UL )) - -#define pgm_to_secsf(t) ( (double)(t) / 1000000.0 ) -#define pgm_to_msecsf(t) ( (double)(t) / 1000.0 ) -#define pgm_to_usecsf(t) ( (double)(t) ) -#define pgm_to_nsecsf(t) ( (double)(t) * 1000.0 ) - -#define pgm_secs(t) ((uint64_t)( (uint64_t)(t) * 1000000UL )) -#define pgm_msecs(t) ((uint64_t)( (uint64_t)(t) * 1000UL )) -#define pgm_usecs(t) ((uint64_t)( (t) )) -#define pgm_nsecs(t) ((uint64_t)( (t) / 1000UL )) - -#define PGM_TIME_FORMAT PRIu64 - -extern pgm_time_since_epoch_func pgm_time_since_epoch; - -PGM_END_DECLS - -#endif /* __PGM_TIME_H__ */ - diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/tsi.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/tsi.h deleted file mode 100644 index c33ea3d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/tsi.h +++ /dev/null @@ -1,47 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * transport session ID helper functions - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_TSI_H__ -#define __PGM_TSI_H__ - -typedef struct pgm_tsi_t pgm_tsi_t; - -#include -#include - -PGM_BEGIN_DECLS - -/* maximum length of TSI as a string */ -#define PGM_TSISTRLEN (sizeof("000.000.000.000.000.000.00000")) -#define PGM_TSI_INIT { PGM_GSI_INIT, 0 } - -struct pgm_tsi_t { - pgm_gsi_t gsi; /* global session identifier */ - uint16_t sport; /* source port: a random number to help detect session re-starts */ -}; - -char* pgm_tsi_print (const pgm_tsi_t*) PGM_GNUC_WARN_UNUSED_RESULT; -int pgm_tsi_print_r (const pgm_tsi_t*restrict, char*restrict, size_t); -bool pgm_tsi_equal (const void*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; - -PGM_END_DECLS - -#endif /* __PGM_TSI_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/types.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/types.h deleted file mode 100644 index 6c1c81b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/types.h +++ /dev/null @@ -1,56 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Cross-platform data types. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_TYPES_H__ -#define __PGM_TYPES_H__ - -#ifndef _MSC_VER -# include -#endif -#include - -#ifdef _WIN32 -# include -# define sa_family_t ULONG -#endif - -#ifdef _MSC_VER -# include -# define bool BOOL -# define ssize_t SSIZE_T -# define restrict -#elif !defined( __cplusplus) || (__GNUC__ >= 4) -/* g++ v4 handles C99 headers without complaints */ -# include -# include -#else -/* g++ v3 and other ancient compilers */ -# define bool int -# include -#endif - -PGM_BEGIN_DECLS - -/* nc */ - -PGM_END_DECLS - -#endif /* __PGM_TYPES_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/version.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/version.h deleted file mode 100644 index 7928450..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/version.h +++ /dev/null @@ -1,41 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * OpenPGM version. - * - * Copyright (c) 2006-2008 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_VERSION_H__ -#define __PGM_VERSION_H__ - -#include - -PGM_BEGIN_DECLS - -extern const unsigned pgm_major_version; -extern const unsigned pgm_minor_version; -extern const unsigned pgm_micro_version; - -extern const char* pgm_build_date; -extern const char* pgm_build_time; -extern const char* pgm_build_system; -extern const char* pgm_build_machine; -extern const char* pgm_build_revision; - -PGM_END_DECLS - -#endif /* __PGM_VERSION_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/winint.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/winint.h deleted file mode 100644 index 0205cdf..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/winint.h +++ /dev/null @@ -1,198 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * stdint.h for Win32 & Win64 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_WININT_H__ -#define __PGM_WININT_H__ - -#include - -/* 7.18.1.1 Exact-width integer types */ -typedef signed __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef signed __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef signed __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef signed __int64 int64_t; -typedef unsigned __int64 uint64_t; - -/* 7.18.1.2 Minimum-width integer types */ -typedef int8_t int_least8_t; -typedef uint8_t uint_least8_t; -typedef int16_t int_least16_t; -typedef uint16_t uint_least16_t; -typedef int32_t int_least32_t; -typedef uint32_t uint_least32_t; -typedef int64_t int_least64_t; -typedef uint64_t uint_least64_t; - -/* 7.18.1.3 Fastest minimum-width integer types - * Not actually guaranteed to be fastest for all purposes - * Here we use the exact-width types for 8 and 16-bit ints. - */ -typedef int8_t int_fast8_t; -typedef uint8_t uint_fast8_t; -typedef int16_t int_fast16_t; -typedef uint16_t uint_fast16_t; -typedef int32_t int_fast32_t; -typedef uint32_t uint_fast32_t; -typedef int64_t int_fast64_t; -typedef uint64_t uint_fast64_t; - -/* 7.18.1.5 Greatest-width integer types */ -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; - -/* 7.18.2 Limits of specified-width integer types */ -#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) - -/* 7.18.2.1 Limits of exact-width integer types */ -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -/* 7.18.2.2 Limits of minimum-width integer types */ -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST64_MIN INT64_MIN - -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MAX INT64_MAX - -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -/* 7.18.2.3 Limits of fastest minimum-width integer types */ -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST64_MIN INT64_MIN - -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MAX INT64_MAX - -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -/* 7.18.2.4 Limits of integer types capable of holding - object pointers */ -#ifdef _WIN64 -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif - -/* 7.18.2.5 Limits of greatest-width integer types */ -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -/* 7.18.3 Limits of other integer types */ -#ifdef _WIN64 -# define PTRDIFF_MIN INT64_MIN -# define PTRDIFF_MAX INT64_MAX -#else -# define PTRDIFF_MIN INT32_MIN -# define PTRDIFF_MAX INT32_MAX -#endif - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX -# ifdef _WIN64 -# define SIZE_MAX UINT64_MAX -# else -# define SIZE_MAX UINT32_MAX -# endif -#endif - -#ifndef WCHAR_MIN /* also in wchar.h */ -# define WCHAR_MIN 0U -# define WCHAR_MAX UINT16_MAX -#endif - -/* - * wint_t is unsigned short for compatibility with MS runtime - */ -#define WINT_MIN 0U -#define WINT_MAX UINT16_MAX - -#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ - - -/* 7.18.4 Macros for integer constants */ -#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) - -/* 7.18.4.1 Macros for minimum-width integer constants - - Accoding to Douglas Gwyn : - "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC - 9899:1999 as initially published, the expansion was required - to be an integer constant of precisely matching type, which - is impossible to accomplish for the shorter types on most - platforms, because C99 provides no standard way to designate - an integer constant with width less than that of type int. - TC1 changed this to require just an integer constant - *expression* with *promoted* type." - - The trick used here is from Clive D W Feather. -*/ - -#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val)) -#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val)) -#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val)) -/* The 'trick' doesn't work in C89 for long long because, without - suffix, (val) will be evaluated as int, not intmax_t */ -#define INT64_C(val) val##LL - -#define UINT8_C(val) (val) -#define UINT16_C(val) (val) -#define UINT32_C(val) (val##U) -#define UINT64_C(val) val##ULL - -/* 7.18.4.2 Macros for greatest-width integer constants */ -#define INTMAX_C(val) val##LL -#define UINTMAX_C(val) val##ULL - -#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ - -#endif /* __PGM_WININT_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/wininttypes.h b/3rdparty/openpgm-svn-r1085/pgm/include/pgm/wininttypes.h deleted file mode 100644 index 5daa7f1..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/include/pgm/wininttypes.h +++ /dev/null @@ -1,254 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * inttypes.h for Win32 & Win64 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_WININTTYPES_H__ -#define __PGM_WININTTYPES_H__ - -#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) - -/* 7.8.1 Macros for format specifiers - * - * MS runtime does not yet understand C9x standard "ll" - * length specifier. It appears to treat "ll" as "l". - * The non-standard I64 length specifier causes warning in GCC, - * but understood by MS runtime functions. - */ - -/* fprintf macros for signed types */ -#define PRId8 "d" -#define PRId16 "hd" -#define PRId32 "I32d" -#define PRId64 "I64d" - -#define PRIdLEAST8 "d" -#define PRIdLEAST16 "hd" -#define PRIdLEAST32 "I32d" -#define PRIdLEAST64 "I64d" - -#define PRIdFAST8 "d" -#define PRIdFAST16 "hd" -#define PRIdFAST32 "I32d" -#define PRIdFAST64 "I64d" - -#define PRIdMAX "I64d" - -#define PRIi8 "i" -#define PRIi16 "hi" -#define PRIi32 "i" -#define PRIi64 "I64i" - -#define PRIiLEAST8 "i" -#define PRIiLEAST16 "hi" -#define PRIiLEAST32 "I32i" -#define PRIiLEAST64 "I64i" - -#define PRIiFAST8 "i" -#define PRIiFAST16 "hi" -#define PRIiFAST32 "I32i" -#define PRIiFAST64 "I64i" - -#define PRIiMAX "I64i" - -#define PRIo8 "o" -#define PRIo16 "ho" -#define PRIo32 "I32o" -#define PRIo64 "I64o" - -#define PRIoLEAST8 "o" -#define PRIoLEAST16 "ho" -#define PRIoLEAST32 "I32o" -#define PRIoLEAST64 "I64o" - -#define PRIoFAST8 "o" -#define PRIoFAST16 "ho" -#define PRIoFAST32 "o" -#define PRIoFAST64 "I64o" - -#define PRIoMAX "I64o" - -/* fprintf macros for unsigned types */ -#define PRIu8 "u" -#define PRIu16 "hu" -#define PRIu32 "I32u" -#define PRIu64 "I64u" - -#define PRIuLEAST8 "u" -#define PRIuLEAST16 "hu" -#define PRIuLEAST32 "I32u" -#define PRIuLEAST64 "I64u" - -#define PRIuFAST8 "u" -#define PRIuFAST16 "hu" -#define PRIuFAST32 "I32u" -#define PRIuFAST64 "I64u" - -#define PRIuMAX "I64u" - -#define PRIx8 "x" -#define PRIx16 "hx" -#define PRIx32 "I32x" -#define PRIx64 "I64x" - -#define PRIxLEAST8 "x" -#define PRIxLEAST16 "hx" -#define PRIxLEAST32 "I32x" -#define PRIxLEAST64 "I64x" - -#define PRIxFAST8 "x" -#define PRIxFAST16 "hx" -#define PRIxFAST32 "I32x" -#define PRIxFAST64 "I64x" - -#define PRIxMAX "I64x" - -#define PRIX8 "X" -#define PRIX16 "hX" -#define PRIX32 "I32X" -#define PRIX64 "I64X" - -#define PRIXLEAST8 "X" -#define PRIXLEAST16 "hX" -#define PRIXLEAST32 "I32X" -#define PRIXLEAST64 "I64X" - -#define PRIXFAST8 "X" -#define PRIXFAST16 "hX" -#define PRIXFAST32 "I32X" -#define PRIXFAST64 "I64X" - -#define PRIXMAX "I64X" - -/* fscanf macros for signed int types */ - -#define SCNd8 "hhd" -#define SCNd16 "hd" -#define SCNd32 "ld" -#define SCNd64 "I64d" - -#define SCNdLEAST8 "hhd" -#define SCNdLEAST16 "hd" -#define SCNdLEAST32 "ld" -#define SCNdLEAST64 "I64d" - -#define SCNdFAST8 "hhd" -#define SCNdFAST16 "hd" -#define SCNdFAST32 "ld" -#define SCNdFAST64 "I64d" - -#define SCNdMAX "I64d" - -#define SCNi8 "hhi" -#define SCNi16 "hi" -#define SCNi32 "li" -#define SCNi64 "I64i" - -#define SCNiLEAST8 "hhi" -#define SCNiLEAST16 "hi" -#define SCNiLEAST32 "li" -#define SCNiLEAST64 "I64i" - -#define SCNiFAST8 "hhi" -#define SCNiFAST16 "hi" -#define SCNiFAST32 "li" -#define SCNiFAST64 "I64i" - -#define SCNiMAX "I64i" - -#define SCNo8 "hho" -#define SCNo16 "ho" -#define SCNo32 "lo" -#define SCNo64 "I64o" - -#define SCNoLEAST8 "hho" -#define SCNoLEAST16 "ho" -#define SCNoLEAST32 "lo" -#define SCNoLEAST64 "I64o" - -#define SCNoFAST8 "hho" -#define SCNoFAST16 "ho" -#define SCNoFAST32 "lo" -#define SCNoFAST64 "I64o" - -#define SCNoMAX "I64o" - -#define SCNx8 "hhx" -#define SCNx16 "hx" -#define SCNx32 "lx" -#define SCNx64 "I64x" - -#define SCNxLEAST8 "hhx" -#define SCNxLEAST16 "hx" -#define SCNxLEAST32 "lx" -#define SCNxLEAST64 "I64x" - -#define SCNxFAST8 "hhx" -#define SCNxFAST16 "hx" -#define SCNxFAST32 "lx" -#define SCNxFAST64 "I64x" - -#define SCNxMAX "I64x" - -/* fscanf macros for unsigned int types */ - -#define SCNu8 "hhu" -#define SCNu16 "hu" -#define SCNu32 "lu" -#define SCNu64 "I64u" - -#define SCNuLEAST8 "hhu" -#define SCNuLEAST16 "hu" -#define SCNuLEAST32 "lu" -#define SCNuLEAST64 "I64u" - -#define SCNuFAST8 "hhu" -#define SCNuFAST16 "hu" -#define SCNuFAST32 "lu" -#define SCNuFAST64 "I64u" - -#define SCNuMAX "I64u" - -#ifdef _WIN64 -# define PRIdPTR "I64d" -# define PRIiPTR "I64i" -# define PRIoPTR "I64o" -# define PRIuPTR "I64u" -# define PRIxPTR "I64x" -# define PRIXPTR "I64X" -# define SCNdPTR "I64d" -# define SCNiPTR "I64i" -# define SCNoPTR "I64o" -# define SCNxPTR "I64x" -# define SCNuPTR "I64u" -#else -# define PRIdPTR "ld" -# define PRIiPTR "li" -# define PRIoPTR "lo" -# define PRIuPTR "lu" -# define PRIxPTR "lx" -# define PRIXPTR "lX" -# define SCNdPTR "ld" -# define SCNiPTR "li" -# define SCNoPTR "lo" -# define SCNxPTR "lx" -# define SCNuPTR "lu" -#endif - -#endif /* !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) */ - -#endif /* __PGM_WININTTYPES_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/indextoaddr.c b/3rdparty/openpgm-svn-r1085/pgm/indextoaddr.c deleted file mode 100644 index 479dffd..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/indextoaddr.c +++ /dev/null @@ -1,98 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable interface index to socket address function. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - - -//#define INDEXTOADDR_DEBUG - - -/* interfaces indexes refer to the link layer, we want to find the internet layer address. - * the big problem is that multiple IPv6 addresses can be bound to one link - called scopes. - * we can just pick the first scope and let IP routing handle the rest. - */ - -bool -pgm_if_indextoaddr ( - const unsigned ifindex, - const sa_family_t iffamily, - const uint32_t ifscope, - struct sockaddr* restrict ifsa, - pgm_error_t** restrict error - ) -{ - pgm_return_val_if_fail (NULL != ifsa, FALSE); - - if (0 == ifindex) /* any interface or address */ - { - ifsa->sa_family = iffamily; - switch (iffamily) { - case AF_INET: - ((struct sockaddr_in*)ifsa)->sin_addr.s_addr = INADDR_ANY; - break; - - case AF_INET6: - ((struct sockaddr_in6*)ifsa)->sin6_addr = in6addr_any; - break; - - default: - pgm_return_val_if_reached (FALSE); - break; - } - return TRUE; - } - - struct pgm_ifaddrs_t *ifap, *ifa; - if (!pgm_getifaddrs (&ifap, error)) { - pgm_prefix_error (error, - _("Enumerating network interfaces: ")); - return FALSE; - } - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) - { - if (NULL == ifa->ifa_addr || - ifa->ifa_addr->sa_family != iffamily) - continue; - - const unsigned i = pgm_if_nametoindex (iffamily, ifa->ifa_name); - pgm_assert (0 != i); - if (i == ifindex) - { - if (ifscope && ifscope != pgm_sockaddr_scope_id (ifa->ifa_addr)) - continue; - memcpy (ifsa, ifa->ifa_addr, pgm_sockaddr_len(ifa->ifa_addr)); - pgm_freeifaddrs (ifap); - return TRUE; - } - } - - pgm_set_error (error, - PGM_ERROR_DOMAIN_IF, - PGM_ERROR_NODEV, - _("No matching network interface index: %i"), - ifindex); - pgm_freeifaddrs (ifap); - return FALSE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/indextoaddr_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/indextoaddr_unittest.c deleted file mode 100644 index 57222d1..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/indextoaddr_unittest.c +++ /dev/null @@ -1,302 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for portable interface index to socket address function. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* IFF_UP */ -#define _BSD_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -/* mock state */ - -struct mock_interface_t { - unsigned int index; - char* name; - unsigned int flags; - struct sockaddr_storage addr; - struct sockaddr_storage netmask; -}; - -static GList *mock_interfaces = NULL; - -struct pgm_ifaddrs_t; -struct pgm_error_t; - -static bool mock_pgm_getifaddrs (struct pgm_ifaddrs_t**, struct pgm_error_t**); -static void mock_pgm_freeifaddrs (struct pgm_ifaddrs_t*); -static unsigned mock_pgm_if_nametoindex (const sa_family_t, const char*); - - -#define pgm_getifaddrs mock_pgm_getifaddrs -#define pgm_freeifaddrs mock_pgm_freeifaddrs -#define pgm_if_nametoindex mock_pgm_if_nametoindex - - -#define INDEXTOADDR_DEBUG -#include "indextoaddr.c" - - -static -gpointer -create_interface ( - const unsigned index, - const char* name, - const char* flags - ) -{ - struct mock_interface_t* new_interface; - - g_assert (name); - g_assert (flags); - - new_interface = g_slice_alloc0 (sizeof(struct mock_interface_t)); - new_interface->index = index; - new_interface->name = g_strdup (name); - - struct sockaddr_in* sin = (gpointer)&new_interface->addr; - struct sockaddr_in6* sin6 = (gpointer)&new_interface->addr; - - gchar** tokens = g_strsplit (flags, ",", 0); - for (guint i = 0; tokens[i]; i++) - { - if (strcmp (tokens[i], "up") == 0) - new_interface->flags |= IFF_UP; - else if (strcmp (tokens[i], "down") == 0) - new_interface->flags |= 0; - else if (strcmp (tokens[i], "loop") == 0) - new_interface->flags |= IFF_LOOPBACK; - else if (strcmp (tokens[i], "broadcast") == 0) - new_interface->flags |= IFF_BROADCAST; - else if (strcmp (tokens[i], "multicast") == 0) - new_interface->flags |= IFF_MULTICAST; - else if (strncmp (tokens[i], "ip=", strlen("ip=")) == 0) { - const char* addr = tokens[i] + strlen("ip="); - g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->addr)); - } - else if (strncmp (tokens[i], "netmask=", strlen("netmask=")) == 0) { - const char* addr = tokens[i] + strlen("netmask="); - g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->netmask)); - } - else if (strncmp (tokens[i], "scope=", strlen("scope=")) == 0) { - const char* scope = tokens[i] + strlen("scope="); - g_assert (AF_INET6 == ((struct sockaddr*)&new_interface->addr)->sa_family); - ((struct sockaddr_in6*)&new_interface->addr)->sin6_scope_id = atoi (scope); - } - else - g_error ("parsing failed for flag \"%s\"", tokens[i]); - } - - g_strfreev (tokens); - return new_interface; -} - -#define APPEND_INTERFACE(a,b,c) \ - do { \ - gpointer data = create_interface ((a), (b), (c)); \ - g_assert (data); \ - mock_interfaces = g_list_append (mock_interfaces, data); \ - g_assert (mock_interfaces); g_assert (mock_interfaces->data); \ - } while (0) -static -void -mock_setup_net (void) -{ - APPEND_INTERFACE( 1, "lo", "up,loop"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast"); - APPEND_INTERFACE( 3, "eth1", "down,broadcast,multicast"); - APPEND_INTERFACE( 1, "lo", "up,loop,ip=127.0.0.1,netmask=255.0.0.0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=10.6.28.33,netmask=255.255.255.0"); - APPEND_INTERFACE( 1, "lo", "up,loop,ip=::1,netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,scope=0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=2002:dce8:d28e::33,netmask=ffff:ffff:ffff:ffff::0,scope=0"); - APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=fe80::214:5eff:febd:6dda,netmask=ffff:ffff:ffff:ffff::0,scope=2"); -} - -static -void -mock_teardown_net (void) -{ - GList* list; - - list = mock_interfaces; - while (list) { - struct mock_interface_t* interface = list->data; - g_free (interface->name); - g_slice_free1 (sizeof(struct mock_interface_t), interface); - list = list->next; - } - g_list_free (mock_interfaces); -} - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - -bool -mock_pgm_getifaddrs ( - struct pgm_ifaddrs_t** ifap, - pgm_error_t** err - ) -{ - if (NULL == ifap) { - return FALSE; - } - - g_debug ("mock_getifaddrs (ifap:%p err:%p)", (gpointer)ifap, (gpointer)err); - - GList* list = mock_interfaces; - int n = g_list_length (list); - struct pgm_ifaddrs_t* ifa = calloc (n, sizeof(struct pgm_ifaddrs_t)); - struct pgm_ifaddrs_t* ift = ifa; - while (list) { - struct mock_interface_t* interface = list->data; - ift->ifa_addr = (gpointer)&interface->addr; - ift->ifa_name = interface->name; - ift->ifa_flags = interface->flags; - ift->ifa_netmask = (gpointer)&interface->netmask; - list = list->next; - if (list) { - ift->ifa_next = ift + 1; - ift = ift->ifa_next; - } - } - - *ifap = ifa; - return TRUE; -} - -static -void -mock_pgm_freeifaddrs ( - struct pgm_ifaddrs_t* ifa - ) -{ - g_debug ("mock_freeifaddrs (ifa:%p)", (gpointer)ifa); - free (ifa); -} - -unsigned -mock_pgm_if_nametoindex ( - const sa_family_t iffamily, - const char* ifname - ) -{ - GList* list = mock_interfaces; - while (list) { - const struct mock_interface_t* interface = list->data; - if (0 == strcmp (ifname, interface->name)) - return interface->index; - list = list->next; - } - return 0; -} - - -/* target: - * bool - * pgm_if_indextoaddr ( - * const unsigned ifindex, - * const sa_family_t iffamily, - * const uint32_t ifscope, - * struct sockaddr* ifsa, - * pgm_error_t** error - * ) - */ - -START_TEST (test_indextoaddr_pass_001) -{ - char saddr[INET6_ADDRSTRLEN]; - struct sockaddr_storage addr; - pgm_error_t* err = NULL; - const unsigned int ifindex = 2; - fail_unless (TRUE == pgm_if_indextoaddr (ifindex, AF_INET, 0, (struct sockaddr*)&addr, &err)); - pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); - g_message ("index:%d -> %s", - ifindex, saddr); - fail_unless (TRUE == pgm_if_indextoaddr (ifindex, AF_INET6, 0, (struct sockaddr*)&addr, &err)); - pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); - g_message ("index:%d -> %s", - ifindex, saddr); -} -END_TEST - -START_TEST (test_indextoaddr_fail_001) -{ - pgm_error_t* err = NULL; - fail_unless (FALSE == pgm_if_indextoaddr (0, 0, 0, NULL, &err)); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_indextoaddr = tcase_create ("init-ctx"); - suite_add_tcase (s, tc_indextoaddr); - tcase_add_checked_fixture (tc_indextoaddr, mock_setup_net, mock_teardown_net); - tcase_add_test (tc_indextoaddr, test_indextoaddr_pass_001); - tcase_add_test (tc_indextoaddr, test_indextoaddr_fail_001); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/indextoname.c b/3rdparty/openpgm-svn-r1085/pgm/indextoname.c deleted file mode 100644 index c4043ef..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/indextoname.c +++ /dev/null @@ -1,52 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Windows interface index to interface name function. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef _WIN32 -# include -# include -#endif -#include - - -//#define INDEXTONAME_DEBUG - - -char* -pgm_if_indextoname ( - unsigned int ifindex, - char* ifname - ) -{ -#ifndef _WIN32 - return if_indextoname (ifindex, ifname); -#else - pgm_return_val_if_fail (NULL != ifname, NULL); - - MIB_IFROW ifRow = { .dwIndex = ifindex }; - const DWORD dwRetval = GetIfEntry (&ifRow); - if (NO_ERROR != dwRetval) - return NULL; - strcpy (ifname, (char*)ifRow.wszName); - return ifname; -#endif /* _WIN32 */ -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/inet_network.c b/3rdparty/openpgm-svn-r1085/pgm/inet_network.c deleted file mode 100644 index 8cac34b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/inet_network.c +++ /dev/null @@ -1,237 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable implementations of inet_network and inet_network6. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - - -//#define INET_NETWORK_DEBUG - -/* locals */ - -static uint32_t cidr_to_netmask (const unsigned) PGM_GNUC_CONST; - - -/* calculate IPv4 netmask from network size, returns address in - * host byte order. - */ - -static -uint32_t -cidr_to_netmask ( - const unsigned cidr - ) -{ - return (cidr == 0) ? 0 : (0xffffffff - (1 << (32 - cidr)) + 1); -} - - -/* Converts a numbers-and-dots notation string into a network number in - * host order. - * Note parameters and return value differs from inet_network(). This - * function will not interpret octal numbers, preceeded with a 0, or - * hexadecimal numbers, preceeded by 0x. - * - * 127 => 127.0.0.0 - * 127.1/8 => 127.0.0.0 -- 127.1.0.0 - * inet_addr() would be 127.0.0.1 - * inet_network() would be 0.0.127.1 - * - * returns 0 on success, returns -1 on invalid address. - */ - -int /* return type to match inet_network() */ -pgm_inet_network ( - const char* restrict s, - struct in_addr* restrict in - ) -{ - pgm_return_val_if_fail (NULL != s, -1); - pgm_return_val_if_fail (NULL != in, -1); - - pgm_debug ("pgm_inet_network (s:\"%s\" in:%p)", - s, (const void*)in); - - const char *p = s; - unsigned val = 0; - int shift = 24; - - in->s_addr = INADDR_ANY; - - while (*p) - { - if (isdigit (*p)) { - val = 10 * val + (*p - '0'); - } else if (*p == '.' || *p == 0) { - if (val > 0xff) { - in->s_addr = INADDR_NONE; - return -1; - } - -//g_trace ("elem %i", val); - - in->s_addr |= val << shift; - val = 0; - shift -= 8; - if (shift < 0 && *p != 0) { - in->s_addr = INADDR_NONE; - return -1; - } - - } else if (*p == '/') { - if (val > 0xff) { - in->s_addr = INADDR_NONE; - return -1; - } -//g_trace ("elem %i", val); - in->s_addr |= val << shift; - p++; val = 0; - while (*p) - { - if (isdigit (*p)) { - val = 10 * val + (*p - '0'); - } else { - in->s_addr = INADDR_NONE; - return -1; - } - p++; - } - if (val == 0 || val > 32) { - in->s_addr = INADDR_NONE; - return -1; - } -//g_trace ("bit mask %i", val); - -/* zero out host bits */ - const struct in_addr netaddr = { .s_addr = cidr_to_netmask (val) }; -#ifdef INET_NETWORK_DEBUG -{ -g_debug ("netaddr %s", inet_ntoa (netaddr)); -} -#endif - in->s_addr &= netaddr.s_addr; - return 0; - - } else if (*p == 'x' || *p == 'X') { /* skip number, e.g. 1.x.x.x */ - if (val > 0) { - in->s_addr = INADDR_NONE; - return -1; - } - - } else { - in->s_addr = INADDR_NONE; - return -1; - } - p++; - } - - in->s_addr |= val << shift; - return 0; -} - -/* Converts a numbers-and-dots notation string into an IPv6 network number. - * - * ::1/128 => 0:0:0:0:0:0:0:1 - * ::1 => 0:0:0:0:0:0:0:1 - * ::1.2.3.4 => 0:0:0:0:1.2.3.4 - * - * returns 0 on success, returns -1 on invalid address. - */ - -int -pgm_inet6_network ( - const char* restrict s, /* NULL terminated */ - struct in6_addr* restrict in6 - ) -{ - pgm_return_val_if_fail (NULL != s, -1); - pgm_return_val_if_fail (NULL != in6, -1); - - pgm_debug ("pgm_inet6_network (s:\"%s\" in6:%p)", - s, (const void*)in6); - -/* inet_pton cannot parse IPv6 addresses with subnet declarations, so - * chop them off. - * - * as we are dealing with network addresses IPv6 zone indices are not important - * so we can use the inet_xtoy functions. - */ - char s2[INET6_ADDRSTRLEN]; - const char *p = s; - char* p2 = s2; - while (*p) { - if (*p == '/') break; - *p2++ = *p++; - } - if (*p == 0) { - if (pgm_inet_pton (AF_INET6, s, in6)) return 0; - pgm_debug ("pgm_inet_pton(AF_INET6) failed on '%s'", s); - memcpy (in6, &in6addr_any, sizeof(in6addr_any)); - return -1; - } - - *p2 = 0; - pgm_debug ("net part %s", s2); - if (!pgm_inet_pton (AF_INET6, s2, in6)) { - pgm_debug ("pgm_inet_pton(AF_INET) failed parsing network part '%s'", s2); - memcpy (in6, &in6addr_any, sizeof(in6addr_any)); - return -1; - } - -#ifdef INET_NETWORK_DEBUG - char sdebug[INET6_ADDRSTRLEN]; - pgm_debug ("IPv6 network address: %s", pgm_inet_ntop(AF_INET6, in6, sdebug, sizeof(sdebug))); -#endif - - p++; - unsigned val = 0; - while (*p) - { - if (isdigit(*p)) { - val = 10 * val + (*p - '0'); - } else { - pgm_debug ("failed parsing subnet size due to character '%c'", *p); - memcpy (in6, &in6addr_any, sizeof(in6addr_any)); - return -1; - } - p++; - } - if (val == 0 || val > 128) { - pgm_debug ("subnet size invalid (%d)", val); - memcpy (in6, &in6addr_any, sizeof(in6addr_any)); - return -1; - } - pgm_debug ("subnet size %i", val); - -/* zero out host bits */ - const unsigned suffix_length = 128 - val; - for (int i = suffix_length, j = 15; i > 0; i -= 8, --j) - { - in6->s6_addr[ j ] &= i >= 8 ? 0x00 : (unsigned)(( 0xffU << i ) & 0xffU ); - } - - pgm_debug ("effective IPv6 network address after subnet mask: %s", pgm_inet_ntop(AF_INET6, in6, s2, sizeof(s2))); - - return 0; -} - -/* eof */ - diff --git a/3rdparty/openpgm-svn-r1085/pgm/inet_network_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/inet_network_unittest.c deleted file mode 100644 index 2739215..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/inet_network_unittest.c +++ /dev/null @@ -1,203 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for portable implementations of inet_network and inet_network6. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -/* mock state */ - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - - -#define INET_NETWORK_DEBUG -#include "inet_network.c" - - -/* target: - * int - * pgm_inet_network ( - * const char* s, - * struct in_addr* in -- in host byte order - * ) - */ - -struct test_case_t { - const char* network; - const char* answer; -}; - -static const struct test_case_t cases_001[] = { - { "127", "127.0.0.0" }, /* different to inet_addr/inet_network */ - { "127/8", "127.0.0.0" }, - { "127.1/8", "127.0.0.0" }, - { "127.1", "127.1.0.0" }, /* different to inet_addr/inet_network */ - { "127.x.x.x", "127.0.0.0" }, - { "127.X.X.X", "127.0.0.0" }, - { "127.0.0.0", "127.0.0.0" }, - { "127.0.0.1/8", "127.0.0.0" }, - { "127.0.0.1/32", "127.0.0.1" }, - { "10.0.0.0/8", "10.0.0.0" }, /* RFC1918 class A */ - { "10.255.255.255/8", "10.0.0.0" }, - { "172.16.0.0/12", "172.16.0.0" }, /* RFC1918 class B */ - { "172.31.255.255/12", "172.16.0.0" }, - { "192.168.0.0/16", "192.168.0.0" }, /* RFC1918 class C */ - { "192.168.255.255/16", "192.168.0.0" }, - { "169.254.0.0/16", "169.254.0.0" }, /* RFC3927 link-local */ - { "192.88.99.0/24", "192.88.99.0" }, /* RFC3068 6to4 relay anycast */ - { "224.0.0.0/4", "224.0.0.0" }, /* RFC3171 multicast */ - { "0.0.0.0", "0.0.0.0" }, - { "255.255.255.255", "255.255.255.255" }, -}; - -START_TEST (test_inet_network_pass_001) -{ - const char* network = cases_001[_i].network; - const char* answer = cases_001[_i].answer; - - struct in_addr host_order, network_order; - fail_unless (0 == pgm_inet_network (network, &host_order)); - network_order.s_addr = g_htonl (host_order.s_addr); - - g_message ("Resolved \"%s\" to \"%s\"", - network, inet_ntoa (network_order)); - -{ -struct in_addr t = { .s_addr = g_htonl (inet_network (network)) }; -g_message ("inet_network (%s) = %s", network, inet_ntoa (t)); -} - - fail_unless (0 == strcmp (answer, inet_ntoa (network_order))); -} -END_TEST - -START_TEST (test_inet_network_fail_001) -{ - fail_unless (-1 == pgm_inet_network (NULL, NULL)); -} -END_TEST - -START_TEST (test_inet_network_fail_002) -{ - const char* network = "192.168.0.1/0"; - - struct in_addr host_order; - fail_unless (-1 == pgm_inet_network (network, &host_order)); -} -END_TEST - -/* target: - * int - * pgm_inet6_network ( - * const char* s, - * struct in6_addr* in6 - * ) - */ - -static const struct test_case_t cases6_001[] = { - { "::1/128", "::1" }, - { "2002:dec8:d28e::36/64", "2002:dec8:d28e::" }, /* 6to4 */ - { "fe80::203:baff:fe4e:6cc8/10", "fe80::" }, /* link-local */ - { "ff02::1/8", "ff00::" }, /* multicast */ - { "fc00:6::61/7", "fc00::" }, /* ULA */ -}; - -START_TEST (test_inet6_network_pass_001) -{ - const char* network = cases6_001[_i].network; - const char* answer = cases6_001[_i].answer; - - char snetwork[INET6_ADDRSTRLEN]; - struct in6_addr addr; - fail_unless (0 == pgm_inet6_network (network, &addr)); - g_message ("Resolved \"%s\" to \"%s\"", - network, pgm_inet_ntop (AF_INET6, &addr, snetwork, sizeof(snetwork))); - - fail_unless (0 == strcmp (answer, snetwork)); -} -END_TEST - -START_TEST (test_inet6_network_fail_001) -{ - fail_unless (-1 == pgm_inet6_network (NULL, NULL)); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_inet_network = tcase_create ("inet-network"); - suite_add_tcase (s, tc_inet_network); - tcase_add_loop_test (tc_inet_network, test_inet_network_pass_001, 0, G_N_ELEMENTS(cases_001)); - tcase_add_test (tc_inet_network, test_inet_network_fail_001); - - TCase* tc_inet6_network = tcase_create ("inet6-network"); - suite_add_tcase (s, tc_inet6_network); - tcase_add_loop_test (tc_inet6_network, test_inet6_network_pass_001, 0, G_N_ELEMENTS(cases6_001)); - tcase_add_test (tc_inet6_network, test_inet6_network_fail_001); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/ip_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/ip_unittest.c deleted file mode 100644 index 48bb601..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/ip_unittest.c +++ /dev/null @@ -1,362 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for ip stack. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -/* getsockopt(3SOCKET) - * level is the protocol number of the protocl that controls the option. - */ -#ifndef SOL_IP -# define SOL_IP IPPROTO_IP -#endif -#ifndef SOL_IPV6 -# define SOL_IPV6 IPPROTO_IPV6 -#endif - -/* mock state */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - - -#define PGM_COMPILATION -#include "impl/sockaddr.h" -#include "impl/indextoaddr.h" -#include "impl/ip.h" - - -/* target: - * testing platform capability to loop send multicast packets to a listening - * receive socket. - */ - -START_TEST (test_multicast_loop_pass_001) -{ - struct sockaddr_in addr; - memset (&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr ("239.192.0.1"); - - int recv_sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); - fail_if (-1 == recv_sock, "socket failed"); - struct sockaddr_in recv_addr; - memcpy (&recv_addr, &addr, sizeof(addr)); - recv_addr.sin_port = 7500; - fail_unless (0 == bind (recv_sock, (struct sockaddr*)&recv_addr, pgm_sockaddr_len ((struct sockaddr*)&recv_addr)), "bind failed"); - struct group_req gr; - memset (&gr, 0, sizeof(gr)); - ((struct sockaddr*)&gr.gr_group)->sa_family = addr.sin_family; - ((struct sockaddr_in*)&gr.gr_group)->sin_addr.s_addr = addr.sin_addr.s_addr; - fail_unless (0 == setsockopt (recv_sock, SOL_IP, MCAST_JOIN_GROUP, (const char*)&gr, sizeof(gr)), "setsockopt failed"); - fail_unless (0 == pgm_sockaddr_multicast_loop (recv_sock, AF_INET, FALSE), "multicast_loop failed"); - - int send_sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); - fail_if (-1 == send_sock, "socket failed"); - struct sockaddr_in send_addr; - memcpy (&send_addr, &addr, sizeof(addr)); - fail_unless (0 == bind (send_sock, (struct sockaddr*)&send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)), "bind failed"); - struct sockaddr_in if_addr; - fail_unless (TRUE == pgm_if_indextoaddr (0, AF_INET, 0, (struct sockaddr*)&if_addr, NULL), "if_indextoaddr failed"); - fail_unless (0 == pgm_sockaddr_multicast_if (send_sock, (struct sockaddr*)&if_addr, 0), "multicast_if failed"); - fail_unless (0 == pgm_sockaddr_multicast_loop (send_sock, AF_INET, TRUE), "multicast_loop failed"); - - const char data[] = "apple pie"; - addr.sin_port = 7500; - ssize_t bytes_sent = sendto (send_sock, data, sizeof(data), 0, (struct sockaddr*)&addr, pgm_sockaddr_len ((struct sockaddr*)&addr)); - if (-1 == bytes_sent) - g_message ("sendto: %s", strerror (errno)); - fail_unless (sizeof(data) == bytes_sent, "sendto underrun"); - - char recv_data[1024]; - ssize_t bytes_read = recv (recv_sock, recv_data, sizeof(recv_data), MSG_DONTWAIT); - if (-1 == bytes_read) - g_message ("sendto: %s", strerror (errno)); - fail_unless (sizeof(data) == bytes_read, "recv underrun"); - - fail_unless (0 == close (recv_sock), "close failed"); - fail_unless (0 == close (send_sock), "close failed"); -} -END_TEST - -/* target: - * testing whether unicast bind accepts packets to multicast join on a - * different port. - */ - -START_TEST (test_port_bind_pass_001) -{ - struct sockaddr_in addr; - memset (&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr ("239.192.0.1"); - - int recv_sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); - fail_if (-1 == recv_sock, "socket failed"); - struct sockaddr_in recv_addr; - memcpy (&recv_addr, &addr, sizeof(addr)); - recv_addr.sin_port = 3056; - fail_unless (0 == bind (recv_sock, (struct sockaddr*)&recv_addr, pgm_sockaddr_len ((struct sockaddr*)&recv_addr)), "bind failed"); - struct group_req gr; - memset (&gr, 0, sizeof(gr)); - ((struct sockaddr*)&gr.gr_group)->sa_family = addr.sin_family; - ((struct sockaddr_in*)&gr.gr_group)->sin_addr.s_addr = addr.sin_addr.s_addr; - ((struct sockaddr_in*)&gr.gr_group)->sin_port = 3055; - fail_unless (0 == setsockopt (recv_sock, SOL_IP, MCAST_JOIN_GROUP, (const char*)&gr, sizeof(gr)), "setsockopt failed"); - fail_unless (0 == pgm_sockaddr_multicast_loop (recv_sock, AF_INET, FALSE), "multicast_loop failed"); - - int send_sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); - fail_if (-1 == send_sock, "socket failed"); - struct sockaddr_in send_addr; - memcpy (&send_addr, &addr, sizeof(addr)); - fail_unless (0 == bind (send_sock, (struct sockaddr*)&send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)), "bind failed"); - struct sockaddr_in if_addr; - fail_unless (TRUE == pgm_if_indextoaddr (0, AF_INET, 0, (struct sockaddr*)&if_addr, NULL), "if_indextoaddr failed"); - fail_unless (0 == pgm_sockaddr_multicast_if (send_sock, (struct sockaddr*)&if_addr, 0), "multicast_if failed"); - fail_unless (0 == pgm_sockaddr_multicast_loop (send_sock, AF_INET, TRUE), "multicast_loop failed"); - - const char data[] = "apple pie"; - addr.sin_port = 3056; - ssize_t bytes_sent = sendto (send_sock, data, sizeof(data), 0, (struct sockaddr*)&addr, pgm_sockaddr_len ((struct sockaddr*)&addr)); - if (-1 == bytes_sent) - g_message ("sendto: %s", strerror (errno)); - fail_unless (sizeof(data) == bytes_sent, "sendto underrun"); - - char recv_data[1024]; - ssize_t bytes_read = recv (recv_sock, recv_data, sizeof(recv_data), MSG_DONTWAIT); - if (-1 == bytes_read) - g_message ("recv: %s", strerror (errno)); - if (sizeof(data) != bytes_read) - g_message ("recv returned %d bytes expected %d.", bytes_read, sizeof(data)); - fail_unless (sizeof(data) == bytes_read, "recv underrun"); - - fail_unless (0 == close (recv_sock), "close failed"); - fail_unless (0 == close (send_sock), "close failed"); -} -END_TEST - -/* target: - * test setting hop limit, aka time-to-live. - * - * NB: whilst convenient, we cannot use SOCK_RAW & IPPROTO_UDP on Solaris 10 - * as it crashes the IP stack. - */ - -START_TEST (test_hop_limit_pass_001) -{ - struct sockaddr_in addr; - memset (&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr ("239.192.0.1"); - - int recv_sock = socket (AF_INET, SOCK_RAW, 113); - fail_if (-1 == recv_sock, "socket failed"); - struct sockaddr_in recv_addr; - memcpy (&recv_addr, &addr, sizeof(addr)); - recv_addr.sin_port = 7500; - fail_unless (0 == bind (recv_sock, (struct sockaddr*)&recv_addr, pgm_sockaddr_len ((struct sockaddr*)&recv_addr)), "bind failed"); - struct group_req gr; - memset (&gr, 0, sizeof(gr)); - ((struct sockaddr*)&gr.gr_group)->sa_family = addr.sin_family; - ((struct sockaddr_in*)&gr.gr_group)->sin_addr.s_addr = addr.sin_addr.s_addr; - fail_unless (0 == setsockopt (recv_sock, SOL_IP, MCAST_JOIN_GROUP, (const char*)&gr, sizeof(gr)), "setsockopt failed"); - fail_unless (0 == pgm_sockaddr_multicast_loop (recv_sock, AF_INET, FALSE), "multicast_loop failed"); - fail_unless (0 == pgm_sockaddr_hdrincl (recv_sock, AF_INET, TRUE), "hdrincl failed"); - - int send_sock = socket (AF_INET, SOCK_RAW, 113); - fail_if (-1 == send_sock, "socket failed"); - struct sockaddr_in send_addr; - memcpy (&send_addr, &addr, sizeof(addr)); - fail_unless (0 == bind (send_sock, (struct sockaddr*)&send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)), "bind failed"); - struct sockaddr_in if_addr; - fail_unless (TRUE == pgm_if_indextoaddr (0, AF_INET, 0, (struct sockaddr*)&if_addr, NULL), "if_indextoaddr failed"); - fail_unless (0 == pgm_sockaddr_multicast_if (send_sock, (struct sockaddr*)&if_addr, 0), "multicast_if failed"); - fail_unless (0 == pgm_sockaddr_multicast_loop (send_sock, AF_INET, TRUE), "multicast_loop failed"); - fail_unless (0 == pgm_sockaddr_multicast_hops (send_sock, AF_INET, 16), "multicast_hops failed"); - - const char data[] = "apple pie"; - addr.sin_port = 7500; - ssize_t bytes_sent = sendto (send_sock, data, sizeof(data), 0, (struct sockaddr*)&addr, pgm_sockaddr_len ((struct sockaddr*)&addr)); - if (-1 == bytes_sent) - g_message ("sendto: %s", strerror (errno)); - fail_unless (sizeof(data) == bytes_sent, "sendto underrun"); - - char recv_data[1024]; - ssize_t bytes_read = recv (recv_sock, recv_data, sizeof(recv_data), MSG_DONTWAIT); - if (-1 == bytes_read) - g_message ("recv: %s", strerror (errno)); - const size_t pkt_len = sizeof(struct pgm_ip) + sizeof(data); - if (pkt_len != bytes_read) - g_message ("recv returned %zd bytes expected %zu.", bytes_read, pkt_len); - fail_unless (pkt_len == bytes_read, "recv underrun"); - const struct pgm_ip* iphdr = (void*)recv_data; - fail_unless (4 == iphdr->ip_v, "Incorrect IP version, found %u expecting 4.", iphdr->ip_v); - fail_unless (16 == iphdr->ip_ttl, "hop count mismatch, found %u expecting 16.", iphdr->ip_ttl); - - fail_unless (0 == close (recv_sock), "close failed"); - fail_unless (0 == close (send_sock), "close failed"); -} -END_TEST - -/* target: - * router alert. - */ - -START_TEST (test_router_alert_pass_001) -{ - struct sockaddr_in addr; - memset (&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr ("239.192.0.1"); - - int recv_sock = socket (AF_INET, SOCK_RAW, 113); - fail_if (-1 == recv_sock, "socket failed"); - struct sockaddr_in recv_addr; - memcpy (&recv_addr, &addr, sizeof(addr)); - recv_addr.sin_port = 7500; - fail_unless (0 == bind (recv_sock, (struct sockaddr*)&recv_addr, pgm_sockaddr_len ((struct sockaddr*)&recv_addr)), "bind failed"); - struct group_req gr; - memset (&gr, 0, sizeof(gr)); - ((struct sockaddr*)&gr.gr_group)->sa_family = addr.sin_family; - ((struct sockaddr_in*)&gr.gr_group)->sin_addr.s_addr = addr.sin_addr.s_addr; - fail_unless (0 == setsockopt (recv_sock, SOL_IP, MCAST_JOIN_GROUP, (const char*)&gr, sizeof(gr)), "setsockopt failed"); - fail_unless (0 == pgm_sockaddr_multicast_loop (recv_sock, AF_INET, FALSE), "multicast_loop failed"); - fail_unless (0 == pgm_sockaddr_hdrincl (recv_sock, AF_INET, TRUE), "hdrincl failed"); - - int send_sock = socket (AF_INET, SOCK_RAW, 113); - fail_if (-1 == send_sock, "socket failed"); - struct sockaddr_in send_addr; - memcpy (&send_addr, &addr, sizeof(addr)); - fail_unless (0 == bind (send_sock, (struct sockaddr*)&send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)), "bind failed"); - struct sockaddr_in if_addr; - fail_unless (TRUE == pgm_if_indextoaddr (0, AF_INET, 0, (struct sockaddr*)&if_addr, NULL), "if_indextoaddr failed"); - fail_unless (0 == pgm_sockaddr_multicast_if (send_sock, (struct sockaddr*)&if_addr, 0), "multicast_if failed"); - fail_unless (0 == pgm_sockaddr_multicast_loop (send_sock, AF_INET, TRUE), "multicast_loop failed"); - fail_unless (0 == pgm_sockaddr_router_alert (send_sock, AF_INET, TRUE), "router_alert failed"); - - const char data[] = "apple pie"; - addr.sin_port = 7500; - ssize_t bytes_sent = sendto (send_sock, data, sizeof(data), 0, (struct sockaddr*)&addr, pgm_sockaddr_len ((struct sockaddr*)&addr)); - if (-1 == bytes_sent) - g_message ("sendto: %s", strerror (errno)); - fail_unless (sizeof(data) == bytes_sent, "sendto underrun"); - - char recv_data[1024]; - ssize_t bytes_read = recv (recv_sock, recv_data, sizeof(recv_data), MSG_DONTWAIT); - if (-1 == bytes_read) - g_message ("recv: %s", strerror (errno)); - const size_t ra_iphdr_len = sizeof(uint32_t) + sizeof(struct pgm_ip); - const size_t ra_pkt_len = ra_iphdr_len + sizeof(data); - if (ra_pkt_len != bytes_read) - g_message ("recv returned %zd bytes expected %zu.", bytes_read, ra_pkt_len); - fail_unless (ra_pkt_len == bytes_read, "recv underrun"); - const struct pgm_ip* iphdr = (void*)recv_data; - fail_unless (4 == iphdr->ip_v, "Incorrect IP version, found %u expecting 4.", iphdr->ip_v); - if (ra_iphdr_len != (iphdr->ip_hl << 2)) { - g_message ("IP header length mismatch, found %zu expecting %zu.", - (size_t)(iphdr->ip_hl << 2), ra_iphdr_len); - } - g_message ("IP header length = %zu", (size_t)(iphdr->ip_hl << 2)); - const uint32_t* ipopt = (const void*)&recv_data[ iphdr->ip_hl << 2 ]; - const uint32_t ipopt_ra = ((uint32_t)PGM_IPOPT_RA << 24) | (0x04 << 16); - const uint32_t router_alert = htonl(ipopt_ra); - if (router_alert == *ipopt) { - g_message ("IP option router alert found after IP header length."); - ipopt += sizeof(uint32_t); - } else { - ipopt = (const void*)&recv_data[ sizeof(struct pgm_ip) ]; - fail_unless (router_alert == *ipopt, "IP router alert option not found."); - g_message ("IP option router alert found before end of IP header length."); - } - g_message ("Final IP header length = %zu", (size_t)((const char*)ipopt - (const char*)recv_data)); - - fail_unless (0 == close (recv_sock), "close failed"); - fail_unless (0 == close (send_sock), "close failed"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_multicast_loop = tcase_create ("multicast loop"); - suite_add_tcase (s, tc_multicast_loop); - tcase_add_test (tc_multicast_loop, test_multicast_loop_pass_001); - - TCase* tc_port_bind = tcase_create ("port bind"); - suite_add_tcase (s, tc_port_bind); - tcase_add_test (tc_port_bind, test_port_bind_pass_001); - - TCase* tc_hop_limit = tcase_create ("hop limit"); - suite_add_tcase (s, tc_hop_limit); - tcase_add_test (tc_hop_limit, test_hop_limit_pass_001); - - TCase* tc_router_alert = tcase_create ("router alert"); - suite_add_tcase (s, tc_router_alert); - tcase_add_test (tc_router_alert, test_router_alert_pass_001); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/list.c b/3rdparty/openpgm-svn-r1085/pgm/list.c deleted file mode 100644 index 7b22f17..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/list.c +++ /dev/null @@ -1,146 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable doubly-linked list. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - - -//#define LIST_DEBUG - -pgm_list_t* -pgm_list_append ( - pgm_list_t* restrict list, - void* restrict data - ) -{ - pgm_list_t* new_list; - pgm_list_t* last; - - new_list = pgm_new (pgm_list_t, 1); - new_list->data = data; - new_list->next = NULL; - - if (list) - { - last = pgm_list_last (list); - last->next = new_list; - new_list->prev = last; - return list; - } - else - { - new_list->prev = NULL; - return new_list; - } -} - -pgm_list_t* -pgm_list_prepend_link ( - pgm_list_t* restrict list, - pgm_list_t* restrict link_ - ) -{ - pgm_list_t* new_list = link_; - - pgm_return_val_if_fail (NULL != link_, list); - - new_list->next = list; - new_list->prev = NULL; - - if (list) - list->prev = new_list; - return new_list; -} - -static inline -pgm_list_t* -_pgm_list_remove_link ( - pgm_list_t* list, /* list and link_ may be the same */ - pgm_list_t* link_ - ) -{ - if (PGM_LIKELY (NULL != link_)) - { - if (link_->prev) - link_->prev->next = link_->next; - if (link_->next) - link_->next->prev = link_->prev; - - if (link_ == list) - list = list->next; - - link_->next = link_->prev = NULL; - } - return list; -} - -pgm_list_t* -pgm_list_remove_link ( - pgm_list_t* list, /* list and link_ may be the same */ - pgm_list_t* link_ - ) -{ - return _pgm_list_remove_link (list, link_); -} - -pgm_list_t* -pgm_list_delete_link ( - pgm_list_t* list, /* list and link_ may be the same */ - pgm_list_t* link_ - ) -{ - pgm_list_t* new_list = _pgm_list_remove_link (list, link_); - pgm_free (link_); - - return new_list; -} - -/* Has pure attribute as NULL is a valid list - */ - -pgm_list_t* -pgm_list_last ( - pgm_list_t* list - ) -{ - if (PGM_LIKELY (NULL != list)) { - while (list->next) - list = list->next; - } - return list; -} - -unsigned -pgm_list_length ( - pgm_list_t* list - ) -{ - unsigned length = 0; - - while (list) - { - length++; - list = list->next; - } - - return length; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/log.c b/3rdparty/openpgm-svn-r1085/pgm/log.c deleted file mode 100644 index af2aec5..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/log.c +++ /dev/null @@ -1,151 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * basic logging. - * - * Copyright (c) 2006-2007 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#ifndef G_OS_WIN32 -# include -#endif -#include -#include "pgm/log.h" - - -/* globals */ - -#define TIME_FORMAT "%Y-%m-%d %H:%M:%S " - -static int log_timezone PGM_GNUC_READ_MOSTLY = 0; -static char log_hostname[NI_MAXHOST + 1] PGM_GNUC_READ_MOSTLY; - -static void glib_log_handler (const gchar*, GLogLevelFlags, const gchar*, gpointer); -static void pgm_log_handler (const int, const char*, void*); - - -/* calculate time zone offset in seconds - */ - -bool -log_init ( void ) -{ -/* time zone offset */ - time_t t = time(NULL); - struct tm sgmt, *gmt = &sgmt; - *gmt = *gmtime(&t); - struct tm* loc = localtime(&t); - log_timezone = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + - (loc->tm_min - gmt->tm_min) * 60; - int dir = loc->tm_year - gmt->tm_year; - if (!dir) dir = loc->tm_yday - gmt->tm_yday; - log_timezone += dir * 24 * 60 * 60; -// printf ("timezone offset %u seconds.\n", log_timezone); - gethostname (log_hostname, sizeof(log_hostname)); - g_log_set_handler ("Pgm", G_LOG_LEVEL_MASK, glib_log_handler, NULL); - g_log_set_handler ("Pgm-Http", G_LOG_LEVEL_MASK, glib_log_handler, NULL); - g_log_set_handler ("Pgm-Snmp", G_LOG_LEVEL_MASK, glib_log_handler, NULL); - g_log_set_handler (NULL, G_LOG_LEVEL_MASK, glib_log_handler, NULL); - pgm_log_set_handler (pgm_log_handler, NULL); - return 0; -} - -/* log callback - */ -static void -glib_log_handler ( - const gchar* log_domain, - G_GNUC_UNUSED GLogLevelFlags log_level, - const gchar* message, - G_GNUC_UNUSED gpointer unused_data - ) -{ -#ifdef G_OS_UNIX - struct iovec iov[7]; - struct iovec* v = iov; - time_t now; - time (&now); - const struct tm* time_ptr = localtime(&now); - char tbuf[1024]; - strftime(tbuf, sizeof(tbuf), TIME_FORMAT, time_ptr); - v->iov_base = tbuf; - v->iov_len = strlen(tbuf); - v++; - v->iov_base = log_hostname; - v->iov_len = strlen(log_hostname); - v++; - if (log_domain) { - v->iov_base = " "; - v->iov_len = 1; - v++; - v->iov_base = log_domain; - v->iov_len = strlen(log_domain); - v++; - } - v->iov_base = ": "; - v->iov_len = 2; - v++; - v->iov_base = message; - v->iov_len = strlen(message); - v++; - v->iov_base = "\n"; - v->iov_len = 1; - v++; - writev (STDOUT_FILENO, iov, v - iov); -#else - time_t now; - time (&now); - const struct tm* time_ptr = localtime(&now); - char s[1024]; - strftime(s, sizeof(s), TIME_FORMAT, time_ptr); - write (STDOUT_FILENO, s, strlen(s)); - write (STDOUT_FILENO, log_hostname, strlen(log_hostname)); - if (log_domain) { - write (STDOUT_FILENO, " ", 1); - write (STDOUT_FILENO, log_domain, strlen(log_domain)); - } - write (STDOUT_FILENO, ": ", 2); - write (STDOUT_FILENO, message, strlen(message)); - write (STDOUT_FILENO, "\n", 1); -#endif -} - -static void -pgm_log_handler ( - const int pgm_log_level, - const char* message, - G_GNUC_UNUSED void* closure - ) -{ - GLogLevelFlags glib_log_level; - - switch (pgm_log_level) { - case PGM_LOG_LEVEL_DEBUG: glib_log_level = G_LOG_LEVEL_DEBUG; break; - case PGM_LOG_LEVEL_TRACE: glib_log_level = G_LOG_LEVEL_DEBUG; break; - case PGM_LOG_LEVEL_MINOR: glib_log_level = G_LOG_LEVEL_INFO; break; - case PGM_LOG_LEVEL_NORMAL: glib_log_level = G_LOG_LEVEL_MESSAGE; break; - case PGM_LOG_LEVEL_WARNING: glib_log_level = G_LOG_LEVEL_WARNING; break; - case PGM_LOG_LEVEL_ERROR: glib_log_level = G_LOG_LEVEL_CRITICAL; break; - case PGM_LOG_LEVEL_FATAL: glib_log_level = G_LOG_LEVEL_ERROR; break; - } - - g_log ("Pgm", glib_log_level, message, NULL); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/math.c b/3rdparty/openpgm-svn-r1085/pgm/math.c deleted file mode 100644 index c2a1b4e..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/math.c +++ /dev/null @@ -1,75 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable math. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - - -//#define MATH_DEBUG - - -static const unsigned primes[] = -{ - 11, - 19, - 37, - 73, - 109, - 163, - 251, - 367, - 557, - 823, - 1237, - 1861, - 2777, - 4177, - 6247, - 9371, - 14057, - 21089, - 31627, - 47431, - 71143, - 106721, - 160073, - 240101, - 360163, - 540217, - 810343, - 1215497, - 1823231, - 2734867, - 4102283, - 6153409, - 9230113, - 13845163, -}; - -unsigned -pgm_spaced_primes_closest (unsigned num) -{ - for (unsigned i = 0; i < PGM_N_ELEMENTS(primes); i++) - if (primes[i] > num) - return primes[i]; - return primes[PGM_N_ELEMENTS(primes) - 1]; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/md5.c b/3rdparty/openpgm-svn-r1085/pgm/md5.c deleted file mode 100644 index 03bad97..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/md5.c +++ /dev/null @@ -1,368 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * MD5 hashing algorithm. - * - * MD5 original source GNU C Library: - * Includes functions to compute MD5 message digest of files or memory blocks - * according to the definition of MD5 in RFC 1321 from April 1992. - * - * Copyright (C) 1995, 1996, 2001, 2003 Free Software Foundation, Inc. - * - * This file is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this file; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - - -//#define MD5_DEBUG - - -/* locals */ - -static void _pgm_md5_process_block (struct pgm_md5_t*restrict, const void*restrict, size_t); -static void* _pgm_md5_read_ctx (const struct pgm_md5_t*, void*restrict); - - -/* This array contains the bytes used to pad the buffer to the next - * 64-byte boundary. (RFC 1321, 3.1: Step 1) */ -static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; - - -#if __BYTE_ORDER == __BIG_ENDIAN -# define SWAP(n) \ - (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) -#else -# define SWAP(n) (n) -#endif - - -/* Initialize structure containing state of computation. - (RFC 1321, 3.3: Step 3) */ - -void -pgm_md5_init_ctx ( - struct pgm_md5_t* ctx - ) -{ -/* pre-conditions */ - pgm_assert (NULL != ctx); - - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; - - ctx->total[0] = ctx->total[1] = 0; - ctx->buflen = 0; -} - -/* These are the four functions used in the four steps of the MD5 algorithm - and defined in the RFC 1321. The first function is a little bit optimized - (as found in Colin Plumbs public domain implementation). */ -#define FF(b, c, d) (d ^ (b & (c ^ d))) -#define FG(b, c, d) FF (d, b, c) -#define FH(b, c, d) (b ^ c ^ d) -#define FI(b, c, d) (c ^ (b | ~d)) - -/* Process LEN bytes of BUFFER, accumulating context into CTX. - It is assumed that LEN % 64 == 0. */ - -static -void -_pgm_md5_process_block ( - struct pgm_md5_t* restrict ctx, - const void* restrict buffer, - size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != buffer); - pgm_assert (len > 0); - pgm_assert (NULL != ctx); - - uint32_t correct_words[16]; - const uint32_t *words = buffer; - const size_t nwords = len / sizeof (uint32_t); - const uint32_t *endp = words + nwords; - uint32_t A = ctx->A; - uint32_t B = ctx->B; - uint32_t C = ctx->C; - uint32_t D = ctx->D; - -/* First increment the byte count. RFC 1321 specifies the possible - length of the file up to 2^64 bits. Here we only compute the - number of bytes. Do a double word increment. */ - ctx->total[0] += len; - if (ctx->total[0] < len) - ++ctx->total[1]; - -/* Process all bytes in the buffer with 64 bytes in each round of - the loop. */ - while (words < endp) - { - uint32_t *cwp = correct_words; - uint32_t A_save = A; - uint32_t B_save = B; - uint32_t C_save = C; - uint32_t D_save = D; - -/* First round: using the given function, the context and a constant - the next context is computed. Because the algorithms processing - unit is a 32-bit word and it is determined to work on words in - little endian byte order we perhaps have to change the byte order - before the computation. To reduce the work for the next steps - we store the swapped words in the array CORRECT_WORDS. */ - -#define OP(a, b, c, d, s, T) \ - do \ - { \ - a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ - ++words; \ - CYCLIC (a, s); \ - a += b; \ - } \ - while (0) - -/* It is unfortunate that C does not provide an operator for - * cyclic rotation. Hope the C compiler is smart enough. */ -#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) - -/* Before we start, one word to the strange constants. - They are defined in RFC 1321 as - - T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64, or - perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}' - */ - -/* Round 1. */ - OP (A, B, C, D, 7, 0xd76aa478); - OP (D, A, B, C, 12, 0xe8c7b756); - OP (C, D, A, B, 17, 0x242070db); - OP (B, C, D, A, 22, 0xc1bdceee); - OP (A, B, C, D, 7, 0xf57c0faf); - OP (D, A, B, C, 12, 0x4787c62a); - OP (C, D, A, B, 17, 0xa8304613); - OP (B, C, D, A, 22, 0xfd469501); - OP (A, B, C, D, 7, 0x698098d8); - OP (D, A, B, C, 12, 0x8b44f7af); - OP (C, D, A, B, 17, 0xffff5bb1); - OP (B, C, D, A, 22, 0x895cd7be); - OP (A, B, C, D, 7, 0x6b901122); - OP (D, A, B, C, 12, 0xfd987193); - OP (C, D, A, B, 17, 0xa679438e); - OP (B, C, D, A, 22, 0x49b40821); - -/* For the second to fourth round we have the possibly swapped words - in CORRECT_WORDS. Redefine the macro to take an additional first - argument specifying the function to use. */ -#undef OP -#define OP(f, a, b, c, d, k, s, T) \ - do \ - { \ - a += f (b, c, d) + correct_words[k] + T; \ - CYCLIC (a, s); \ - a += b; \ - } \ - while (0) - -/* Round 2. */ - OP (FG, A, B, C, D, 1, 5, 0xf61e2562); - OP (FG, D, A, B, C, 6, 9, 0xc040b340); - OP (FG, C, D, A, B, 11, 14, 0x265e5a51); - OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); - OP (FG, A, B, C, D, 5, 5, 0xd62f105d); - OP (FG, D, A, B, C, 10, 9, 0x02441453); - OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); - OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); - OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); - OP (FG, D, A, B, C, 14, 9, 0xc33707d6); - OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); - OP (FG, B, C, D, A, 8, 20, 0x455a14ed); - OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); - OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); - OP (FG, C, D, A, B, 7, 14, 0x676f02d9); - OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); - -/* Round 3. */ - OP (FH, A, B, C, D, 5, 4, 0xfffa3942); - OP (FH, D, A, B, C, 8, 11, 0x8771f681); - OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); - OP (FH, B, C, D, A, 14, 23, 0xfde5380c); - OP (FH, A, B, C, D, 1, 4, 0xa4beea44); - OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); - OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); - OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); - OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); - OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); - OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); - OP (FH, B, C, D, A, 6, 23, 0x04881d05); - OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); - OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); - OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); - OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); - -/* Round 4. */ - OP (FI, A, B, C, D, 0, 6, 0xf4292244); - OP (FI, D, A, B, C, 7, 10, 0x432aff97); - OP (FI, C, D, A, B, 14, 15, 0xab9423a7); - OP (FI, B, C, D, A, 5, 21, 0xfc93a039); - OP (FI, A, B, C, D, 12, 6, 0x655b59c3); - OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); - OP (FI, C, D, A, B, 10, 15, 0xffeff47d); - OP (FI, B, C, D, A, 1, 21, 0x85845dd1); - OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); - OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); - OP (FI, C, D, A, B, 6, 15, 0xa3014314); - OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); - OP (FI, A, B, C, D, 4, 6, 0xf7537e82); - OP (FI, D, A, B, C, 11, 10, 0xbd3af235); - OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); - OP (FI, B, C, D, A, 9, 21, 0xeb86d391); - -/* Add the starting values of the context. */ - A += A_save; - B += B_save; - C += C_save; - D += D_save; - } - -/* Put checksum in context given as argument. */ - ctx->A = A; - ctx->B = B; - ctx->C = C; - ctx->D = D; -} - -void -pgm_md5_process_bytes ( - struct pgm_md5_t* restrict ctx, - const void* restrict buffer, - size_t len - ) -{ -/* pre-conditions */ - if (len > 0) { - pgm_assert (NULL != buffer); - } - pgm_assert (NULL != ctx); - - if (len >= 64) - { -#if !_STRING_ARCH_unaligned -/* To check alignment gcc has an appropriate operator. Other - compilers don't. */ -# if __GNUC__ >= 2 -# define UNALIGNED_P(p) (((uintptr_t)p) % __alignof__ (uint32_t) != 0) -# else -# define UNALIGNED_P(p) (((uintptr_t)p) % sizeof(uint32_t) != 0) -# endif - if (UNALIGNED_P (buffer)) - while (len > 64) - { - _pgm_md5_process_block (ctx, memcpy (ctx->buffer, buffer, 64), 64); - buffer = (const char*)buffer + 64; - len -= 64; - } - else -#endif - { - _pgm_md5_process_block (ctx, buffer, len & ~63); - buffer = (const char*)buffer + (len & ~63); - len &= 63; - } - } - -/* Move remaining bytes in internal buffer. */ - if (len > 0) - { - size_t left_over = ctx->buflen; - - memcpy (&ctx->buffer[left_over], buffer, len); - left_over += len; - if (left_over >= 64) - { - _pgm_md5_process_block (ctx, ctx->buffer, 64); - left_over -= 64; - memcpy (ctx->buffer, &ctx->buffer[64], left_over); - } - ctx->buflen = left_over; - } -} - -/* Put result from CTX in first 16 bytes following RESBUF. The result - must be in little endian byte order. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ - -static -void* -_pgm_md5_read_ctx ( - const struct pgm_md5_t* restrict ctx, - void* restrict resbuf - ) -{ -/* pre-conditions */ - pgm_assert (NULL != ctx); - pgm_assert (NULL != resbuf); - - ((uint32_t*)resbuf)[0] = SWAP (ctx->A); - ((uint32_t*)resbuf)[1] = SWAP (ctx->B); - ((uint32_t*)resbuf)[2] = SWAP (ctx->C); - ((uint32_t*)resbuf)[3] = SWAP (ctx->D); - - return resbuf; -} - -/* Process the remaining bytes in the internal buffer and the usual - prolog according to the standard and write the result to RESBUF. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ - -void* -pgm_md5_finish_ctx ( - struct pgm_md5_t* restrict ctx, - void* restrict resbuf - ) -{ -/* pre-conditions */ - pgm_assert (NULL != ctx); - pgm_assert (NULL != resbuf); - -/* Take yet unprocessed bytes into account. */ - const uint32_t bytes = ctx->buflen; - size_t pad; - -/* Now count remaining bytes. */ - ctx->total[0] += bytes; - if (ctx->total[0] < bytes) - ++ctx->total[1]; - - pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; - memcpy (&ctx->buffer[bytes], fillbuf, pad); - - /* Put the 64-bit file length in *bits* at the end of the buffer. */ - *(uint32_t*) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3); - *(uint32_t*) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) | - (ctx->total[0] >> 29)); - -/* Process last bytes. */ - _pgm_md5_process_block (ctx, ctx->buffer, bytes + pad + 8); - - return _pgm_md5_read_ctx (ctx, resbuf); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/md5_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/md5_unittest.c deleted file mode 100644 index 836af1f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/md5_unittest.c +++ /dev/null @@ -1,189 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for MD5 hashing (not actual algorithm). - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - - -/* mock state */ - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - - -#define MD5_DEBUG -#include "md5.c" - - -/* target: - * void - * pgm_md5_init_ctx ( - * struct pgm_md5_t* ctx - * ) - */ - -START_TEST (test_init_ctx_pass_001) -{ - struct pgm_md5_t ctx; - memset (&ctx, 0, sizeof(ctx)); - pgm_md5_init_ctx (&ctx); -} -END_TEST - -START_TEST (test_init_ctx_fail_001) -{ - pgm_md5_init_ctx (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_md5_process_bytes ( - * struct pgm_md5_t* ctx, - * const void* buffer, - * size_t len - * ) - */ - -START_TEST (test_process_bytes_pass_001) -{ - const char buffer[] = "i am not a string."; - struct pgm_md5_t ctx; - memset (&ctx, 0, sizeof(ctx)); - pgm_md5_init_ctx (&ctx); - pgm_md5_process_bytes (&ctx, buffer, sizeof(buffer)); -} -END_TEST - -START_TEST (test_process_bytes_fail_001) -{ - const char buffer[] = "i am not a string."; - pgm_md5_process_bytes (NULL, buffer, sizeof(buffer)); -} -END_TEST - -/* target: - * void* - * pgm_md5_finish_ctx ( - * struct pgm_md5_t* ctx, - * void* resbuf - * ) - */ - -START_TEST (test_finish_ctx_pass_001) -{ - const char* buffer = "i am not a string."; - const char* answer = "ef71-1617-4eef-9737-5e2b-5d7a-d015-b064"; - - char md5[1024]; - char resblock[16]; - struct pgm_md5_t ctx; - memset (&ctx, 0, sizeof(ctx)); - memset (resblock, 0, sizeof(resblock)); - pgm_md5_init_ctx (&ctx); - pgm_md5_process_bytes (&ctx, buffer, strlen(buffer)+1); - pgm_md5_finish_ctx (&ctx, resblock); - sprintf (md5, "%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx", - resblock[0], resblock[1], - resblock[2], resblock[3], - resblock[4], resblock[5], - resblock[6], resblock[7], - resblock[8], resblock[9], - resblock[10], resblock[11], - resblock[12], resblock[13], - resblock[14], resblock[15]); - g_message ("md5: %s", md5); - - fail_unless (0 == strcmp (md5, answer), "md5 mismatch"); -} -END_TEST - -START_TEST (test_finish_ctx_fail_001) -{ - char resblock[16]; - pgm_md5_finish_ctx (NULL, resblock); - fail ("reached"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_init_ctx = tcase_create ("init-ctx"); - suite_add_tcase (s, tc_init_ctx); - tcase_add_test (tc_init_ctx, test_init_ctx_pass_001); - tcase_add_test_raise_signal (tc_init_ctx, test_init_ctx_fail_001, SIGABRT); - - TCase* tc_process_bytes = tcase_create ("process_bytes"); - suite_add_tcase (s, tc_process_bytes); - tcase_add_test (tc_process_bytes, test_process_bytes_pass_001); - tcase_add_test_raise_signal (tc_process_bytes, test_process_bytes_fail_001, SIGABRT); - - TCase* tc_finish_ctx = tcase_create ("finish-ctx"); - suite_add_tcase (s, tc_finish_ctx); - tcase_add_test (tc_finish_ctx, test_finish_ctx_pass_001); - tcase_add_test_raise_signal (tc_finish_ctx, test_finish_ctx_fail_001, SIGABRT); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/mem.c b/3rdparty/openpgm-svn-r1085/pgm/mem.c deleted file mode 100644 index 85a6dee..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/mem.c +++ /dev/null @@ -1,249 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable fail fast memory allocation. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#ifdef _WIN32 -# define strcasecmp stricmp -#endif -#include -#include - - -//#define MEM_DEBUG - - -/* globals */ - -bool pgm_mem_gc_friendly PGM_GNUC_READ_MOSTLY = FALSE; - - -/* locals */ - -struct pgm_debug_key_t { - const char* key; - unsigned value; -}; -typedef struct pgm_debug_key_t pgm_debug_key_t; - -static volatile uint32_t mem_ref_count = 0; - - -static -bool -debug_key_matches ( - const char* restrict key, - const char* restrict token, - unsigned length - ) -{ - for (; length; length--, key++, token++) - { - const char k = (*key == '_') ? '-' : tolower (*key ); - const char t = (*token == '_') ? '-' : tolower (*token); - if (k != t) - return FALSE; - } - return *key == '\0'; -} - -static -unsigned -pgm_parse_debug_string ( - const char* restrict string, - const pgm_debug_key_t* restrict keys, - const unsigned nkeys - ) -{ - unsigned result = 0; - - if (NULL == string) - return result; - - if (!strcasecmp (string, "all")) - { - for (unsigned i = 0; i < nkeys; i++) - result |= keys[i].value; - } - else if (!strcasecmp (string, "help")) - { - fprintf (stderr, "Supported debug values:"); - for (unsigned i = 0; i < nkeys; i++) - fprintf (stderr, " %s", keys[i].key); - fprintf (stderr, "\n"); - } - else - { - while (string) { - const char* q = strpbrk (string, ":;, \t"); - if (!q) - q = string + strlen (string); - for (unsigned i = 0; i < nkeys; i++) - if (debug_key_matches (keys[i].key, string, q - string)) - result |= keys[i].value; - string = q; - if (*string) - string++; - } - } - return result; -} - -void -pgm_mem_init (void) -{ - static const pgm_debug_key_t keys[] = { - { "gc-friendly", 1 }, - }; - - if (pgm_atomic_exchange_and_add32 (&mem_ref_count, 1) > 0) - return; - - const char *val = getenv ("PGM_DEBUG"); - const unsigned flags = !val ? 0 : pgm_parse_debug_string (val, keys, PGM_N_ELEMENTS (keys)); - if (flags & 1) - pgm_mem_gc_friendly = TRUE; -} - -void -pgm_mem_shutdown (void) -{ - pgm_return_if_fail (pgm_atomic_read32 (&mem_ref_count) > 0); - - if (pgm_atomic_exchange_and_add32 (&mem_ref_count, (uint32_t)-1) != 1) - return; - - /* nop */ -} - -/* malloc wrappers to hard fail */ -void* -pgm_malloc ( - const size_t n_bytes - ) -{ - if (PGM_LIKELY (n_bytes)) - { - void* mem = malloc (n_bytes); - if (mem) - return mem; - - pgm_fatal ("file %s: line %d (%s): failed to allocate %zu bytes", - __FILE__, __LINE__, __PRETTY_FUNCTION__, - n_bytes); - abort (); - } - return NULL; -} - -#define SIZE_OVERFLOWS(a,b) (PGM_UNLIKELY ((a) > SIZE_MAX / (b))) - -void* -pgm_malloc_n ( - const size_t n_blocks, - const size_t block_bytes - ) -{ - if (SIZE_OVERFLOWS (n_blocks, block_bytes)) { - pgm_fatal ("file %s: line %d (%s): overflow allocating %zu*%zu bytes", - __FILE__, __LINE__, __PRETTY_FUNCTION__, - n_blocks, block_bytes); - } - return pgm_malloc (n_blocks * block_bytes); -} - -void* -pgm_malloc0 ( - const size_t n_bytes - ) -{ - if (PGM_LIKELY (n_bytes)) - { - void* mem = calloc (1, n_bytes); - if (mem) - return mem; - - pgm_fatal ("file %s: line %d (%s): failed to allocate %zu bytes", - __FILE__, __LINE__, __PRETTY_FUNCTION__, - n_bytes); - abort (); - } - return NULL; -} - -void* -pgm_malloc0_n ( - const size_t n_blocks, - const size_t block_bytes - ) -{ - if (PGM_LIKELY (n_blocks && block_bytes)) - { - void* mem = calloc (n_blocks, block_bytes); - if (mem) - return mem; - - pgm_fatal ("file %s: line %d (%s): failed to allocate %zu*%zu bytes", - __FILE__, __LINE__, __PRETTY_FUNCTION__, - n_blocks, block_bytes); - abort (); - } - return NULL; -} - -void* -pgm_memdup ( - const void* mem, - const size_t n_bytes - ) -{ - void* new_mem; - - if (PGM_LIKELY (NULL != mem)) - { - new_mem = pgm_malloc (n_bytes); - memcpy (new_mem, mem, n_bytes); - } - else - new_mem = NULL; - - return new_mem; -} - -void* -pgm_realloc ( - void* mem, - const size_t n_bytes - ) -{ - return realloc (mem, n_bytes); -} - -void -pgm_free ( - void* mem - ) -{ - if (PGM_LIKELY (NULL != mem)) - free (mem); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/memcheck b/3rdparty/openpgm-svn-r1085/pgm/memcheck deleted file mode 100755 index fbfe59c..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/memcheck +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -G_SLICE=always-malloc \ -G_DEBUG=gc-friendly \ - valgrind \ - -v \ - --tool=memcheck \ - --leak-check=full \ - --num-callers=40 \ - --gen-suppressions=no \ - --show-reachable=yes \ - --suppressions=valgrind.supp \ - $* diff --git a/3rdparty/openpgm-svn-r1085/pgm/messages.c b/3rdparty/openpgm-svn-r1085/pgm/messages.c deleted file mode 100644 index 9fa281b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/messages.c +++ /dev/null @@ -1,173 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * basic message reporting. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include - - -/* globals */ - -/* bit mask for trace role modules */ -int pgm_log_mask PGM_GNUC_READ_MOSTLY = 0xffff; -int pgm_min_log_level PGM_GNUC_READ_MOSTLY = PGM_LOG_LEVEL_NORMAL; - - -/* locals */ - -static const char log_levels[8][6] = { - "Uknown", - "Debug", - "Trace", - "Minor", - "Info", - "Warn", - "Error", - "Fatal" -}; - -static volatile uint32_t messages_ref_count = 0; -static pgm_mutex_t messages_mutex; -static pgm_log_func_t log_handler PGM_GNUC_READ_MOSTLY = NULL; -static void* log_handler_closure PGM_GNUC_READ_MOSTLY = NULL; - -static inline const char* log_level_text (const int) PGM_GNUC_PURE; - - -static inline -const char* -log_level_text ( - const int log_level - ) -{ - switch (log_level) { - default: return log_levels[0]; - case PGM_LOG_LEVEL_DEBUG: return log_levels[1]; - case PGM_LOG_LEVEL_TRACE: return log_levels[2]; - case PGM_LOG_LEVEL_MINOR: return log_levels[3]; - case PGM_LOG_LEVEL_NORMAL: return log_levels[4]; - case PGM_LOG_LEVEL_WARNING: return log_levels[5]; - case PGM_LOG_LEVEL_ERROR: return log_levels[6]; - case PGM_LOG_LEVEL_FATAL: return log_levels[7]; - } -} - -/* reference counted init and shutdown - */ - -void -pgm_messages_init (void) -{ - if (pgm_atomic_exchange_and_add32 (&messages_ref_count, 1) > 0) - return; - - pgm_mutex_init (&messages_mutex); - - const char* log_mask = getenv ("PGM_LOG_MASK"); - if (NULL != log_mask) { - unsigned int value = 0; - if (1 == sscanf (log_mask, "0x%4x", &value)) - pgm_log_mask = value; - } - const char *min_log_level = getenv ("PGM_MIN_LOG_LEVEL"); - if (NULL != min_log_level) { - switch (min_log_level[0]) { - case 'D': pgm_min_log_level = PGM_LOG_LEVEL_DEBUG; break; - case 'T': pgm_min_log_level = PGM_LOG_LEVEL_TRACE; break; - case 'M': pgm_min_log_level = PGM_LOG_LEVEL_MINOR; break; - case 'N': pgm_min_log_level = PGM_LOG_LEVEL_NORMAL; break; - case 'W': pgm_min_log_level = PGM_LOG_LEVEL_WARNING; break; - case 'E': pgm_min_log_level = PGM_LOG_LEVEL_ERROR; break; - case 'F': pgm_min_log_level = PGM_LOG_LEVEL_FATAL; break; - default: break; - } - } -} - -void -pgm_messages_shutdown (void) -{ - pgm_return_if_fail (pgm_atomic_read32 (&messages_ref_count) > 0); - - if (pgm_atomic_exchange_and_add32 (&messages_ref_count, (uint32_t)-1) != 1) - return; - - pgm_mutex_free (&messages_mutex); -} - -/* set application handler for log messages, returns previous value, - * default handler value is NULL. - */ - -pgm_log_func_t -pgm_log_set_handler ( - pgm_log_func_t handler, - void* closure - ) -{ - pgm_log_func_t previous_handler; - pgm_mutex_lock (&messages_mutex); - previous_handler = log_handler; - log_handler = handler; - log_handler_closure = closure; - pgm_mutex_unlock (&messages_mutex); - return previous_handler; -} - -void -pgm__log ( - const int log_level, - const char* format, - ... - ) -{ - va_list args; - - va_start (args, format); - pgm__logv (log_level, format, args); - va_end (args); -} - -void -pgm__logv ( - const int log_level, - const char* format, - va_list args - ) -{ - char tbuf[ 1024 ]; - - pgm_mutex_lock (&messages_mutex); - const int offset = sprintf (tbuf, "%s: ", log_level_text (log_level)); - vsnprintf (tbuf+offset, sizeof(tbuf)-offset, format, args); - tbuf[ sizeof(tbuf) ] = '\0'; - if (log_handler) - log_handler (log_level, tbuf, log_handler_closure); - else { -/* ignore return value */ - write (STDOUT_FILENO, tbuf, strlen (tbuf)); - write (STDOUT_FILENO, "\n", 1); - } - - pgm_mutex_unlock (&messages_mutex); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/mibs/PGM-MIB-petrova-01.txt b/3rdparty/openpgm-svn-r1085/pgm/mibs/PGM-MIB-petrova-01.txt deleted file mode 100644 index 28ff72c..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/mibs/PGM-MIB-petrova-01.txt +++ /dev/null @@ -1,5459 +0,0 @@ ----------------------------------------------------------------- --- --- Pragmatic General Multicast (PGM) MIB --- ----------------------------------------------------------------- --- --- --- Full MIB for the PGM protocol incorporating Network Element --- (router), source, receiver and DLR functionality --- --- extracted from draft-petrova-pgmmib-01.txt - -PGM-MIB DEFINITIONS ::= BEGIN -IMPORTS - OBJECT-TYPE, Counter32, Integer32, Unsigned32, NOTIFICATION-TYPE, - MODULE-IDENTITY, IpAddress, TimeTicks, experimental, BITS - FROM SNMPv2-SMI - MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP - FROM SNMPv2-CONF - InterfaceIndex - FROM IF-MIB; - -pgmMIB MODULE-IDENTITY - LAST-UPDATED "200205010000Z" - ORGANIZATION - "Cisco Systems + Tibco Software Inc + Nortel Networks" - CONTACT-INFO - " Richard Edmonstone - redmonst@cisco.com - +44 131 561 3621 - Cisco Systems, Inc. - 170 West Tasman Drive, - San Jose, CA 95134 - USA - - Rajiv Raghunarayan - raraghun@cisco.com - +91 80 532 1300 - Cisco Systems, Inc. - 170 West Tasman Drive, - San Jose, CA 95134 - USA - - Devendra Raut - draut@nortelnetworks.com - (408)495-2859 - Nortel Networks - 4401 Great America Parkway, - Santa Clara, CA 95052 - - Moses Sun - mosun@nortelnetworks.com - (979)694-7156 - Nortel Networks - 4401 Great America Parkway - Santa Clara, CA, - USA - - Todd L. Montgomery - tmontgomery@tibco.com - (304)291-5972 - Tibco Software Inc. - 29W110 Butterfield Rd, Suite 205 - Warrenville, IL 60555 - USA - - Michael Garwood - mgarwood@tibco.com - (630)393-7363 ext.275 - Tibco Software Inc. - 29W110 Butterfield Rd, Suite 205 - Warrenville, IL 60555 - USA - - Luna Petrova - lpetrova@tibco.com - (630)393-7363 ext.330 - Tibco Software Inc. - 29W110 Butterfield Rd, Suite 205 - Warrenville, IL 60555 - USA" - DESCRIPTION - "The MIB module for managing PGM implementations." - REVISION "200205010000Z" - DESCRIPTION - "Rev 2.0: SNMP Notifications added to the MIB." - ::= { experimental 112 } -- assigned by IANA. - -pgm OBJECT IDENTIFIER ::= { pgmMIB 1 } -pgmNetworkElement OBJECT IDENTIFIER ::= { pgm 1 } -pgmSource OBJECT IDENTIFIER ::= { pgm 2 } -pgmReceiver OBJECT IDENTIFIER ::= { pgm 3 } -pgmDLR OBJECT IDENTIFIER ::= { pgm 4 } -pgmNotificationPrefix OBJECT IDENTIFIER ::= { pgmMIB 2 } - --- PGM Network Element - -pgmNeEnable OBJECT-TYPE - SYNTAX INTEGER { - enable(1), - disable(2) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Enable/Disable Parameter indicates whether - this PGM operation is enabled or disabled." - DEFVAL { enable } - ::= { pgmNetworkElement 1 } - -pgmNeSessionLifeTime OBJECT-TYPE - SYNTAX Unsigned32(0..2147483647) - UNITS "seconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The length of the idle time (seconds) following - which a PGM session will be aged out. An idle PGM - session means there is no SPM message received - from the upstream. - Value of 0 indicates no timeout." - DEFVAL { 300 } - ::= { pgmNetworkElement 2 } - -pgmNeMaxReXmitStates OBJECT-TYPE - SYNTAX Integer32(-2..2147483647) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The Maximum number of retransmission state entries. - The value of -1 means network element has no - limitation. - The value of -2 means not supported by this - implementation." - ::= { pgmNetworkElement 3 } - -pgmNeMaxSessions OBJECT-TYPE - SYNTAX Integer32(-2..2147483647) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The maximum number of state sessions supported. - The value of -1 means network element has no - limitation. - The value of -2 means not supported by this - implementation." - ::= { pgmNetworkElement 4 } - --- The PGM NE Network Interface - --- The PGM NE Network Interface tables contain --- per-interface information about the PGM protocol. --- The information is grouped into three major categories: --- fault, configuration and performance management. - -pgmNeInterface OBJECT IDENTIFIER ::= { pgmNetworkElement 100 } - -pgmNeTotalInterfacesNumberOfEntries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of entries in the PGM Interface - table." - ::= { pgmNeInterface 1 } - --- The PGM NE Network Interface configuration table - -pgmNeIfConfigTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmNeIfConfigEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per interface configuration - information relating to PGM Network Element - operation." - ::= {pgmNeInterface 3} - -pgmNeIfConfigEntry OBJECT-TYPE - SYNTAX PgmNeIfConfigEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per Interface Configuration Information." - INDEX { pgmNeIfConfigIndex } - ::= { pgmNeIfConfigTable 1 } - -PgmNeIfConfigEntry ::= SEQUENCE { - pgmNeIfConfigIndex - InterfaceIndex, - pgmNeIfPgmEnable - INTEGER, - pgmNeIfNakRptInterval - Unsigned32, - pgmNeIfNakRptRate - Unsigned32, - pgmNeIfNakRdataInterval - Unsigned32, - pgmNeIfNakEliminateInterval - Unsigned32 - } - -pgmNeIfConfigIndex OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A unique value for each interface. Its value - ranges between 1 and the value of ifNumber. The - value for each interface must remain constant at - least from one re-initialization of the entity's - network management system to the next - re-initialization." - ::= { pgmNeIfConfigEntry 1 } - -pgmNeIfPgmEnable OBJECT-TYPE - SYNTAX INTEGER { - enable(1), - disable(2) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Allows PGM to be enabled and disabled per - Network Interface. - - PGM can be enabled or disabled per Network - Interface, only if PGM is enabled for this - Network Element." - ::= { pgmNeIfConfigEntry 2 } - -pgmNeIfNakRptInterval OBJECT-TYPE - SYNTAX Unsigned32(1..4294967295) - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The length of time (milliseconds) for which a - network element will repeat a NAK while waiting - for a corresponding NCF. This interval is counted - down from the transmission of a NAK." - DEFVAL { 100 } - ::= { pgmNeIfConfigEntry 3 } - -pgmNeIfNakRptRate OBJECT-TYPE - SYNTAX Unsigned32(1..4294967295) - UNITS "number of NAKs per second" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The rate at which NAKs are repeated." - DEFVAL { 2 } - ::= { pgmNeIfConfigEntry 4 } - -pgmNeIfNakRdataInterval OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The length of time (milliseconds) for which - a network element will wait for the - corresponding RDATA. This interval is counted - down from the time a matching NCF is received. - This value must be greater than the - pgmNeIfNakEliminateInterval." - DEFVAL { 10000 } - ::= { pgmNeIfConfigEntry 5 } - -pgmNeIfNakEliminateInterval OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The length of time (milliseconds) for which - a network element will eliminate NAKs for - a specific TSI/SQN. This interval is counted - down from the time the first NAK is - established. This value must - be smaller than pgmNeIfNakRdataInterval." - DEFVAL { 5000 } - ::= { pgmNeIfConfigEntry 6 } - --- The PGM NE Interface performance table. --- This is primarily statistical information --- about packets received and sent on the interface - -pgmNeIfPerformanceTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmNeIfPerformanceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per interface performance - information related to PGM Network Element - operation." - ::= {pgmNeInterface 4} - -pgmNeIfPerformanceEntry OBJECT-TYPE - SYNTAX PgmNeIfPerformanceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per Interface Information for Network Elements." - INDEX { pgmNeIfPerformanceIndex } - ::= { pgmNeIfPerformanceTable 1 } - -PgmNeIfPerformanceEntry ::= SEQUENCE { - pgmNeIfPerformanceIndex - InterfaceIndex, - pgmNeIfReXmitStates - Counter32, - pgmNeIfReXmitTimedOut - Counter32, - pgmNeIfInSpms - Counter32, - pgmNeIfOutSpms - Counter32, - pgmNeIfInParitySpms - Counter32, - pgmNeIfOutParitySpms - Counter32, - pgmNeIfInRdata - Counter32, - pgmNeIfOutRdata - Counter32, - pgmNeIfInParityRdata - Counter32, - pgmNeIfOutParityRdata - Counter32, - pgmNeIfInRdataNoSessionErrors - Counter32, - pgmNeIfUniqueNaks - Counter32, - pgmNeIfInNaks - Counter32, - pgmNeIfOutNaks - Counter32, - pgmNeIfUniqueParityNaks - Counter32, - pgmNeIfInParityNaks - Counter32, - pgmNeIfOutParityNaks - Counter32, - pgmNeIfInNakNoSessionErrors - Counter32, - pgmNeIfInNakSeqErrors - Counter32, - pgmNeIfInParityNakTgErrors - Counter32, - pgmNeIfInNnaks - Counter32, - pgmNeIfOutNnaks - Counter32, - pgmNeIfInParityNnaks - Counter32, - pgmNeIfOutParityNnaks - Counter32, - pgmNeIfInNnakNoSessionErrors - Counter32, - pgmNeIfInNcfs - Counter32, - pgmNeIfOutNcfs - Counter32, - pgmNeIfInParityNcfs - Counter32, - pgmNeIfOutParityNcfs - Counter32, - pgmNeIfInNcfNoSessionErrors - Counter32, - pgmNeIfInRedirectNcfs - Counter32, - pgmNeIfMalformed - Counter32, - pgmNeIfSpmFromSource - Counter32, - pgmNeIfSpmBadSqn - Counter32, - pgmNeIfSpmError - Counter32, - pgmNeIfPollRandomIgnore - Counter32, - pgmNeIfPollTsiStateError - Counter32, - pgmNeIfPollParentError - Counter32, - pgmNeIfPollTypeError - Counter32, - pgmNeIfPollError - Counter32, - pgmNeIfPollSuccess - Counter32, - pgmNeIfPollOriginated - Counter32, - pgmNeIfPolrNoState - Counter32, - pgmNeIfPolrError - Counter32, - pgmNeIfPolrParityError - Counter32, - pgmNeIfPolrSuccess - Counter32, - pgmNeIfPolrOriginated - Counter32, - pgmNeIfNcfError - Counter32, - pgmNeIfNcfParityError - Counter32, - pgmNeIfNcfPartialParity - Counter32, - pgmNeIfNcfReceived - Counter32, - pgmNeIfNcfAnticipated - Counter32, - pgmNeIfNcfRedirecting - Counter32, - pgmNeIfNakEliminated - Counter32, - pgmNeIfNakError - Counter32, - pgmNeIfNakParityError - Counter32, - pgmNeIfNNakEliminated - Counter32, - pgmNeIfNNakError - Counter32, - pgmNeIfNNakParityError - Counter32, - pgmNeIfNNakCongestionReports - Counter32, - pgmNeIfNakRetryExpired - Counter32, - pgmNeIfNakRetryExpiredDLR - Counter32, - pgmNeIfNakForwardedDLR - Counter32, - pgmNeIfNakRetransmitted - Counter32, - pgmNeIfRdataEliminatedOIF - Counter32, - pgmNeIfRdataEliminatedSqn - Counter32, - pgmNeIfInRdataFragments - Counter32, - pgmNeIfRdataFragmentsNoSessionErrors - Counter32, - pgmNeIfRdataFragmentsEliminatedOIF - Counter32, - pgmNeIfRdataFragmentsEliminatedSqn - Counter32, - pgmNeIfOutRdataFragments - Counter32 -} - -pgmNeIfPerformanceIndex OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A unique value for each interface. Its value - ranges between 1 and the value of ifNumber. - The value for each interface must remain - constant at least from one re-initialization - of the entity's network management system - to the next re-initialization." - ::= { pgmNeIfPerformanceEntry 1 } - -pgmNeIfReXmitStates OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total retransmit state entries for this - interface." - ::= { pgmNeIfPerformanceEntry 2 } - -pgmNeIfReXmitTimedOut OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of timed-out retransmit state - entries for this interface." - ::= { pgmNeIfPerformanceEntry 3 } - -pgmNeIfInSpms OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of SPMs received on the PGM - interface." - ::= { pgmNeIfPerformanceEntry 4 } - -pgmNeIfOutSpms OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of SPMs sent out from the PGM - interface." - ::= { pgmNeIfPerformanceEntry 5 } - -pgmNeIfInParitySpms OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity SPMs received on the - PGM interface." - ::= { pgmNeIfPerformanceEntry 6 } - -pgmNeIfOutParitySpms OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity SPMs sent out from the - PGM interface." - ::= { pgmNeIfPerformanceEntry 7 } - -pgmNeIfInRdata OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of RDATA received on the PGM - interface." - ::= { pgmNeIfPerformanceEntry 8 } - -pgmNeIfOutRdata OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of RDATA sent out from the - PGM interface." - ::= { pgmNeIfPerformanceEntry 9 } - -pgmNeIfInParityRdata OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity RDATA received on the - PGM interface." - ::= { pgmNeIfPerformanceEntry 10 } - -pgmNeIfOutParityRdata OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity RDATA sent out from - the PGM interface." - ::= { pgmNeIfPerformanceEntry 11 } - -pgmNeIfInRdataNoSessionErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of received RDATA discarded because - of no session." - ::= { pgmNeIfPerformanceEntry 12 } - -pgmNeIfUniqueNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of unique NAKs received on - this interface." - ::= { pgmNeIfPerformanceEntry 13 } - -pgmNeIfInNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NAKs received on the PGM - interface." - ::= { pgmNeIfPerformanceEntry 14 } - -pgmNeIfOutNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NAKs sent out from the - PGM interface." - ::= { pgmNeIfPerformanceEntry 15 } - -pgmNeIfUniqueParityNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of unique parity NAKs received - on this interface." - ::= { pgmNeIfPerformanceEntry 16 } - -pgmNeIfInParityNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity NAKs received on the - PGM interface." - ::= { pgmNeIfPerformanceEntry 17 } - -pgmNeIfOutParityNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity NAKs sent out from - the PGM interface." - ::= { pgmNeIfPerformanceEntry 18 } - -pgmNeIfInNakNoSessionErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of received NAKs discarded because of - no session." - ::= { pgmNeIfPerformanceEntry 19 } - -pgmNeIfInNakSeqErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of received NAKs discarded because - of out of sequence (out of retransmit window)." - ::= { pgmNeIfPerformanceEntry 20 } - -pgmNeIfInParityNakTgErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of received parity NAKs discarded - because out of parity TG window." - ::= { pgmNeIfPerformanceEntry 21 } - -pgmNeIfInNnaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NNAKs received on the PGM - interface." - ::= { pgmNeIfPerformanceEntry 22 } - -pgmNeIfOutNnaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NNAKs sent out from the - PGM interface." - ::= { pgmNeIfPerformanceEntry 23 } - -pgmNeIfInParityNnaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity NNAKs received on - the PGM interface." - ::= { pgmNeIfPerformanceEntry 24 } - -pgmNeIfOutParityNnaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity NNAKs sent out from - the PGM interface." - ::= { pgmNeIfPerformanceEntry 25 } - -pgmNeIfInNnakNoSessionErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of received NNAKs discarded because - of no session." - ::= { pgmNeIfPerformanceEntry 26 } - -pgmNeIfInNcfs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NCFs received on the PGM - interface." - ::= { pgmNeIfPerformanceEntry 27 } - -pgmNeIfOutNcfs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NCFs sent out from the PGM - interface." - ::= { pgmNeIfPerformanceEntry 28 } - -pgmNeIfInParityNcfs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity NCFs received on the - PGM interface." - ::= { pgmNeIfPerformanceEntry 29 } - -pgmNeIfOutParityNcfs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity NCFs sent out from - the PGM interface." - ::= { pgmNeIfPerformanceEntry 30 } - -pgmNeIfInNcfNoSessionErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of received NCFs discarded because - of no session." - ::= { pgmNeIfPerformanceEntry 31 } - -pgmNeIfInRedirectNcfs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of redirected NCFs received on the - PGM interface." - ::= { pgmNeIfPerformanceEntry 32 } - -pgmNeIfMalformed OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of malformed PGM packets." - ::= { pgmNeIfPerformanceEntry 33 } - -pgmNeIfSpmFromSource OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of SPM packets received from source." - ::= { pgmNeIfPerformanceEntry 34 } - -pgmNeIfSpmBadSqn OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of SPM packets discarded due to bad - SQN." - ::= { pgmNeIfPerformanceEntry 35 } - -pgmNeIfSpmError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of SPM packets discarded due to - operational error. Some examples of operational - errors are failure to create TSI state for SPM, - parity SPM for a TSI with no parity." - ::= { pgmNeIfPerformanceEntry 36 } - -pgmNeIfPollRandomIgnore OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of POLL packets not replied due to random - condition failing." - ::= { pgmNeIfPerformanceEntry 37 } - -pgmNeIfPollTsiStateError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of POLL packets discarded due to no - matching TSI state." - ::= { pgmNeIfPerformanceEntry 38 } - -pgmNeIfPollParentError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of POLL packets discarded due to - unknown parent." - ::= { pgmNeIfPerformanceEntry 39 } - -pgmNeIfPollTypeError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of POLL packets discarded due to failed - type matching." - ::= { pgmNeIfPerformanceEntry 40 } - -pgmNeIfPollError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of POLL packets discarded due to - operational error." - ::= { pgmNeIfPerformanceEntry 41 } - -pgmNeIfPollSuccess OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of successfully scheduled POLRs." - ::= { pgmNeIfPerformanceEntry 42 } - -pgmNeIfPollOriginated OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of polls originated on this interface." - ::= { pgmNeIfPerformanceEntry 43 } - -pgmNeIfPolrNoState OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of POLRs discarded due to no matching - state." - ::= { pgmNeIfPerformanceEntry 44 } - -pgmNeIfPolrError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of POLRs discarded due to operational - error." - ::= { pgmNeIfPerformanceEntry 45 } - -pgmNeIfPolrParityError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of parity POLRs received for non-parity - TSI." - ::= { pgmNeIfPerformanceEntry 46 } - -pgmNeIfPolrSuccess OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of POLRs recorded successfully." - ::= { pgmNeIfPerformanceEntry 47 } - -pgmNeIfPolrOriginated OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of POLRs originated by this interface." - ::= { pgmNeIfPerformanceEntry 48 } - -pgmNeIfNcfError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NCFs ignored due to no packet memory, - due to packet processing errors." - ::= { pgmNeIfPerformanceEntry 49 } - -pgmNeIfNcfParityError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NCFs ignored. Incremented when a parity - NCF is received on a session for which no parity - capability has been advertised in the session's - SPMs." - ::= { pgmNeIfPerformanceEntry 50 } - -pgmNeIfNcfPartialParity OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NCFs ignored due to not enough parity - blocks acknowledged." - ::= { pgmNeIfPerformanceEntry 51 } - -pgmNeIfNcfReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NCFs that confirm an outstanding NAK." - ::= { pgmNeIfPerformanceEntry 52 } - -pgmNeIfNcfAnticipated OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NCFs that cause NAK anticipation." - ::= { pgmNeIfPerformanceEntry 53 } - -pgmNeIfNcfRedirecting OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NCFs received as consequence of - redirected NAK." - ::= { pgmNeIfPerformanceEntry 54 } - -pgmNeIfNakEliminated OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAKs eliminated by retransmission - state." - ::= { pgmNeIfPerformanceEntry 55 } - -pgmNeIfNakError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of errors creating retransmission state - or NAK, due to NAK packet processing." - ::= { pgmNeIfPerformanceEntry 56 } - -pgmNeIfNakParityError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAKs ignored, due to no parity - available. Incremented when parity NAK is - received on this session, for which no parity - capability has been advartised." - ::= { pgmNeIfPerformanceEntry 57 } - -pgmNeIfNNakEliminated OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NNAKs eliminated by retransmission - state." - ::= { pgmNeIfPerformanceEntry 58 } - -pgmNeIfNNakError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of errors encountered creating - retransmission state OR nak." - ::= { pgmNeIfPerformanceEntry 59 } - -pgmNeIfNNakParityError OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of Null NAKs ignored, due to no parity - available. Incremented when parity NNAK is - received on this session, for which no parity - capability has been advartised." - ::= { pgmNeIfPerformanceEntry 60 } - -pgmNeIfNNakCongestionReports OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAKs forwarded as NNAK as congestion - report only." - ::= { pgmNeIfPerformanceEntry 61 } - -pgmNeIfNakRetryExpired OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NAKs timed out after - retrying." - ::= { pgmNeIfPerformanceEntry 62 } - -pgmNeIfNakRetryExpiredDLR OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAKs unconfirmed by DLR." - ::= { pgmNeIfPerformanceEntry 63 } - -pgmNeIfNakForwardedDLR OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAKs forwarded out this i/f to DLR - with retransmission state." - ::= { pgmNeIfPerformanceEntry 64 } - -pgmNeIfNakRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Total number of NAKs retransmitted out this i/f." - ::= { pgmNeIfPerformanceEntry 65 } - -pgmNeIfRdataEliminatedOIF OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of RDATA packets eliminated by lack of - OIF's." - ::= { pgmNeIfPerformanceEntry 66 } - -pgmNeIfRdataEliminatedSqn OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of RDATA packets eliminated by lack of - SQN." - ::= { pgmNeIfPerformanceEntry 67 } - -pgmNeIfInRdataFragments OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Total number of RDATA fragments received." - ::= { pgmNeIfPerformanceEntry 68 } - -pgmNeIfRdataFragmentsNoSessionErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of RDATA fragments eliminated by lack of - GSI." - ::= { pgmNeIfPerformanceEntry 69 } - -pgmNeIfRdataFragmentsEliminatedOIF OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of RDATA fragments eliminated by lack of - OIFs." - ::= { pgmNeIfPerformanceEntry 70 } - -pgmNeIfRdataFragmentsEliminatedSqn OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of RDATA fragments eliminated by lack of - SQN." - ::= { pgmNeIfPerformanceEntry 71 } - -pgmNeIfOutRdataFragments OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Total number of RDATA fragments forwarded." - ::= { pgmNeIfPerformanceEntry 72 } - --- --- PGM Network Element Transport Session Identifier --- -pgmNeTsi OBJECT IDENTIFIER ::= { pgmNetworkElement 101 } - -pgmNeTotalTsiNumberOfEntries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of sessions in the PGM NE TSI - table." - ::= { pgmNeTsi 1 } - --- The PGM Transport Session Identifier (TSI) table --- The TSI information is grouped into three major categories: --- fault, configuration and performance management. - --- The PGM NE TSI fault management table --- This table contains state and some general --- per TSI information - -pgmNeTsiTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmNeTsiEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per-tsi state information." - ::= {pgmNeTsi 2} - -pgmNeTsiEntry OBJECT-TYPE - SYNTAX PgmNeTsiEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Transport Session is identified by Global ID and - Source Port." - INDEX { pgmNeTsiGlobalId, pgmNeTsiDataSourcePort } - ::= { pgmNeTsiTable 1 } - -PgmNeTsiEntry ::= SEQUENCE { - pgmNeTsiGlobalId - OCTET STRING, - pgmNeTsiDataSourcePort - Unsigned32, - pgmNeTsiStateBits - BITS, - pgmNeTsiDataDestinationPort - Unsigned32, - pgmNeTsiSourceAddress - IpAddress, - pgmNeTsiGroupAddress - IpAddress, - pgmNeTsiUpstreamAddress - IpAddress, - pgmNeTsiUpstreamIfIndex - InterfaceIndex, - pgmNeTsiDlrAddress - IpAddress - } - -pgmNeTsiGlobalId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The Globally unique source identifier for this - transport session." - ::= {pgmNeTsiEntry 1 } - -pgmNeTsiDataSourcePort OBJECT-TYPE - SYNTAX Unsigned32 (0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Data source port." - ::= {pgmNeTsiEntry 2} - -pgmNeTsiStateBits OBJECT-TYPE - SYNTAX BITS { initialising(0), - spmSqnStateValid(1), - dlrCanProvideParity(2) } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "State associated with the TSI." - ::= {pgmNeTsiEntry 3 } - -pgmNeTsiDataDestinationPort OBJECT-TYPE - SYNTAX Unsigned32 (0..65535) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Data destination port." - ::= {pgmNeTsiEntry 4 } - -pgmNeTsiSourceAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "IP address of the source." - ::= {pgmNeTsiEntry 5 } - -pgmNeTsiGroupAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Multicast group destination address." - ::= {pgmNeTsiEntry 6 } - -pgmNeTsiUpstreamAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The IP address of the upstream PGM neighbouring - element for this TSI." - ::= { pgmNeTsiEntry 7 } - -pgmNeTsiUpstreamIfIndex OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The index of the upstream PGM element for the - entry." - ::= { pgmNeTsiEntry 8 } - -pgmNeTsiDlrAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "IP Address of a known DLR that will be used if - required." - ::= {pgmNeTsiEntry 9 } - - --- PGM Network Element TSI Configuration Management Table --- Since the Network Element cannot be configured --- per TSI, configuration table is not implemented - - --- PGM Network Element TSI Performance Management Table - -pgmNeTsiPerformanceTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmNeTsiPerformanceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding details of every transport - flow known by the Network Element." - ::= {pgmNeTsi 4} - -pgmNeTsiPerformanceEntry OBJECT-TYPE - SYNTAX PgmNeTsiPerformanceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Transport session description." - INDEX { pgmNeTsiPerformanceGlobalId, - pgmNeTsiPerformanceDataSourcePort } - ::= { pgmNeTsiPerformanceTable 1 } - -PgmNeTsiPerformanceEntry ::= SEQUENCE { - pgmNeTsiPerformanceGlobalId - OCTET STRING, - pgmNeTsiPerformanceDataSourcePort - Unsigned32, - pgmNeTsiSessionTrailEdgeSeq - Counter32, - pgmNeTsiSessionIncrSeq - Counter32, - pgmNeTsiLeadEdgeSeq - Counter32, - pgmNeTsiInSpms - Counter32, - pgmNeTsiOutSpms - Counter32, - pgmNeTsiInParitySpms - Counter32, - pgmNeTsiOutParitySpms - Counter32, - pgmNeTsiTotalReXmitStates - Counter32, - pgmNeTsiTotalReXmitTimedOut - Counter32, - pgmNeTsiInRdata - Counter32, - pgmNeTsiOutRdata - Counter32, - pgmNeTsiInParityRdata - Counter32, - pgmNeTsiOutParityRdata - Counter32, - pgmNeTsiInRdataNoStateErrors - Counter32, - pgmNeTsiUniqueNaks - Counter32, - pgmNeTsiInNaks - Counter32, - pgmNeTsiOutNaks - Counter32, - pgmNeTsiUniqueParityNaks - Counter32, - pgmNeTsiInParityNaks - Counter32, - pgmNeTsiOutParityNaks - Counter32, - pgmNeTsiInNakSeqErrors - Counter32, - pgmNeTsiInNnaks - Counter32, - pgmNeTsiOutNnaks - Counter32, - pgmNeTsiInParityNnaks - Counter32, - pgmNeTsiOutParityNnaks - Counter32, - pgmNeTsiInNcfs - Counter32, - pgmNeTsiOutNcfs - Counter32, - pgmNeTsiInParityNcfs - Counter32, - pgmNeTsiOutParityNcfs - Counter32, - pgmNeTsiSpmSequenceNumber - Unsigned32, - pgmNeTsiTransmissionGroupSize - Unsigned32, - pgmNeTsiTimeout - TimeTicks, - pgmNeTsiLastTtl - Unsigned32, - pgmNeTsiLinkLossRate - Unsigned32, - pgmNeTsiPathLossRate - Unsigned32, - pgmNeTsiReceiverLossRate - Unsigned32, - pgmNeTsiCongestionReportLead - Unsigned32, - pgmNeTsiCongestionReportWorstReceiver - IpAddress -} - -pgmNeTsiPerformanceGlobalId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The Globally unique source identifier for this - transport session." - ::= {pgmNeTsiPerformanceEntry 1 } - -pgmNeTsiPerformanceDataSourcePort OBJECT-TYPE - SYNTAX Unsigned32 (0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Data source port." - ::= {pgmNeTsiPerformanceEntry 2} - -pgmNeTsiSessionTrailEdgeSeq OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The trailing edge sequence of the transmit - window." - ::= { pgmNeTsiPerformanceEntry 3 } - -pgmNeTsiSessionIncrSeq OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The sequence number defining the leading edge of - the increment window." - ::= { pgmNeTsiPerformanceEntry 4 } - -pgmNeTsiLeadEdgeSeq OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The leading edge sequence of the transmit - window." - ::= { pgmNeTsiPerformanceEntry 5 } - -pgmNeTsiInSpms OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of SPMs received for this - session." - ::= { pgmNeTsiPerformanceEntry 6 } - -pgmNeTsiOutSpms OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of SPMs sent out for this - session." - ::= { pgmNeTsiPerformanceEntry 7 } - -pgmNeTsiInParitySpms OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of Parity SPMs received for - this session." - ::= { pgmNeTsiPerformanceEntry 8 } - -pgmNeTsiOutParitySpms OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of Parity SPMs sent out for - this session." - ::= { pgmNeTsiPerformanceEntry 9 } - -pgmNeTsiTotalReXmitStates OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total retransmit states for this session." - ::= { pgmNeTsiPerformanceEntry 10 } - -pgmNeTsiTotalReXmitTimedOut OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total timed-out retransmit state entries for - this session." - ::= { pgmNeTsiPerformanceEntry 11 } - -pgmNeTsiInRdata OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of RDATAs received for this - session." - ::= { pgmNeTsiPerformanceEntry 12 } - -pgmNeTsiOutRdata OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of RDATAs sent out from this - session." - ::= { pgmNeTsiPerformanceEntry 13 } - -pgmNeTsiInParityRdata OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity RDATAs received for - this session." - ::= { pgmNeTsiPerformanceEntry 14 } - -pgmNeTsiOutParityRdata OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity RDATAs sent out from - this session." - ::= { pgmNeTsiPerformanceEntry 15 } - -pgmNeTsiInRdataNoStateErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of received RDATA discarded - due to no retransmit state." - ::= { pgmNeTsiPerformanceEntry 16 } - -pgmNeTsiUniqueNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of unique NAKs received for - this session." - ::= { pgmNeTsiPerformanceEntry 17 } - -pgmNeTsiInNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NAKs received for this - session." - ::= { pgmNeTsiPerformanceEntry 18 } - -pgmNeTsiOutNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NAKs sent out from this - session." - ::= { pgmNeTsiPerformanceEntry 19 } - -pgmNeTsiUniqueParityNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of unique parity NAKs received - for this session." - ::= { pgmNeTsiPerformanceEntry 20 } - -pgmNeTsiInParityNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity NAKs received for - this session." - ::= { pgmNeTsiPerformanceEntry 21 } - -pgmNeTsiOutParityNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity NAKs sent out from - this session." - ::= { pgmNeTsiPerformanceEntry 22 } - -pgmNeTsiInNakSeqErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of received NAKs discarded - because of out of sequence (out of retransmit - window)." - ::= { pgmNeTsiPerformanceEntry 23 } - -pgmNeTsiInNnaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NNAKs received for this - session." - ::= { pgmNeTsiPerformanceEntry 24 } - -pgmNeTsiOutNnaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NNAKs sent out from this - session." - ::= { pgmNeTsiPerformanceEntry 25 } - -pgmNeTsiInParityNnaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity NNAKs received for - this session." - ::= { pgmNeTsiPerformanceEntry 26 } - -pgmNeTsiOutParityNnaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity NNAKs sent out from - this session." - ::= { pgmNeTsiPerformanceEntry 27 } - -pgmNeTsiInNcfs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NCFs received for this - session." - ::= { pgmNeTsiPerformanceEntry 28 } - -pgmNeTsiOutNcfs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of NCFs sent out from this - session." - ::= { pgmNeTsiPerformanceEntry 29 } - -pgmNeTsiInParityNcfs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of parity NCFs received for - this session." - ::= { pgmNeTsiPerformanceEntry 30 } - -pgmNeTsiOutParityNcfs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of Parity NCFs sent out from - this session." - ::= { pgmNeTsiPerformanceEntry 31 } - -pgmNeTsiSpmSequenceNumber OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Sequence number of the last seen SPM." - ::= {pgmNeTsiPerformanceEntry 32 } - -pgmNeTsiTransmissionGroupSize OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Advertised size of the transmission group for - this transport session." - ::= {pgmNeTsiPerformanceEntry 33 } - -pgmNeTsiTimeout OBJECT-TYPE - SYNTAX TimeTicks - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Time left for this entry to expire." - ::= {pgmNeTsiPerformanceEntry 34 } - -pgmNeTsiLastTtl OBJECT-TYPE - SYNTAX Unsigned32(1..255) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "IP TTL of last seen valid SPM." - ::= {pgmNeTsiPerformanceEntry 35 } - -pgmNeTsiLinkLossRate OBJECT-TYPE - SYNTAX Unsigned32(0..100) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Worst reported link loss rate for congestion - control. This is reported as a percentage." - ::= {pgmNeTsiPerformanceEntry 36 } - -pgmNeTsiPathLossRate OBJECT-TYPE - SYNTAX Unsigned32 (0..100) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Worst reported path loss rate for congestion - control. This is reported as a percentage." - ::= {pgmNeTsiPerformanceEntry 37 } - -pgmNeTsiReceiverLossRate OBJECT-TYPE - SYNTAX Unsigned32 (0..100) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Worst reported receiver loss rate for congestion - control. This is reported as a percentage." - ::= {pgmNeTsiPerformanceEntry 38 } - -pgmNeTsiCongestionReportLead OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Data lead sequence number associated with the - worst reported receiver loss rate." - ::= {pgmNeTsiPerformanceEntry 39 } - -pgmNeTsiCongestionReportWorstReceiver OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "IP address of the receiver that reported the - worst receiver loss rate." - ::= {pgmNeTsiPerformanceEntry 40 } - --- The PGM Retransmission table - --- The PGM Retransmission table contains --- information about current retransmission requests. --- This information is held per sequence number, or in --- the case of FEC, every transmission group, for which --- retransmission has been requested. - -pgmNeTsiRtxNumberOfEntries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of entries in the retransmission table." - ::= { pgmNeTsi 5 } - -pgmNeTsiRtxTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmNeTsiRtxEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding information for every sequence - number, or in the case of FEC, every - transmission group, for which retransmission has - been requested." - ::= {pgmNeTsi 6 } - -pgmNeTsiRtxEntry OBJECT-TYPE - SYNTAX PgmNeTsiRtxEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per sequence number / transmission group - information." - INDEX { pgmNeTsiGlobalId, - pgmNeTsiDataSourcePort, - pgmNeTsiRtxSequenceNumber, - pgmNeTsiRtxSequenceNumberType } - ::= { pgmNeTsiRtxTable 1 } - -PgmNeTsiRtxEntry ::= SEQUENCE { - pgmNeTsiRtxSequenceNumber - Unsigned32, - pgmNeTsiRtxSequenceNumberType - INTEGER, - pgmNeTsiRtxReqParityTgCount - Counter32, - pgmNeTsiRtxTimeout - TimeTicks, - pgmNeTsiRtxStateBits - BITS -} - -pgmNeTsiRtxSequenceNumber OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "For non-parity retransmission, a sequence number. - For parity retransmission, a transmission group - and packet count." - ::= {pgmNeTsiRtxEntry 1 } - -pgmNeTsiRtxSequenceNumberType OBJECT-TYPE - SYNTAX INTEGER { - selective(1), - tg(2) - } - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Selective Sequence Number and TG Sequence - Number." - ::= {pgmNeTsiRtxEntry 2 } - -pgmNeTsiRtxReqParityTgCount OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The Requested number of missing parity packets - of specific Tg. The largest counter of the - received NAK will be stored in this mib. This - variable is valid for parity packets only." - ::= { pgmNeTsiRtxEntry 4 } - -pgmNeTsiRtxTimeout OBJECT-TYPE - SYNTAX TimeTicks - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "When this state will expire." - ::= {pgmNeTsiRtxEntry 5 } - -pgmNeTsiRtxStateBits OBJECT-TYPE - SYNTAX BITS { - initialising(0), - eliminating(1), - redirecting(2), - stateCreatedByNullNAK(3), - listNAKentry(4), - parityState(5) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "State associated with retransmission entry." - ::= {pgmNeTsiRtxEntry 6 } - --- The PGM Retransmission interfaces table - --- The PGM Retransmission interfaces table contains --- information about what interfaces will be sent --- retransmitted data for a particular --- retransmission entry - -pgmNeTsiRtxIfNumberOfEntries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of entries in the retransmission - interfaces table." - ::= { pgmNeTsi 7 } - -pgmNeTsiRtxIfTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmNeTsiRtxIfEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding information of every - interface for which retransmit state for - a particular sequence number or transmission - group has to be sent." - ::= {pgmNeTsi 8} - -pgmNeTsiRtxIfEntry OBJECT-TYPE - SYNTAX PgmNeTsiRtxIfEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Destination interfaces for a particular - retransmit state." - INDEX { pgmNeTsiGlobalId, - pgmNeTsiDataSourcePort, - pgmNeTsiRtxSequenceNumber, - pgmNeTsiRtxSequenceNumberType, - pgmNeTsiRtxIfIndex } - ::= { pgmNeTsiRtxIfTable 1 } - -PgmNeTsiRtxIfEntry ::= SEQUENCE { - pgmNeTsiRtxIfIndex - InterfaceIndex, - pgmNeTsiRtxIfPacketCount - Counter32 -} - -pgmNeTsiRtxIfIndex OBJECT-TYPE - SYNTAX InterfaceIndex - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "A unique value for each interface. Its value - ranges between 1 and the value of ifNumber. - The value for each interface must remain - constant at least from one re-initialization - of the entity's network management system to - the next re-initialization." - ::= { pgmNeTsiRtxIfEntry 1 } - -pgmNeTsiRtxIfPacketCount OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of repair data packets still to be - retransmitted on this interface. For non-parity - retransmission this will never have a value - greater than 1. For parity retransmission, - any number can be present." - ::= { pgmNeTsiRtxIfEntry 2 } - --- The PGM Poll Response table - --- The PGM Poll Response table contains information --- about PGM parent's of this network element who are --- currently polling it. - -pgmNeTsiPolrNumberOfEntries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of entries in the poll response table." - ::= { pgmNeTsi 9 } - -pgmNeTsiPolrTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmNeTsiPolrEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding state information about what - PGM parents are polling this Network Element." - ::= { pgmNeTsi 10 } - -pgmNeTsiPolrEntry OBJECT-TYPE - SYNTAX PgmNeTsiPolrEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "State information for a Network Element that - is being polled by its parents" - INDEX { pgmNeTsiGlobalId, - pgmNeTsiDataSourcePort, - pgmNeTsiPolrSource } - ::= { pgmNeTsiPolrTable 1 } - -PgmNeTsiPolrEntry ::= SEQUENCE { - pgmNeTsiPolrSource - IpAddress, - pgmNeTsiPolrSequenceNumber - Unsigned32 -} - -pgmNeTsiPolrSource OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "IP Address of parent who is polling this - device." - ::= { pgmNeTsiPolrEntry 1 } - -pgmNeTsiPolrSequenceNumber OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Sequence number of last POLR from the source." - ::= { pgmNeTsiPolrEntry 2 } - --- The PGM Poll table - --- The PGM Poll table contains information related to --- polling that this Network Element is doing for --- its children - -pgmNeTsiPollNumberOfEntries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of entries in the poll table." - ::= { pgmNeTsi 11 } - -pgmNeTsiPollTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmNeTsiPollEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding state information related - to polling that this Network Element is doing - for its children." - ::= { pgmNeTsi 12 } - -pgmNeTsiPollEntry OBJECT-TYPE - SYNTAX PgmNeTsiPollEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "State information for a Network Element that - is polling its children." - INDEX { pgmNeTsiGlobalId, - pgmNeTsiDataSourcePort, - pgmNeTsiPollType } - ::= { pgmNeTsiPollTable 1 } - -PgmNeTsiPollEntry ::= SEQUENCE { - pgmNeTsiPollType - INTEGER, - pgmNeTsiPollSequence - Unsigned32, - pgmNeTsiPollChildBackoff - Unsigned32, - pgmNeTsiPollMask - Unsigned32, - pgmNeTsiPollPeriod - Unsigned32, - pgmNeTsiPollCount - Counter32, - pgmNeTsiPollTimeout - TimeTicks -} - -pgmNeTsiPollType OBJECT-TYPE - SYNTAX INTEGER { - general(1), - dlr(2) - } - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Type of Poll." - ::= { pgmNeTsiPollEntry 1 } - -pgmNeTsiPollSequence OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Sequence number of the most recent POLL packet - that we sent." - ::= { pgmNeTsiPollEntry 2 } - -pgmNeTsiPollChildBackoff OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Backoff advertised to be used by child of poll." - ::= { pgmNeTsiPollEntry 3 } - -pgmNeTsiPollMask OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Mask being used in poll." - ::= { pgmNeTsiPollEntry 4 } - -pgmNeTsiPollPeriod OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Period of poll." - ::= { pgmNeTsiPollEntry 5 } - -pgmNeTsiPollCount OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of Poll responses (POLRs) received." - ::= { pgmNeTsiPollEntry 6 } - -pgmNeTsiPollTimeout OBJECT-TYPE - SYNTAX TimeTicks - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Remaining Time Ticks to next poll." - ::= { pgmNeTsiPollEntry 7 } - - --- --- PGM Source --- - --- PGM Source general management information - - -pgmSourceSaveDefaults OBJECT-TYPE - SYNTAX INTEGER { initial (1), - save (2), - pending (3), - success (4), - failure (5) } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Flag used to initiate the storing - of all default variable values to - non-volatile storage and to report the - result of the operation. - The following values can only be read, - never written : - initial(1) - returned prior to any requests - for saving the default configuration - pending(3) - saving in progress - success(4) - returned when a save(2) request - is successful - failure(5) - returned when a save(2) request - is unsuccessful - - The following values can only be written, - never read : - save(2) - to indicate that the default - configuration should be saved." - ::= { pgmSource 1 } - -pgmSourceLastUpdateTime OBJECT-TYPE - SYNTAX TimeTicks - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of TimeTicks since the last update - of the non-volatile storage." - ::= { pgmSource 2 } - -pgmSourceDefaultTtl OBJECT-TYPE - SYNTAX Unsigned32(1..255) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Default TTL used by the PGM Source." - ::= { pgmSource 3 } - -pgmSourceDefaultAdvMode OBJECT-TYPE - SYNTAX INTEGER { data(1), - time(2), - applctrl(3), - other(4) } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Flag to indicate that the transmit window is - advanced with data, by time, under application - control, or any other method." - ::= { pgmSource 4 } - -pgmSourceDefaultLateJoin OBJECT-TYPE - SYNTAX INTEGER { - enable(1), - disable(2) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Flag to indicate whether or not the sender will - accept late joiners." - ::= { pgmSource 5 } - -pgmSourceDefaultTxwMaxRte OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Maximum transmit rate in bytes/second." - ::= { pgmSource 6 } - -pgmSourceDefaultTxwSecs OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Transmit window size in seconds." - ::= { pgmSource 7 } - -pgmSourceDefaultTxwAdvSecs OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Transmit window advance in seconds. This value - should always be set to a value smaller than - the pgmSourceTxwSecs." - ::= { pgmSource 8 } - -pgmSourceDefaultAdvIvl OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Advance interval in milliseconds. Always a - valid parameter when advancing with time. - Valid only in cases of absence of lost data - when advancing with data." - ::= { pgmSource 9 } - -pgmSourceDefaultSpmIvl OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "SPM interval in milliseconds." - ::= { pgmSource 10 } - -pgmSourceDefaultSpmHeartBeatIvlMin OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "SPM heartbeat interval in milliseconds." - ::= { pgmSource 11 } - -pgmSourceDefaultSpmHeartBeatIvlMax OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Maximum SPM heartbeat interval in milliseconds." - ::= { pgmSource 12 } - -pgmSourceDefaultRdataBackoffIvl OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "RDATA backoff interval in milliseconds." - ::= { pgmSource 13 } - -pgmSourceDefaultFECProactiveParitySize OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Number of proactive parity messages per FEC - block." - ::= { pgmSource 14 } - -pgmSourceDefaultGroupAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The default IP Multicast group address - used by the sender." - ::= { pgmSource 15 } - -pgmSourceUpdateSinceLastSave OBJECT-TYPE - SYNTAX INTEGER - { - notUpdated(1), - updated(2) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Specifies if any of the Source Default - variables have been updated or not, - since the last successful pgmSourceSaveDefaults. - notUpdated - none of the default Source - variables were set after the last - successful save to a non-volatile - storage. - updated - at least one of the default Source - variables were set after the last - successful save to a non-volatile - storage." - ::= { pgmSource 16 } - --- PGM Source per TSI management information - -pgmSourceTsi OBJECT IDENTIFIER ::= { pgmSource 100 } - -pgmSourceNumberOfEntries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of PGM Source sessions." - ::= { pgmSourceTsi 1 } - --- PGM Source Fault Management Table - -pgmSourceTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmSourceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per TSI fault - management and general information - related to PGM Source." - ::= {pgmSourceTsi 2} - -pgmSourceEntry OBJECT-TYPE - SYNTAX PgmSourceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per PGM sender information." - INDEX { pgmSourceGlobalId, - pgmSourceSourcePort } - ::= { pgmSourceTable 1 } - -PgmSourceEntry ::= SEQUENCE { - pgmSourceGlobalId - OCTET STRING, - pgmSourceSourcePort - Unsigned32, - pgmSourceSourceAddress - IpAddress, - pgmSourceGroupAddress - IpAddress, - pgmSourceDestPort - Unsigned32, - pgmSourceSourceGsi - OCTET STRING, - pgmSourceSourcePortNumber - Unsigned32 - } - -pgmSourceGlobalId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Globally unique session identifier (GSI)." - ::= { pgmSourceEntry 1 } - -pgmSourceSourcePort OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmSourceEntry 2 } - -pgmSourceSourceAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Source IP address." - ::= { pgmSourceEntry 3 } - -pgmSourceGroupAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "IP Multicast group address used by the - sender." - ::= { pgmSourceEntry 4 } - -pgmSourceDestPort OBJECT-TYPE - SYNTAX Unsigned32 (0..65535) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Destination port number." - ::= { pgmSourceEntry 5 } - -pgmSourceSourceGsi OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Globally unique session identifier (GSI)." - ::= { pgmSourceEntry 6 } - -pgmSourceSourcePortNumber OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmSourceEntry 7 } - - --- PGM Source Configuration Management Table - -pgmSourceConfigTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmSourceConfigEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per TSI - configuration information - related to the PGM Source." - ::= {pgmSourceTsi 3} - -pgmSourceConfigEntry OBJECT-TYPE - SYNTAX PgmSourceConfigEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per PGM sender information." - INDEX { pgmSourceConfigGlobalId, - pgmSourceConfigSourcePort } - ::= { pgmSourceConfigTable 1 } - -PgmSourceConfigEntry ::= SEQUENCE { - pgmSourceConfigGlobalId - OCTET STRING, - pgmSourceConfigSourcePort - Unsigned32, - pgmSourceTtl - Unsigned32, - pgmSourceAdvMode - INTEGER, - pgmSourceLateJoin - INTEGER, - pgmSourceTxwMaxRte - Unsigned32, - pgmSourceTxwSecs - Unsigned32, - pgmSourceTxwAdvSecs - Unsigned32, - pgmSourceAdvIvl - Unsigned32, - pgmSourceSpmIvl - Unsigned32, - pgmSourceSpmHeartBeatIvlMin - Unsigned32, - pgmSourceSpmHeartBeatIvlMax - Unsigned32, - pgmSourceRdataBackoffIvl - Unsigned32, - pgmSourceFEC - INTEGER, - pgmSourceFECTransmissionGrpSize - Unsigned32, - pgmSourceFECProactiveParitySize - Unsigned32, - pgmSourceSpmPathAddress - IpAddress - } - -pgmSourceConfigGlobalId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Globally unique session identifier (GSI)." - ::= { pgmSourceConfigEntry 1 } - -pgmSourceConfigSourcePort OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmSourceConfigEntry 2 } - -pgmSourceTtl OBJECT-TYPE - SYNTAX Unsigned32(1..255) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "TTL used by sender." - ::= { pgmSourceConfigEntry 3 } - -pgmSourceAdvMode OBJECT-TYPE - SYNTAX INTEGER { data(1), - time(2), - applctrl(3), - other(4) } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Flag to indicate that the transmit window is - advanced with data, by time, under application - control, or any other method." - ::= { pgmSourceConfigEntry 4 } - -pgmSourceLateJoin OBJECT-TYPE - SYNTAX INTEGER { - enable(1), - disable(2) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Flag to indicate whether or not the sender will - accept late joiners." - ::= { pgmSourceConfigEntry 5 } - -pgmSourceTxwMaxRte OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Maximum transmit rate in bytes/second." - ::= { pgmSourceConfigEntry 6 } - -pgmSourceTxwSecs OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Transmit window size in seconds." - ::= { pgmSourceConfigEntry 7 } - -pgmSourceTxwAdvSecs OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Transmit window advance in seconds. This value - should always be set to a value smaller than - the pgmSourceTxwSecs." - ::= { pgmSourceConfigEntry 8 } - -pgmSourceAdvIvl OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Advance interval in milliseconds. Always a - valid parameter when advancing with time. - Valid only in cases of absence of lost data - when advancing with data." - ::= { pgmSourceConfigEntry 9 } - -pgmSourceSpmIvl OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "SPM interval in milliseconds." - ::= { pgmSourceConfigEntry 10 } - -pgmSourceSpmHeartBeatIvlMin OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "SPM heartbeat interval in milliseconds." - ::= { pgmSourceConfigEntry 11 } - -pgmSourceSpmHeartBeatIvlMax OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Maximum SPM heartbeat interval in milliseconds." - ::= { pgmSourceConfigEntry 12 } - -pgmSourceRdataBackoffIvl OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "RDATA backoff interval in milliseconds." - ::= { pgmSourceConfigEntry 13 } - -pgmSourceFEC OBJECT-TYPE - SYNTAX INTEGER { disabled(1), - enabledFixedPacketSize(2), - enabledVariablePacketSize(3) } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Flag to indicate whether or not FEC is enabled - and whether it supports variable or fixed size - messages." - ::= { pgmSourceConfigEntry 14 } - -pgmSourceFECTransmissionGrpSize OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "FEC transmission group size." - ::= { pgmSourceConfigEntry 15 } - -pgmSourceFECProactiveParitySize OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Number of proactive parity messages per FEC - block." - ::= { pgmSourceConfigEntry 16 } - -pgmSourceSpmPathAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Ip Address for the NAKs to be sent, - in case that NE is not set." - ::= { pgmSourceConfigEntry 17 } - --- PGM Source Performance Management Table - -pgmSourcePerformanceTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmSourcePerformanceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per TSI performance - information related to the PGM Source." - ::= {pgmSourceTsi 4} - -pgmSourcePerformanceEntry OBJECT-TYPE - SYNTAX PgmSourcePerformanceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per PGM sender information." - INDEX { pgmSourcePerformanceGlobalId, - pgmSourcePerformanceSourcePort } - ::= { pgmSourcePerformanceTable 1 } - -PgmSourcePerformanceEntry ::= SEQUENCE { - pgmSourcePerformanceGlobalId - OCTET STRING, - pgmSourcePerformanceSourcePort - Unsigned32, - pgmSourceDataBytesSent - Counter32, - pgmSourceDataMsgsSent - Counter32, - pgmSourceBytesBuffered - Counter32, - pgmSourceMsgsBuffered - Counter32, - pgmSourceBytesRetransmitted - Counter32, - pgmSourceMsgsRetransmitted - Counter32, - pgmSourceBytesSent - Counter32, - pgmSourceRawNaksReceived - Counter32, - pgmSourceNaksIgnored - Counter32, - pgmSourceCksumErrors - Counter32, - pgmSourceMalformedNaks - Counter32, - pgmSourcePacketsDiscarded - Counter32, - pgmSourceNaksRcvd - Counter32, - pgmSourceParityBytesRetransmitted - Counter32, - pgmSourceSelectiveBytesRetransmited - Counter32, - pgmSourceParityMsgsRetransmitted - Counter32, - pgmSourceSelectiveMsgsRetransmitted - Counter32, - pgmSourceBytesAdmit - Counter32, - pgmSourceMsgsAdmit - Counter32, - pgmSourceParityNakPacketsReceived - Counter32, - pgmSourceSelectiveNakPacketsReceived - Counter32, - pgmSourceParityNaksReceived - Counter32, - pgmSourceSelectiveNaksReceived - Counter32, - pgmSourceParityNaksIgnored - Counter32, - pgmSourceSelectiveNaksIgnored - Counter32, - pgmSourceAckErrors - Counter32, - pgmSourcePgmCCAcker - IpAddress, - pgmSourceTransmissionCurrentRate - Counter32, - pgmSourceAckPacketsReceived - Counter32, - pgmSourceNNakPacketsReceived - Counter32, - pgmSourceParityNNakPacketsReceived - Counter32, - pgmSourceSelectiveNNakPacketsReceived - Counter32, - pgmSourceNNaksReceived - Counter32, - pgmSourceParityNNaksReceived - Counter32, - pgmSourceSelectiveNNaksReceived - Counter32, - pgmSourceNNakErrors - Counter32 -} - -pgmSourcePerformanceGlobalId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Globally unique source identifier (GSI)." - ::= { pgmSourcePerformanceEntry 1 } - -pgmSourcePerformanceSourcePort OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmSourcePerformanceEntry 2 } - -pgmSourceDataBytesSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of data bytes sent for this TSI." - ::= { pgmSourcePerformanceEntry 3 } - -pgmSourceDataMsgsSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of data messages sent for this TSI." - ::= { pgmSourcePerformanceEntry 4 } - -pgmSourceBytesBuffered OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes currently buffered for this - TSI." - ::= { pgmSourcePerformanceEntry 5 } - -pgmSourceMsgsBuffered OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of messages currently buffered for - this TSI." - ::= { pgmSourcePerformanceEntry 6 } - -pgmSourceBytesRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes retransmitted for this TSI." - ::= { pgmSourcePerformanceEntry 7 } - -pgmSourceMsgsRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of messages retransmitted for this TSI." - ::= { pgmSourcePerformanceEntry 8 } - -pgmSourceBytesSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of bytes send for this TSI. Includes - IP header and non-data messages." - ::= { pgmSourcePerformanceEntry 9 } - -pgmSourceRawNaksReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Raw number of NAK packets received." - ::= { pgmSourcePerformanceEntry 10 } - -pgmSourceNaksIgnored OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of ignored Naks for this TSI, due to - duplicate NAKs reception." - ::= { pgmSourcePerformanceEntry 11 } - -pgmSourceCksumErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of checksum errors for this TSI." - ::= { pgmSourcePerformanceEntry 12 } - -pgmSourceMalformedNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of malformed NAK packets." - ::= { pgmSourcePerformanceEntry 13 } - -pgmSourcePacketsDiscarded OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of discarded data packets. This counter - is used to count all discarded incoming packets - per TSI in cases of duplicates, header and - packet errors, etc." - ::= { pgmSourcePerformanceEntry 14 } - -pgmSourceNaksRcvd OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of Sequence Numbers NAKed." - ::= { pgmSourcePerformanceEntry 15 } - -pgmSourceParityBytesRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes sent in parity retransmissions." - ::= { pgmSourcePerformanceEntry 16 } - -pgmSourceSelectiveBytesRetransmited OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes sent in selective retransmissions." - ::= { pgmSourcePerformanceEntry 17 } - -pgmSourceParityMsgsRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of parity retransmissions sent." - ::= { pgmSourcePerformanceEntry 18 } - -pgmSourceSelectiveMsgsRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of selective retransmissions sent." - ::= { pgmSourcePerformanceEntry 19 } - -pgmSourceBytesAdmit OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes currently in the rate controled - admit queue. Includes IP header, UDP header if - encapsulated, PGM header, and data." - ::= { pgmSourcePerformanceEntry 20 } - -pgmSourceMsgsAdmit OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of messages currently in the rate controled - admit queue. Includes data messages, retransmissions, - and SPMs." - ::= { pgmSourcePerformanceEntry 21 } - -pgmSourceParityNakPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of parity NAK packets received." - ::= { pgmSourcePerformanceEntry 22 } - -pgmSourceSelectiveNakPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of selective NAK packets received." - ::= { pgmSourcePerformanceEntry 23 } - -pgmSourceParityNaksReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual parity NAKs received." - ::= { pgmSourcePerformanceEntry 24 } - -pgmSourceSelectiveNaksReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual selective NAKs received." - ::= { pgmSourcePerformanceEntry 25 } - -pgmSourceParityNaksIgnored OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual parity NAKs ignored." - ::= { pgmSourcePerformanceEntry 26 } - -pgmSourceSelectiveNaksIgnored OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual selective NAKs ignored." - ::= { pgmSourcePerformanceEntry 27 } - -pgmSourceAckErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of ACK packets received with error in - them, different than checksum error." - ::= { pgmSourcePerformanceEntry 28 } - -pgmSourcePgmCCAcker OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Ip Address of the currently designated pgm - congestion control ACKER." - ::= { pgmSourcePerformanceEntry 29 } - -pgmSourceTransmissionCurrentRate OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Current transmission rate." - ::= { pgmSourcePerformanceEntry 30 } - -pgmSourceAckPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of ACK packets received." - ::= { pgmSourcePerformanceEntry 31 } - -pgmSourceNNakPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of Null NAKs received." - ::= { pgmSourcePerformanceEntry 32 } - -pgmSourceParityNNakPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of parity Null NAK packets received." - ::= { pgmSourcePerformanceEntry 33 } - -pgmSourceSelectiveNNakPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of selective Null NAK packets received." - ::= { pgmSourcePerformanceEntry 34 } - -pgmSourceNNaksReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual NAKs, received in Null - NAK packets." - ::= { pgmSourcePerformanceEntry 35 } - -pgmSourceParityNNaksReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual parity NAKs, - received in Null NAK packets." - ::= { pgmSourcePerformanceEntry 36 } - -pgmSourceSelectiveNNaksReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual NAKs, - received in Null NAK packets." - ::= { pgmSourcePerformanceEntry 37 } - -pgmSourceNNakErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of Null NAK packets received that contain - error, different than checksum error." - ::= { pgmSourcePerformanceEntry 38 } - --- --- PGM Receiver --- - --- PGM Receiver general management information - -pgmReceiverSaveDefaults OBJECT-TYPE - SYNTAX INTEGER { initial (1), - save (2), - pending (3), - success (4), - failure (5) } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Flag used to initiate the storing - of all default variable values to - non-volatile storage and to report the - result of the operation. - The following values can only be read, - never written : - initial(1) - returned prior to any requests - for saving the default configuration - pending(3) - saving in progress - success(4) - returned when a save(2) request - is successful - failure(5) - returned when a save(2) request - is unsuccessful - - The following values can only be written, - never read : - save(2) - to indicate that the default - configuration should be saved." - ::= { pgmReceiver 1 } - -pgmReceiverLastUpdateTime OBJECT-TYPE - SYNTAX TimeTicks - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of TimeTicks since the last update - of the non-volatile storage." - ::= { pgmReceiver 2 } - -pgmReceiverDefaultNakBackoffIvl OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "NAK random backoff interval." - ::= { pgmReceiver 3 } - -pgmReceiverDefaultNakRepeatIvl OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "NAK repeat interval." - ::= { pgmReceiver 4 } - -pgmReceiverDefaultNakNcfRetries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Max NAK retries while witing for matching NCF." - ::= { pgmReceiver 5 } - -pgmReceiverDefaultNakRdataIvl OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Default NAK RDATA interval, i.e the amount of - time to cease NAKs for a particular piece of - data after a corresponding NCF has been received." - ::= { pgmReceiver 6 } - -pgmReceiverDefaultNakDataRetries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Max NAK retries while waiting for missing data." - ::= { pgmReceiver 7 } - -pgmReceiverDefaultSendNaks OBJECT-TYPE - SYNTAX INTEGER { - enabled(1), - disabled(2) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Flag to indicate whether or not receiver should - send NAKs or be totally passive." - ::= { pgmReceiver 8 } - -pgmReceiverDefaultLateJoin OBJECT-TYPE - SYNTAX INTEGER { - enabled(1), - disabled(2) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Flag to indicate whether or not the receiver - should wait for a OPT_JOIN SPM before - attempting to late join." - ::= { pgmReceiver 9 } - -pgmReceiverDefaultNakTtl OBJECT-TYPE - SYNTAX Unsigned32(1..255) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "TTL on NAK packets sent for loss." - ::= { pgmReceiver 10 } - -pgmReceiverDefaultDeliveryOrder OBJECT-TYPE - SYNTAX INTEGER { - unordered(1), - ordered(2) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Packet Delivery Order for the receiving - application." - ::= { pgmReceiver 11 } - -pgmReceiverDefaultNextPgmHop OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Next hop PGM router address. This option - sets the default address to send NAKs to, - instead of sending to the last hop address." - ::= { pgmReceiver 12 } - -pgmReceiverDefaultGroupAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Default IP Multicast group address - used by the sender." - ::= { pgmReceiver 13 } - -pgmReceiverUpdateSinceLastSave OBJECT-TYPE - SYNTAX INTEGER - { - notUpdated(1), - updated(2) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Specifies if any of the Receiver Default - variables have been updated or not, - since the last successful pgmSourceSaveDefaults. - notUpdated - none of the default Receiver - variables were set after the last - successful save to a non-volatile - storage. - updated - at least one of the default Receiver - variables were set after the last - successful save to a non-volatile - storage." - ::= { pgmReceiver 14 } - -pgmReceiverDefaultNakFailureThresholdTimer OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Timer that defines the default - interval of time during which unrecoverable - lost packets are monitored - for purposes of SNMP trap generation." - ::= { pgmReceiver 15 } - -pgmReceiverDefaultNakFailureThreshold OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The default number of unrecoverable - lost packets within the defined interval - after which an SNMP trap is generated." - ::= { pgmReceiver 16 } - - --- PGM Receiver per Receiver management information - -pgmReceiverTsi OBJECT IDENTIFIER ::= { pgmReceiver 100 } - -pgmReceiverNumberOfEntries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of PGM Receivers." - ::= { pgmReceiverTsi 1 } - --- PGM Receiver Fault Management Table - -pgmReceiverTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmReceiverEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per TSI fault - management and general information - related to the PGM Receiver." - ::= {pgmReceiverTsi 2} - -pgmReceiverEntry OBJECT-TYPE - SYNTAX PgmReceiverEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per PGM receiver fault management - and general information." - INDEX { pgmReceiverGlobalId, - pgmReceiverSourcePort, - pgmReceiverInstance } - ::= { pgmReceiverTable 1 } - -PgmReceiverEntry ::= SEQUENCE { - pgmReceiverGlobalId - OCTET STRING, - pgmReceiverSourcePort - Unsigned32, - pgmReceiverInstance - Unsigned32, - pgmReceiverGroupAddress - IpAddress, - pgmReceiverDestPort - Unsigned32, - pgmReceiverSourceAddress - IpAddress, - pgmReceiverLastHop - IpAddress, - pgmReceiverSourceGsi - OCTET STRING, - pgmReceiverSourcePortNumber - Unsigned32, - pgmReceiverUniqueInstance - Unsigned32 - } - -pgmReceiverGlobalId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Globally unique source identifier (GSI)." - ::= { pgmReceiverEntry 1 } - -pgmReceiverSourcePort OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmReceiverEntry 2 } - -pgmReceiverInstance OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Positive number, uniquely identifying - a Receiver." - ::= { pgmReceiverEntry 3 } - -pgmReceiverGroupAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "IP Multicast group address used by the sender." - ::= { pgmReceiverEntry 4 } - -pgmReceiverDestPort OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Destination port number." - ::= { pgmReceiverEntry 5 } - -pgmReceiverSourceAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Source IP address number." - ::= { pgmReceiverEntry 6 } - -pgmReceiverLastHop OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Last hop PGM router address." - ::= { pgmReceiverEntry 7 } - -pgmReceiverSourceGsi OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Globally unique source identifier (GSI)." - ::= { pgmReceiverEntry 8 } - -pgmReceiverSourcePortNumber OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmReceiverEntry 9 } - -pgmReceiverUniqueInstance OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Positive number, uniquely identifying - a Receiver." - ::= { pgmReceiverEntry 10 } - --- PGM Receiver Configuration Management Table - -pgmReceiverConfigTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmReceiverConfigEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per TSI configuration - management information related - to the PGM Receiver." - ::= {pgmReceiverTsi 3 } - -pgmReceiverConfigEntry OBJECT-TYPE - SYNTAX PgmReceiverConfigEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per PGM receiver configuration management - information." - INDEX { pgmReceiverConfigGlobalId, - pgmReceiverConfigSourcePort, - pgmReceiverConfigInstance } - ::= { pgmReceiverConfigTable 1 } - -PgmReceiverConfigEntry ::= SEQUENCE { - pgmReceiverConfigGlobalId - OCTET STRING, - pgmReceiverConfigSourcePort - Unsigned32, - pgmReceiverConfigInstance - Unsigned32, - pgmReceiverNakBackoffIvl - Unsigned32, - pgmReceiverNakRepeatIvl - Unsigned32, - pgmReceiverNakNcfRetries - Unsigned32, - pgmReceiverNakRdataIvl - Unsigned32, - pgmReceiverNakDataRetries - Unsigned32, - pgmReceiverSendNaks - INTEGER, - pgmReceiverLateJoin - INTEGER, - pgmReceiverNakTtl - Unsigned32, - pgmReceiverDeliveryOrder - INTEGER, - pgmReceiverMcastNaks - INTEGER, - pgmReceiverNakFailureThresholdTimer - Unsigned32, - pgmReceiverNakFailureThreshold - Unsigned32 - } - -pgmReceiverConfigGlobalId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Globally unique source identifier (GSI)." - ::= { pgmReceiverConfigEntry 1 } - -pgmReceiverConfigSourcePort OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmReceiverConfigEntry 2 } - -pgmReceiverConfigInstance OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Positive number, uniquely identifying - a Receiver." - ::= { pgmReceiverConfigEntry 3 } - -pgmReceiverNakBackoffIvl OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "NAK random backoff interval." - ::= { pgmReceiverConfigEntry 4 } - -pgmReceiverNakRepeatIvl OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "NAK repeat interval." - ::= { pgmReceiverConfigEntry 5 } - -pgmReceiverNakNcfRetries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Max NAK retries while witing for matching NCF." - ::= { pgmReceiverConfigEntry 6 } - -pgmReceiverNakRdataIvl OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "NAK RDATA interval." - ::= { pgmReceiverConfigEntry 7 } - -pgmReceiverNakDataRetries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Max NAK retries while waiting for missing data." - ::= { pgmReceiverConfigEntry 8 } - -pgmReceiverSendNaks OBJECT-TYPE - SYNTAX INTEGER { - enabled(1), - disabled(2) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Flag to indicate whether or not receiver should - send NAKs or be totally passive." - ::= { pgmReceiverConfigEntry 9 } - -pgmReceiverLateJoin OBJECT-TYPE - SYNTAX INTEGER { - enabled(1), - disabled(2) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Flag to indicate whether or not the receiver - should wait for a OPT_JOIN SPM before - attempting to late join." - ::= { pgmReceiverConfigEntry 10 } - -pgmReceiverNakTtl OBJECT-TYPE - SYNTAX Unsigned32(1..255) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "TTL on NAK packets sent for loss." - ::= { pgmReceiverConfigEntry 11 } - -pgmReceiverDeliveryOrder OBJECT-TYPE - SYNTAX INTEGER { - unordered(1), - ordered(2) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Packet Delivery Order for the receiving - application." - ::= { pgmReceiverConfigEntry 12 } - -pgmReceiverMcastNaks OBJECT-TYPE - SYNTAX INTEGER { - enabled(1), - disabled(2) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Flag to indicate whether or not receiver should - send multicast NAKs." - ::= { pgmReceiverConfigEntry 13 } - -pgmReceiverNakFailureThresholdTimer OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "seconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Timer that defines per receiver - interval of time during which unrecoverable - lost packets are monitored - for purposes of SNMP trap generation." - ::= { pgmReceiverConfigEntry 14 } - -pgmReceiverNakFailureThreshold OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The number of unrecoverable lost packets - within the defined interval - after which an SNMP trap is generated." - ::= { pgmReceiverConfigEntry 15 } - - --- PGM Receiver Performance Management Table - -pgmReceiverPerformanceTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmReceiverPerformanceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per TSI - performance management information - related to the PGM Receiver." - ::= {pgmReceiverTsi 4} - -pgmReceiverPerformanceEntry OBJECT-TYPE - SYNTAX PgmReceiverPerformanceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per PGM Receiver session performance - management information." - INDEX { pgmReceiverPerformanceGlobalId, - pgmReceiverPerformanceSourcePort, - pgmReceiverPerformanceInstance } - ::= { pgmReceiverPerformanceTable 1 } - -PgmReceiverPerformanceEntry ::= SEQUENCE { - pgmReceiverPerformanceGlobalId - OCTET STRING, - pgmReceiverPerformanceSourcePort - Unsigned32, - pgmReceiverPerformanceInstance - Unsigned32, - pgmReceiverDataBytesReceived - Counter32, - pgmReceiverDataMsgsReceived - Counter32, - pgmReceiverNaksSent - Counter32, - pgmReceiverNaksRetransmitted - Counter32, - pgmReceiverNakFailures - Counter32, - pgmReceiverBytesReceived - Counter32, - pgmReceiverNaksSuppressed - Counter32, - pgmReceiverCksumErrors - Counter32, - pgmReceiverMalformedSpms - Counter32, - pgmReceiverMalformedOdata - Counter32, - pgmReceiverMalformedRdata - Counter32, - pgmReceiverMalformedNcfs - Counter32, - pgmReceiverPacketsDiscarded - Counter32, - pgmReceiverLosses - Counter32, - pgmReceiverBytesDeliveredToApp - Counter32, - pgmReceiverMsgsDeliveredToApp - Counter32, - pgmReceiverDupSpms - Counter32, - pgmReceiverDupDatas - Counter32, - pgmReceiverDupParities - Counter32, - pgmReceiverNakPacketsSent - Counter32, - pgmReceiverParityNakPacketsSent - Counter32, - pgmReceiverSelectiveNakPacketsSent - Counter32, - pgmReceiverParityNaksSent - Counter32, - pgmReceiverSelectiveNaksSent - Counter32, - pgmReceiverParityNaksRetransmitted - Counter32, - pgmReceiverSelectiveNaksRetransmitted - Counter32, - pgmReceiverNaksFailed - Counter32, - pgmReceiverParityNaksFailed - Counter32, - pgmReceiverSelectiveNaksFailed - Counter32, - pgmReceiverNaksFailedRxwAdvanced - Counter32, - pgmReceiverNaksFaledNcfRetriesExceeded - Counter32, - pgmReceiverNaksFailedDataRetriesExceeded - Counter32, - pgmReceiverNaksFailedGenExpired - Counter32, - pgmReceiverNakFailuresDelivered - Counter32, - pgmReceiverParityNaksSuppressed - Counter32, - pgmReceiverSelectiveNaksSuppressed - Counter32, - pgmReceiverNakErrors - Counter32, - pgmReceiverOutstandingParityNaks - Counter32, - pgmReceiverOutstandingSelectiveNaks - Counter32, - pgmReceiverLastActivity - Counter32, - pgmReceiverNakSvcTimeMin - Counter32, - pgmReceiverNakSvcTimeMean - Counter32, - pgmReceiverNakSvcTimeMax - Counter32, - pgmReceiverNakFailTimeMin - Counter32, - pgmReceiverNakFailTimeMean - Counter32, - pgmReceiverNakFailTimeMax - Counter32, - pgmReceiverNakTransmitMin - Counter32, - pgmReceiverNakTransmitMean - Counter32, - pgmReceiverNakTransmitMax - Counter32, - pgmReceiverAcksSent - Counter32, - pgmReceiverRxwTrail - Counter32, - pgmReceiverRxwLead - Counter32, - pgmReceiverNakFailuresLastInterval - Counter32, - pgmReceiverLastIntervalNakFailures - Counter32 -} - -pgmReceiverPerformanceGlobalId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Globally unique source identifier (GSI)." - ::= { pgmReceiverPerformanceEntry 1 } - -pgmReceiverPerformanceSourcePort OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmReceiverPerformanceEntry 2 } - -pgmReceiverPerformanceInstance OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Positive number, uniquely identifying - a Receiver." - ::= { pgmReceiverPerformanceEntry 3 } - -pgmReceiverDataBytesReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of data bytes received for this PGM - Receiver session." - ::= { pgmReceiverPerformanceEntry 4 } - -pgmReceiverDataMsgsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of data messages received for this - PGM Receiver session." - ::= { pgmReceiverPerformanceEntry 5 } - -pgmReceiverNaksSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAKs sent for this session." - ::= { pgmReceiverPerformanceEntry 6 } - -pgmReceiverNaksRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAKs retransmitted for this - session." - ::= { pgmReceiverPerformanceEntry 7 } - -pgmReceiverNakFailures OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAK failures for this session. - This counter represents the number of - unrecoverable/unrepairable data packets." - ::= { pgmReceiverPerformanceEntry 8 } - -pgmReceiverBytesReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes received for this session. - It counts all bytes received, including IP - and PGM header and non-data messages." - ::= { pgmReceiverPerformanceEntry 9 } - -pgmReceiverNaksSuppressed OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of suppressed NAKs." - ::= { pgmReceiverPerformanceEntry 10 } - -pgmReceiverCksumErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of checksum errors for this session." - ::= { pgmReceiverPerformanceEntry 11 } - -pgmReceiverMalformedSpms OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of malformed SPMs for this session." - ::= { pgmReceiverPerformanceEntry 12 } - -pgmReceiverMalformedOdata OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of malformed ODATA packets for this - session." - ::= { pgmReceiverPerformanceEntry 13 } - -pgmReceiverMalformedRdata OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of malformed RDATA packets for this - session." - ::= { pgmReceiverPerformanceEntry 14 } - -pgmReceiverMalformedNcfs OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of malformed NCF packets for this - session." - ::= { pgmReceiverPerformanceEntry 15 } - -pgmReceiverPacketsDiscarded OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of discarded packets for this - session." - ::= { pgmReceiverPerformanceEntry 16 } - -pgmReceiverLosses OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of detected missed packets for - this session. This counter is incremented - every time a Receiver detects a missing - packet." - ::= { pgmReceiverPerformanceEntry 17 } - -pgmReceiverBytesDeliveredToApp OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes, delivered to the - application." - ::= { pgmReceiverPerformanceEntry 18 } - -pgmReceiverMsgsDeliveredToApp OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of messages, delivered to the - application." - ::= { pgmReceiverPerformanceEntry 19 } - -pgmReceiverDupSpms OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of duplicate SPMs." - ::= { pgmReceiverPerformanceEntry 20 } - -pgmReceiverDupDatas OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of duplicate RDATA/ODATA." - ::= { pgmReceiverPerformanceEntry 21 } - -pgmReceiverDupParities OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of duplicate parities seen." - ::= { pgmReceiverPerformanceEntry 22 } - -pgmReceiverNakPacketsSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAK packets sent. - Includes parity and selective." - ::= { pgmReceiverPerformanceEntry 23 } - -pgmReceiverParityNakPacketsSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of parity NAK packets sent." - ::= { pgmReceiverPerformanceEntry 24 } - -pgmReceiverSelectiveNakPacketsSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of selective NAK packets sent." - ::= { pgmReceiverPerformanceEntry 25 } - -pgmReceiverParityNaksSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual parity NAK packets sent." - ::= { pgmReceiverPerformanceEntry 26 } - -pgmReceiverSelectiveNaksSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual selective NAK packets sent." - ::= { pgmReceiverPerformanceEntry 27 } - -pgmReceiverParityNaksRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual parity NAKs retransmitted." - ::= { pgmReceiverPerformanceEntry 28 } - -pgmReceiverSelectiveNaksRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual selective NAKs retransmitted." - ::= { pgmReceiverPerformanceEntry 29 } - -pgmReceiverNaksFailed OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual NAKs that failed." - ::= { pgmReceiverPerformanceEntry 30 } - -pgmReceiverParityNaksFailed OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual parity NAKs that failed." - ::= { pgmReceiverPerformanceEntry 31 } - -pgmReceiverSelectiveNaksFailed OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual selective NAKs that failed." - ::= { pgmReceiverPerformanceEntry 32 } - -pgmReceiverNaksFailedRxwAdvanced OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual NAKs that failed, due to the - window being advanced over them." - ::= { pgmReceiverPerformanceEntry 33 } - -pgmReceiverNaksFaledNcfRetriesExceeded OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual NAKs that failed, due to ncf - retry limit exceeded." - ::= { pgmReceiverPerformanceEntry 34 } - -pgmReceiverNaksFailedDataRetriesExceeded OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual NAKs that failed, due to data - retry limit exceeded." - ::= { pgmReceiverPerformanceEntry 35 } - -pgmReceiverNaksFailedGenExpired OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual NAKs that failed, due to NAK - generation interval expiring before it - could be repaired." - ::= { pgmReceiverPerformanceEntry 36 } - -pgmReceiverNakFailuresDelivered OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAK failures delivered to application." - ::= { pgmReceiverPerformanceEntry 37 } - -pgmReceiverParityNaksSuppressed OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual parity NAKs that were - suppressed from being sent due to reception - of an NCF or ODATA/RDATA for the loss." - ::= { pgmReceiverPerformanceEntry 38 } - -pgmReceiverSelectiveNaksSuppressed OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual selective NAKs that were - suppressed from being sent due to reception - of an NCF or ODATA/RDATA for the loss." - ::= { pgmReceiverPerformanceEntry 39 } - -pgmReceiverNakErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAK packets, that contained - errors in them." - ::= { pgmReceiverPerformanceEntry 40 } - -pgmReceiverOutstandingParityNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Current number of outstanding individual parity - NAKs that are waiting to be repaired." - ::= { pgmReceiverPerformanceEntry 41 } - -pgmReceiverOutstandingSelectiveNaks OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Current number of outstanding individual selective - NAKs that are waiting to be repaired." - ::= { pgmReceiverPerformanceEntry 42 } - -pgmReceiverLastActivity OBJECT-TYPE - SYNTAX Counter32 - UNITS "seconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Last time activity was observed from - the Source. In seconds since the epoch, - January 1, 1970." - ::= { pgmReceiverPerformanceEntry 43 } - -pgmReceiverNakSvcTimeMin OBJECT-TYPE - SYNTAX Counter32 - UNITS "miliseconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The min time that it took for a loss - to be repaired." - ::= { pgmReceiverPerformanceEntry 44 } - -pgmReceiverNakSvcTimeMean OBJECT-TYPE - SYNTAX Counter32 - UNITS "miliseconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The mean time that it took for all losses - to be repaired." - ::= { pgmReceiverPerformanceEntry 45 } - -pgmReceiverNakSvcTimeMax OBJECT-TYPE - SYNTAX Counter32 - UNITS "miliseconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The max time that it took for a loss - to be repaired." - ::= { pgmReceiverPerformanceEntry 46 } - -pgmReceiverNakFailTimeMin OBJECT-TYPE - SYNTAX Counter32 - UNITS "miliseconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The min time it took for a loss - to be considered unrecoverable." - ::= { pgmReceiverPerformanceEntry 47 } - -pgmReceiverNakFailTimeMean OBJECT-TYPE - SYNTAX Counter32 - UNITS "miliseconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The mean time it took for all losses - to be considered unrecoverable." - ::= { pgmReceiverPerformanceEntry 48 } - -pgmReceiverNakFailTimeMax OBJECT-TYPE - SYNTAX Counter32 - UNITS "miliseconds" - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The max time it took for a loss - to be considered unrecoverable." - ::= { pgmReceiverPerformanceEntry 49 } - -pgmReceiverNakTransmitMin OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The min number of times an individual NAK - needed to be retransmitted before it was repaired." - ::= { pgmReceiverPerformanceEntry 50 } - -pgmReceiverNakTransmitMean OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The mean number of times an individual NAK - needed to be retransmitted before it was repaired." - ::= { pgmReceiverPerformanceEntry 51 } - -pgmReceiverNakTransmitMax OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The max number of times an individual NAK - needed to be retransmitted before it was repaired." - ::= { pgmReceiverPerformanceEntry 52 } - -pgmReceiverAcksSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The number of ACKs sent from the congestion - control operation." - ::= { pgmReceiverPerformanceEntry 53 } - -pgmReceiverRxwTrail OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Sequence number of the trailing edge of - the transmission window as is being advertised - by the sender." - ::= { pgmReceiverPerformanceEntry 54 } - -pgmReceiverRxwLead OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Sequence number of the leading edge of - the transmission window as is being advertised - by the sender." - ::= { pgmReceiverPerformanceEntry 55 } - -pgmReceiverNakFailuresLastInterval OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The actual number of seconds since the - last pgmReceiverLastIntervalNakFailures - counter reset due to number of nak failures - threshold exceeded." - ::= { pgmReceiverPerformanceEntry 56 } - -pgmReceiverLastIntervalNakFailures OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of actual unrecoverable failures for - the requested threshold interval for this session." - ::= { pgmReceiverPerformanceEntry 57 } - --- --- Designated Local Repairer (DLR) --- - --- Designated Local Repairer (DLR) Default Configuration - -pgmDlrSaveDefaults OBJECT-TYPE - SYNTAX INTEGER { initial (1), - save (2), - pending (3), - success (4), - failure (5) } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Flag used to initiate the storing - of all default variable values to - non-volatile storage and to report the - result of the operation. - The following values can only be read, - never written : - initial(1) - returned prior to any requests - for saving the default configuration - pending(3) - saving in progress - success(4) - returned when a save(2) request - is successful - failure(5) - returned when a save(2) request - is unsuccessful - - The following values can only be written, - never read : - save(2) - to indicate that the default - configuration should be saved." - ::= { pgmDLR 1 } - -pgmDlrLastUpdateTime OBJECT-TYPE - SYNTAX TimeTicks - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of TimeTicks since the last update - of the non-volatile storage." - ::= { pgmDLR 2 } - -pgmDlrGroupAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Multicast group address to listen for traffic - on." - ::= { pgmDLR 3 } - -pgmDlrCacheRtx OBJECT-TYPE - SYNTAX INTEGER - { - cacheOFF(1), - cacheON(2) - } - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Specifies if the NE should also cache data for - retransmission or simply suppress duplicate - NAKs and forward the NAKs to it's parent NE or - sender." - ::= { pgmDLR 4 } - -pgmDlrActivityIvl OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Specifies the delay between activity checks - for specific PGM sessions." - ::= { pgmDLR 5 } - -pgmDlrMaxRate OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Specifies the maximum rate (in bps) for - retransmissions." - ::= { pgmDLR 6 } - -pgmDlrParentNeAddr OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "Ip Address of the NE to send all NAKs to." - ::= { pgmDLR 7 } - -pgmDlrUpdateSinceLastSave OBJECT-TYPE - SYNTAX INTEGER - { - notUpdated(1), - updated(2) - } - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Specifies if any of the Dlr Default - variables have been updated or not, - since the last successful pgmDlrSaveDefaults. - notUpdated - none of the default Dlr - variables were set after the last - successful save to a non-volatile - storage. - updated - at least one of the default Dlr - variables were set after the last - successful save to a non-volatile - storage." - ::= { pgmDLR 8 } - - --- --- PGM DLR Source/Re-transmitter Sessions --- -pgmDlrSource OBJECT IDENTIFIER ::= { pgmDLR 100 } - -pgmDlrSourceNumberOfEntries OBJECT-TYPE - SYNTAX Unsigned32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "The total number of PGM Source sessions for - the PGM DLR." - ::= { pgmDlrSource 1 } - --- PGM Dlr Source Fault Management Table - -pgmDlrSourceTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmDlrSourceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per TSI fault - management and general information - related to the PGM DLR Source sessions." - ::= {pgmDlrSource 2} - -pgmDlrSourceEntry OBJECT-TYPE - SYNTAX PgmDlrSourceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per PGM DLR Source sessions fault - management information." - INDEX { pgmDlrSourceGlobalId, - pgmDlrSourceSourcePort } - ::= { pgmDlrSourceTable 1 } - -PgmDlrSourceEntry ::= SEQUENCE { - pgmDlrSourceGlobalId - OCTET STRING, - pgmDlrSourceSourcePort - Unsigned32, - pgmDlrSourceGroupAddress - IpAddress, - pgmDlrSourceSourceGsi - OCTET STRING, - pgmDlrSourceSourcePortNumber - Unsigned32 - } - -pgmDlrSourceGlobalId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Globally unique source identifier (GSI)." - ::= { pgmDlrSourceEntry 1 } - -pgmDlrSourceSourcePort OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmDlrSourceEntry 2 } - -pgmDlrSourceGroupAddress OBJECT-TYPE - SYNTAX IpAddress - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Multicast group interface address - to send multicast packets on." - ::= { pgmDlrSourceEntry 3 } - -pgmDlrSourceSourceGsi OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Globally unique source identifier (GSI)." - ::= { pgmDlrSourceEntry 4 } - -pgmDlrSourceSourcePortNumber OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmDlrSourceEntry 5 } - --- PGM DLR Source Configuration Management Table - -pgmDlrSourceConfigTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmDlrSourceConfigEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per TSI configuration - management information related to the - PGM DLR Source sessions." - ::= {pgmDlrSource 3} - -pgmDlrSourceConfigEntry OBJECT-TYPE - SYNTAX PgmDlrSourceConfigEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per PGM DLR Source sessions configuration - management information." - INDEX { pgmDlrSourceConfigGlobalId, - pgmDlrSourceConfigSourcePort } - ::= { pgmDlrSourceConfigTable 1 } - -PgmDlrSourceConfigEntry ::= SEQUENCE { - pgmDlrSourceConfigGlobalId - OCTET STRING, - pgmDlrSourceConfigSourcePort - Unsigned32, - pgmDlrSourceGroupTtl - Unsigned32, - pgmDlrSourceRdataBackoffIvl - Unsigned32 - } - -pgmDlrSourceConfigGlobalId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Globally unique source identifier (GSI)." - ::= { pgmDlrSourceConfigEntry 1 } - -pgmDlrSourceConfigSourcePort OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmDlrSourceConfigEntry 2 } - -pgmDlrSourceGroupTtl OBJECT-TYPE - SYNTAX Unsigned32(1..255) - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "This option sets the default TTL to use for - multicast packets. " - ::= { pgmDlrSourceConfigEntry 3 } - -pgmDlrSourceRdataBackoffIvl OBJECT-TYPE - SYNTAX Unsigned32 - UNITS "milliseconds" - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "This option sets the default RDATA backoff - interval. The value is expressed in milliseconds. - The value of 0 indicates no backoff." - ::= { pgmDlrSourceConfigEntry 4 } - - --- PGM DLR Source Performance Management Table - -pgmDlrSourcePerformanceTable OBJECT-TYPE - SYNTAX SEQUENCE OF PgmDlrSourcePerformanceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "The table holding per TSI performance - management information related to the - PGM DLR Source sessions." - ::= {pgmDlrSource 4} - -pgmDlrSourcePerformanceEntry OBJECT-TYPE - SYNTAX PgmDlrSourcePerformanceEntry - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Per PGM DLR Source performance management - information." - INDEX { pgmDlrSourcePerformanceGlobalId, - pgmDlrSourcePerformanceSourcePort } - ::= { pgmDlrSourcePerformanceTable 1 } - -PgmDlrSourcePerformanceEntry ::= SEQUENCE { - pgmDlrSourcePerformanceGlobalId - OCTET STRING, - pgmDlrSourcePerformanceSourcePort - Unsigned32, - pgmDlrSourceRdataMsgsSent - Counter32, - pgmDlrSourceRdataBytesSent - Counter32, - pgmDlrSourceBytesSent - Counter32, - pgmDlrSourceNaksRcvd - Counter32, - pgmDlrSourceNaksIgnored - Counter32, - pgmDlrSourceNakErrors - Counter32, - pgmDlrSourceDiscards - Counter32, - pgmDlrSourceCksumErrors - Counter32, - pgmDlrSourceNNaksSent - Counter32, - pgmDlrSourceBytesBuffered - Counter32, - pgmDlrSourceMsgsBuffered - Counter32, - pgmDlrSourceParityBytesRetransmitted - Counter32, - pgmDlrSourceSelectiveBytesRetransmited - Counter32, - pgmDlrSourceParityMsgsRetransmitted - Counter32, - pgmDlrSourceSelectiveMsgsRetransmitted - Counter32, - pgmDlrSourceBytesAdmit - Counter32, - pgmDlrSourceMsgsAdmit - Counter32, - pgmDlrSourceNakPacketsReceived - Counter32, - pgmDlrSourceParityNakPacketsReceived - Counter32, - pgmDlrSourceSelectiveNakPacketsReceived - Counter32, - pgmDlrSourceParityNaksReceived - Counter32, - pgmDlrSourceSelectiveNaksReceived - Counter32, - pgmDlrSourceParityNaksIgnored - Counter32, - pgmDlrSourceSelectiveNaksIgnored - Counter32, - pgmDlrSourceAckErrors - Counter32, - pgmDlrSourceNNakErrors - Counter32, - pgmDlrSourceAckPacketsReceived - Counter32, - pgmDlrSourceNNakPacketsReceived - Counter32, - pgmDlrSourceParityNNakPacketsReceived - Counter32, - pgmDlrSourceSelectiveNNakPacketsReceived - Counter32, - pgmDlrSourceNNaksReceived - Counter32, - pgmDlrSourceParityNNaksReceived - Counter32, - pgmDlrSourceSelectiveNNaksReceived - Counter32 - } - -pgmDlrSourcePerformanceGlobalId OBJECT-TYPE - SYNTAX OCTET STRING (SIZE (12)) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Globally unique source identifier (GSI)." - ::= { pgmDlrSourcePerformanceEntry 1 } - -pgmDlrSourcePerformanceSourcePort OBJECT-TYPE - SYNTAX Unsigned32(0..65535) - MAX-ACCESS not-accessible - STATUS current - DESCRIPTION - "Source port number." - ::= { pgmDlrSourcePerformanceEntry 2 } - -pgmDlrSourceRdataMsgsSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of Repair Data (RDATA) packets sent for - this PGM DLR." - ::= { pgmDlrSourcePerformanceEntry 3 } - -pgmDlrSourceRdataBytesSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of RDATA bytes sent." - ::= { pgmDlrSourcePerformanceEntry 4 } - -pgmDlrSourceBytesSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes sent. This includes IP and - PGM header and non-data msgs." - ::= { pgmDlrSourcePerformanceEntry 5 } - -pgmDlrSourceNaksRcvd OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAKs received on this TSI." - ::= { pgmDlrSourcePerformanceEntry 6 } - -pgmDlrSourceNaksIgnored OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAKs ignored on this TSI, due to - duplicates." - ::= { pgmDlrSourcePerformanceEntry 7 } - -pgmDlrSourceNakErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of malformed NAKs on this TSI." - ::= { pgmDlrSourcePerformanceEntry 8 } - -pgmDlrSourceDiscards OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of discarded packets on this TSI. - This counter is used to count all discarded - incoming packets per TSI in cases of - duplicates, header and packet errors, etc." - ::= { pgmDlrSourcePerformanceEntry 9 } - -pgmDlrSourceCksumErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of checksum errors on this TSI." - ::= { pgmDlrSourcePerformanceEntry 10 } - -pgmDlrSourceNNaksSent OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of Null NAKs (in number of packets) - sent by this PGM DLR session." - ::= { pgmDlrSourcePerformanceEntry 11 } - -pgmDlrSourceBytesBuffered OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes currently buffered for this - TSI." - ::= { pgmDlrSourcePerformanceEntry 12 } - -pgmDlrSourceMsgsBuffered OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of messages currently buffered for - this TSI." - ::= { pgmDlrSourcePerformanceEntry 13 } - -pgmDlrSourceParityBytesRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes sent in parity retransmissions." - ::= { pgmDlrSourcePerformanceEntry 14 } - -pgmDlrSourceSelectiveBytesRetransmited OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes sent in selective retransmissions." - ::= { pgmDlrSourcePerformanceEntry 15 } - -pgmDlrSourceParityMsgsRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of parity retransmissions sent." - ::= { pgmDlrSourcePerformanceEntry 16 } - -pgmDlrSourceSelectiveMsgsRetransmitted OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of selective retransmissions sent." - ::= { pgmDlrSourcePerformanceEntry 17 } - -pgmDlrSourceBytesAdmit OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of bytes currently in the rate controled - admit queue. Includes IP header, UDP header if - encapsulated, PGM header, and data." - ::= { pgmDlrSourcePerformanceEntry 18 } - -pgmDlrSourceMsgsAdmit OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of messages currently in the rate controled - admit queue. Includes data messages, retransmissions, - and SPMs." - ::= { pgmDlrSourcePerformanceEntry 19 } - -pgmDlrSourceNakPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of NAK packets received." - ::= { pgmDlrSourcePerformanceEntry 20 } - -pgmDlrSourceParityNakPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of parity NAK packets received." - ::= { pgmDlrSourcePerformanceEntry 21 } - -pgmDlrSourceSelectiveNakPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of selective NAK packets received." - ::= { pgmDlrSourcePerformanceEntry 22 } - -pgmDlrSourceParityNaksReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual parity NAKs received." - ::= { pgmDlrSourcePerformanceEntry 23 } - -pgmDlrSourceSelectiveNaksReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual selective NAKs received." - ::= { pgmDlrSourcePerformanceEntry 24 } - -pgmDlrSourceParityNaksIgnored OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual parity NAKs ignored." - ::= { pgmDlrSourcePerformanceEntry 25 } - -pgmDlrSourceSelectiveNaksIgnored OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual selective NAKs ignored." - ::= { pgmDlrSourcePerformanceEntry 26 } - -pgmDlrSourceAckErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of ACK packets received with error in - them, different than checksum error." - ::= { pgmDlrSourcePerformanceEntry 27 } - -pgmDlrSourceNNakErrors OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of Null NAK packets received that contain - error, rSifferent than checksum error." - ::= { pgmDlrSourcePerformanceEntry 28 } - -pgmDlrSourceAckPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of ACK packets received." - ::= { pgmDlrSourcePerformanceEntry 29 } - -pgmDlrSourceNNakPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of Null NAKs received." - ::= { pgmDlrSourcePerformanceEntry 30 } - -pgmDlrSourceParityNNakPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of parity Null NAK packets received." - ::= { pgmDlrSourcePerformanceEntry 31 } - -pgmDlrSourceSelectiveNNakPacketsReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of selective Null NAK packets received." - ::= { pgmDlrSourcePerformanceEntry 32 } - -pgmDlrSourceNNaksReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual NAKs, received in Null - NAK packets." - ::= { pgmDlrSourcePerformanceEntry 33 } - -pgmDlrSourceParityNNaksReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual parity NAKs, - received in Null NAK packets." - ::= { pgmDlrSourcePerformanceEntry 34 } - -pgmDlrSourceSelectiveNNaksReceived OBJECT-TYPE - SYNTAX Counter32 - MAX-ACCESS read-only - STATUS current - DESCRIPTION - "Number of individual NAKs, - received in Null NAK packets." - ::= { pgmDlrSourcePerformanceEntry 35 } - --- Notifications - -pgmNotifications OBJECT IDENTIFIER ::= - { pgmNotificationPrefix 0 } - -pgmStart NOTIFICATION-TYPE - STATUS current - DESCRIPTION - "This trap is sent when the pgm snmp agent starts" - ::= { pgmNotifications 1 } - -pgmStop NOTIFICATION-TYPE - STATUS current - DESCRIPTION - "This trap is sent when the pgm snmp agent terminates" - ::= { pgmNotifications 2 } - --- PGM Source Specific Traps - -pgmNewSourceTrap NOTIFICATION-TYPE - OBJECTS { - pgmSourceSourceGsi, - pgmSourceSourcePortNumber - } - STATUS current - DESCRIPTION - "New Source Session created." - ::= { pgmNotifications 3 } - -pgmClosedSourceTrap NOTIFICATION-TYPE - OBJECTS { - pgmSourceSourceGsi, - pgmSourceSourcePortNumber - } - STATUS current - DESCRIPTION - "Source Session closed." - ::= { pgmNotifications 4 } - --- PGM Receiver Specific Traps - -pgmNewReceiverTrap NOTIFICATION-TYPE - OBJECTS { - pgmReceiverSourceGsi, - pgmReceiverSourcePortNumber, - pgmReceiverUniqueInstance - } - STATUS current - DESCRIPTION - "New Receiver Session created. - This trap is optional." - ::= { pgmNotifications 5 } - -pgmClosedReceiverTrap NOTIFICATION-TYPE - OBJECTS { - pgmReceiverSourceGsi, - pgmReceiverSourcePortNumber, - pgmReceiverUniqueInstance - } - STATUS current - DESCRIPTION - "Receiver Session closed. - This trap is optional." - ::= { pgmNotifications 6 } - -pgmNakFailuresTrap NOTIFICATION-TYPE - OBJECTS { - pgmReceiverSourceGsi, - pgmReceiverSourcePortNumber, - pgmReceiverUniqueInstance, - pgmReceiverNakFailureThresholdTimer, - pgmReceiverNakFailureThreshold, - pgmReceiverNakFailuresLastInterval, - pgmReceiverLastIntervalNakFailures - } - STATUS current - DESCRIPTION - "The number of unrecovered lost packets - exceeded the threshold limit for the - corresponding threshold interval." - ::= { pgmNotifications 7 } - --- PGM Dlr Source Specific Traps - -pgmNewDlrSourceTrap NOTIFICATION-TYPE - OBJECTS { - pgmDlrSourceSourceGsi, - pgmDlrSourceSourcePortNumber - } - STATUS current - DESCRIPTION - "New Dlr Source Session created." - ::= { pgmNotifications 8 } - -pgmClosedDlrSourceTrap NOTIFICATION-TYPE - OBJECTS { - pgmDlrSourceSourceGsi, - pgmDlrSourceSourcePortNumber - } - STATUS current - DESCRIPTION - "Dlr Source Session closed." - ::= { pgmNotifications 9 } - --- Conformance information - -pgmMIBConformance OBJECT IDENTIFIER ::= { pgmMIB 3 } -pgmMIBCompliances OBJECT IDENTIFIER ::= { pgmMIBConformance 1 } -pgmMIBGroups OBJECT IDENTIFIER ::= { pgmMIBConformance 2 } - --- Compliance statements - -pgmNetworkElementMIBCompliance MODULE-COMPLIANCE - STATUS current - DESCRIPTION - "The compliance statement for devices running as PGM - Network Elements." - MODULE -- this module - MANDATORY-GROUPS { pgmNetworkElementMIBGroup } - - ::= { pgmMIBCompliances 1 } - -pgmSourceMIBCompliance MODULE-COMPLIANCE - STATUS current - DESCRIPTION - "The compliance statement for devices running as PGM - sources." - MODULE -- this module - MANDATORY-GROUPS { pgmSourceMIBGroup } - - ::= { pgmMIBCompliances 2 } - -pgmReceiverMIBCompliance MODULE-COMPLIANCE - STATUS current - DESCRIPTION - "The compliance statement for devices running as PGM - receivers." - MODULE -- this module - MANDATORY-GROUPS { pgmReceiverMIBGroup } - - ::= { pgmMIBCompliances 3 } - -pgmDLRMIBCompliance MODULE-COMPLIANCE - STATUS current - DESCRIPTION - "The compliance statement for devices running as PGM - designated local repairers (DLR)." - MODULE -- this module - MANDATORY-GROUPS { pgmDLRMIBGroup, - pgmReceiverMIBGroup } - - ::= { pgmMIBCompliances 4 } - -pgmTrapsMIBCompliance MODULE-COMPLIANCE - STATUS current - DESCRIPTION - "The compliance statement for PGM traps." - MODULE -- this module - MANDATORY-GROUPS { pgmTrapsMIBGroup, - pgmTrapsSourceMIBGroup, - pgmTrapsReceiverMIBGroup, - pgmTrapsDlrSourceMIBGroup } - ::= { pgmMIBCompliances 5 } - --- Units of conformance - -pgmNetworkElementMIBGroup OBJECT-GROUP - OBJECTS { pgmNeEnable, - pgmNeSessionLifeTime, - pgmNeMaxReXmitStates, - pgmNeMaxSessions, - pgmNeTotalInterfacesNumberOfEntries, - pgmNeIfPgmEnable, - pgmNeIfNakRptInterval, - pgmNeIfNakRptRate, - pgmNeIfNakRdataInterval, - pgmNeIfNakEliminateInterval, - pgmNeIfReXmitStates, - pgmNeIfReXmitTimedOut, - pgmNeIfInSpms, - pgmNeIfOutSpms, - pgmNeIfInParitySpms, - pgmNeIfOutParitySpms, - pgmNeIfInRdata, - pgmNeIfOutRdata, - pgmNeIfInParityRdata, - pgmNeIfOutParityRdata, - pgmNeIfInRdataNoSessionErrors, - pgmNeIfUniqueNaks, - pgmNeIfInNaks, - pgmNeIfOutNaks, - pgmNeIfUniqueParityNaks, - pgmNeIfInParityNaks, - pgmNeIfOutParityNaks, - pgmNeIfInNakNoSessionErrors, - pgmNeIfInNakSeqErrors, - pgmNeIfInParityNakTgErrors, - pgmNeIfInNnaks, - pgmNeIfOutNnaks, - pgmNeIfInParityNnaks, - pgmNeIfOutParityNnaks, - pgmNeIfInNnakNoSessionErrors, - pgmNeIfInNcfs, - pgmNeIfOutNcfs, - pgmNeIfInParityNcfs, - pgmNeIfOutParityNcfs, - pgmNeIfInNcfNoSessionErrors, - pgmNeIfInRedirectNcfs, - pgmNeIfMalformed, - pgmNeIfSpmFromSource, - pgmNeIfSpmBadSqn, - pgmNeIfSpmError, - pgmNeIfPollRandomIgnore, - pgmNeIfPollTsiStateError, - pgmNeIfPollParentError, - pgmNeIfPollTypeError, - pgmNeIfPollError, - pgmNeIfPollSuccess, - pgmNeIfPollOriginated, - pgmNeIfPolrNoState, - pgmNeIfPolrError, - pgmNeIfPolrParityError, - pgmNeIfPolrSuccess, - pgmNeIfPolrOriginated, - pgmNeIfNcfError, - pgmNeIfNcfParityError, - pgmNeIfNcfPartialParity, - pgmNeIfNcfReceived, - pgmNeIfNcfAnticipated, - pgmNeIfNcfRedirecting, - pgmNeIfNakEliminated, - pgmNeIfNakError, - pgmNeIfNakParityError, - pgmNeIfNNakEliminated, - pgmNeIfNNakError, - pgmNeIfNNakParityError, - pgmNeIfNNakCongestionReports, - pgmNeIfNakRetryExpired, - pgmNeIfNakRetryExpiredDLR, - pgmNeIfNakForwardedDLR, - pgmNeIfNakRetransmitted, - pgmNeIfRdataEliminatedOIF, - pgmNeIfRdataEliminatedSqn, - pgmNeIfInRdataFragments, - pgmNeIfRdataFragmentsNoSessionErrors, - pgmNeIfRdataFragmentsEliminatedOIF, - pgmNeIfRdataFragmentsEliminatedSqn, - pgmNeIfOutRdataFragments, - pgmNeTotalTsiNumberOfEntries, - pgmNeTsiStateBits, - pgmNeTsiDataDestinationPort, - pgmNeTsiSourceAddress, - pgmNeTsiGroupAddress, - pgmNeTsiUpstreamAddress, - pgmNeTsiUpstreamIfIndex, - pgmNeTsiDlrAddress, - pgmNeTsiSessionTrailEdgeSeq, - pgmNeTsiSessionIncrSeq, - pgmNeTsiLeadEdgeSeq, - pgmNeTsiInSpms, - pgmNeTsiOutSpms, - pgmNeTsiInParitySpms, - pgmNeTsiOutParitySpms, - pgmNeTsiTotalReXmitStates, - pgmNeTsiTotalReXmitTimedOut, - pgmNeTsiInRdata, - pgmNeTsiOutRdata, - pgmNeTsiInParityRdata, - pgmNeTsiOutParityRdata, - pgmNeTsiInRdataNoStateErrors, - pgmNeTsiUniqueNaks, - pgmNeTsiInNaks, - pgmNeTsiOutNaks, - pgmNeTsiUniqueParityNaks, - pgmNeTsiInParityNaks, - pgmNeTsiOutParityNaks, - pgmNeTsiInNakSeqErrors, - pgmNeTsiInNnaks, - pgmNeTsiOutNnaks, - pgmNeTsiInParityNnaks, - pgmNeTsiOutParityNnaks, - pgmNeTsiInNcfs, - pgmNeTsiOutNcfs, - pgmNeTsiInParityNcfs, - pgmNeTsiOutParityNcfs, - pgmNeTsiSpmSequenceNumber, - pgmNeTsiTransmissionGroupSize, - pgmNeTsiTimeout, - pgmNeTsiLastTtl, - pgmNeTsiLinkLossRate, - pgmNeTsiPathLossRate, - pgmNeTsiReceiverLossRate, - pgmNeTsiCongestionReportLead, - pgmNeTsiCongestionReportWorstReceiver, - pgmNeTsiRtxNumberOfEntries, - pgmNeTsiRtxReqParityTgCount, - pgmNeTsiRtxTimeout, - pgmNeTsiRtxStateBits, - pgmNeTsiRtxIfNumberOfEntries, - pgmNeTsiRtxIfPacketCount, - pgmNeTsiPolrNumberOfEntries, - pgmNeTsiPolrSequenceNumber, - pgmNeTsiPollNumberOfEntries, - pgmNeTsiPollSequence, - pgmNeTsiPollChildBackoff, - pgmNeTsiPollMask, - pgmNeTsiPollPeriod, - pgmNeTsiPollCount, - pgmNeTsiPollTimeout } - STATUS current - DESCRIPTION - "A collection of objects to support - management of PGM Network Elements." - ::= { pgmMIBGroups 1 } - -pgmSourceMIBGroup OBJECT-GROUP - OBJECTS { pgmSourceSaveDefaults, - pgmSourceLastUpdateTime, - pgmSourceDefaultTtl, - pgmSourceDefaultAdvMode, - pgmSourceDefaultLateJoin, - pgmSourceDefaultTxwMaxRte, - pgmSourceDefaultTxwSecs, - pgmSourceDefaultTxwAdvSecs, - pgmSourceDefaultAdvIvl, - pgmSourceDefaultSpmIvl, - pgmSourceDefaultSpmHeartBeatIvlMin, - pgmSourceDefaultSpmHeartBeatIvlMax, - pgmSourceDefaultRdataBackoffIvl, - pgmSourceDefaultFECProactiveParitySize, - pgmSourceDefaultGroupAddress, - pgmSourceUpdateSinceLastSave, - pgmSourceNumberOfEntries, - pgmSourceSourceAddress, - pgmSourceGroupAddress, - pgmSourceDestPort, - pgmSourceSourceGsi, - pgmSourceSourcePortNumber, - pgmSourceTtl, - pgmSourceAdvMode, - pgmSourceLateJoin, - pgmSourceTxwMaxRte, - pgmSourceTxwSecs, - pgmSourceTxwAdvSecs, - pgmSourceAdvIvl, - pgmSourceSpmIvl, - pgmSourceSpmHeartBeatIvlMin, - pgmSourceSpmHeartBeatIvlMax, - pgmSourceRdataBackoffIvl, - pgmSourceFEC, - pgmSourceFECTransmissionGrpSize, - pgmSourceFECProactiveParitySize, - pgmSourceSpmPathAddress, - pgmSourceDataBytesSent, - pgmSourceDataMsgsSent, - pgmSourceBytesBuffered, - pgmSourceMsgsBuffered, - pgmSourceBytesRetransmitted, - pgmSourceMsgsRetransmitted, - pgmSourceBytesSent, - pgmSourceRawNaksReceived, - pgmSourceNaksIgnored, - pgmSourceCksumErrors, - pgmSourceMalformedNaks, - pgmSourcePacketsDiscarded, - pgmSourceNaksRcvd, - pgmSourceParityBytesRetransmitted, - pgmSourceSelectiveBytesRetransmited, - pgmSourceParityMsgsRetransmitted, - pgmSourceSelectiveMsgsRetransmitted, - pgmSourceBytesAdmit, - pgmSourceMsgsAdmit, - pgmSourceParityNakPacketsReceived, - pgmSourceSelectiveNakPacketsReceived, - pgmSourceParityNaksReceived, - pgmSourceSelectiveNaksReceived, - pgmSourceParityNaksIgnored, - pgmSourceSelectiveNaksIgnored, - pgmSourceAckErrors, - pgmSourcePgmCCAcker, - pgmSourceTransmissionCurrentRate, - pgmSourceAckPacketsReceived, - pgmSourceNNakPacketsReceived, - pgmSourceParityNNakPacketsReceived, - pgmSourceSelectiveNNakPacketsReceived, - pgmSourceNNaksReceived, - pgmSourceParityNNaksReceived, - pgmSourceSelectiveNNaksReceived, - pgmSourceNNakErrors } - STATUS current - DESCRIPTION - "A collection of objects to support management of - PGM sources." - ::= { pgmMIBGroups 2 } - -pgmReceiverMIBGroup OBJECT-GROUP - OBJECTS { pgmReceiverSaveDefaults, - pgmReceiverLastUpdateTime, - pgmReceiverDefaultNakBackoffIvl, - pgmReceiverDefaultNakRepeatIvl, - pgmReceiverDefaultNakNcfRetries, - pgmReceiverDefaultNakRdataIvl, - pgmReceiverDefaultNakDataRetries, - pgmReceiverDefaultSendNaks, - pgmReceiverDefaultLateJoin, - pgmReceiverDefaultNakTtl, - pgmReceiverDefaultDeliveryOrder, - pgmReceiverDefaultNextPgmHop, - pgmReceiverDefaultGroupAddress, - pgmReceiverUpdateSinceLastSave, - pgmReceiverDefaultNakFailureThresholdTimer, - pgmReceiverDefaultNakFailureThreshold, - pgmReceiverNumberOfEntries, - pgmReceiverGroupAddress, - pgmReceiverDestPort, - pgmReceiverSourceAddress, - pgmReceiverLastHop, - pgmReceiverSourceGsi, - pgmReceiverSourcePortNumber, - pgmReceiverUniqueInstance, - pgmReceiverNakBackoffIvl, - pgmReceiverNakRepeatIvl, - pgmReceiverNakNcfRetries, - pgmReceiverNakRdataIvl, - pgmReceiverNakDataRetries, - pgmReceiverSendNaks, - pgmReceiverLateJoin, - pgmReceiverNakTtl, - pgmReceiverDeliveryOrder, - pgmReceiverMcastNaks, - pgmReceiverNakFailureThresholdTimer, - pgmReceiverNakFailureThreshold, - pgmReceiverDataBytesReceived, - pgmReceiverDataMsgsReceived, - pgmReceiverNaksSent, - pgmReceiverNaksRetransmitted, - pgmReceiverNakFailures, - pgmReceiverBytesReceived, - pgmReceiverNaksSuppressed, - pgmReceiverCksumErrors, - pgmReceiverMalformedSpms, - pgmReceiverMalformedOdata, - pgmReceiverMalformedRdata, - pgmReceiverMalformedNcfs, - pgmReceiverPacketsDiscarded, - pgmReceiverLosses, - pgmReceiverBytesDeliveredToApp, - pgmReceiverMsgsDeliveredToApp, - pgmReceiverDupSpms, - pgmReceiverDupDatas, - pgmReceiverDupParities, - pgmReceiverNakPacketsSent, - pgmReceiverParityNakPacketsSent, - pgmReceiverSelectiveNakPacketsSent, - pgmReceiverParityNaksSent, - pgmReceiverSelectiveNaksSent, - pgmReceiverParityNaksRetransmitted, - pgmReceiverSelectiveNaksRetransmitted, - pgmReceiverNaksFailed, - pgmReceiverParityNaksFailed, - pgmReceiverSelectiveNaksFailed, - pgmReceiverNaksFailedRxwAdvanced, - pgmReceiverNaksFaledNcfRetriesExceeded, - pgmReceiverNaksFailedDataRetriesExceeded, - pgmReceiverNaksFailedGenExpired, - pgmReceiverNakFailuresDelivered, - pgmReceiverParityNaksSuppressed, - pgmReceiverSelectiveNaksSuppressed, - pgmReceiverNakErrors, - pgmReceiverOutstandingParityNaks, - pgmReceiverOutstandingSelectiveNaks, - pgmReceiverLastActivity, - pgmReceiverNakSvcTimeMin, - pgmReceiverNakSvcTimeMean, - pgmReceiverNakSvcTimeMax, - pgmReceiverNakFailTimeMin, - pgmReceiverNakFailTimeMean, - pgmReceiverNakFailTimeMax, - pgmReceiverNakTransmitMin, - pgmReceiverNakTransmitMean, - pgmReceiverNakTransmitMax, - pgmReceiverAcksSent, - pgmReceiverRxwTrail, - pgmReceiverRxwLead, - pgmReceiverNakFailuresLastInterval, - pgmReceiverLastIntervalNakFailures } - STATUS current - DESCRIPTION - "A collection of objects to support management of - PGM receivers." - ::= { pgmMIBGroups 3 } - -pgmDLRMIBGroup OBJECT-GROUP - OBJECTS { pgmDlrSaveDefaults, - pgmDlrLastUpdateTime, - pgmDlrGroupAddress, - pgmDlrCacheRtx, - pgmDlrActivityIvl, - pgmDlrMaxRate, - pgmDlrParentNeAddr, - pgmDlrUpdateSinceLastSave, - pgmDlrSourceNumberOfEntries, - pgmDlrSourceGroupAddress, - pgmDlrSourceSourceGsi, - pgmDlrSourceSourcePortNumber, - pgmDlrSourceGroupTtl, - pgmDlrSourceRdataBackoffIvl, - pgmDlrSourceRdataMsgsSent, - pgmDlrSourceRdataBytesSent, - pgmDlrSourceBytesSent, - pgmDlrSourceNaksRcvd, - pgmDlrSourceNaksIgnored, - pgmDlrSourceNakErrors, - pgmDlrSourceDiscards, - pgmDlrSourceCksumErrors, - pgmDlrSourceNNaksSent, - pgmDlrSourceBytesBuffered, - pgmDlrSourceMsgsBuffered, - pgmDlrSourceParityBytesRetransmitted, - pgmDlrSourceSelectiveBytesRetransmited, - pgmDlrSourceParityMsgsRetransmitted, - pgmDlrSourceSelectiveMsgsRetransmitted, - pgmDlrSourceBytesAdmit, - pgmDlrSourceMsgsAdmit, - pgmDlrSourceNakPacketsReceived, - pgmDlrSourceParityNakPacketsReceived, - pgmDlrSourceSelectiveNakPacketsReceived, - pgmDlrSourceParityNaksReceived, - pgmDlrSourceSelectiveNaksReceived, - pgmDlrSourceParityNaksIgnored, - pgmDlrSourceSelectiveNaksIgnored, - pgmDlrSourceAckErrors, - pgmDlrSourceNNakErrors, - pgmDlrSourceAckPacketsReceived, - pgmDlrSourceNNakPacketsReceived, - pgmDlrSourceParityNNakPacketsReceived, - pgmDlrSourceSelectiveNNakPacketsReceived, - pgmDlrSourceNNaksReceived, - pgmDlrSourceParityNNaksReceived, - pgmDlrSourceSelectiveNNaksReceived } - STATUS current - DESCRIPTION - "A collection of objects to support management of - PGM designated local repairers (DLR)." - ::= { pgmMIBGroups 4 } - -pgmTrapsMIBGroup NOTIFICATION-GROUP - NOTIFICATIONS { pgmStart, - pgmStop } - STATUS current - DESCRIPTION - "A collection of objects to support pgm - specific traps." - ::= { pgmMIBGroups 5 } - -pgmTrapsSourceMIBGroup NOTIFICATION-GROUP - NOTIFICATIONS { pgmNewSourceTrap, - pgmClosedSourceTrap } - STATUS current - DESCRIPTION - "A collection of objects to support pgm - source specific traps." - ::= { pgmMIBGroups 6 } - -pgmTrapsReceiverMIBGroup NOTIFICATION-GROUP - NOTIFICATIONS { pgmNewReceiverTrap, - pgmClosedReceiverTrap, - pgmNakFailuresTrap } - STATUS current - DESCRIPTION - "A collection of objects to support pgm - receiver specific traps." - ::= { pgmMIBGroups 7 } - -pgmTrapsDlrSourceMIBGroup NOTIFICATION-GROUP - NOTIFICATIONS { pgmNewDlrSourceTrap, - pgmClosedDlrSourceTrap } - STATUS current - DESCRIPTION - "A collection of objects to support pgm - dlr source specific traps." - ::= { pgmMIBGroups 8 } - - -END - diff --git a/3rdparty/openpgm-svn-r1085/pgm/mld-semantics.txt b/3rdparty/openpgm-svn-r1085/pgm/mld-semantics.txt deleted file mode 100644 index 135400d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/mld-semantics.txt +++ /dev/null @@ -1,52 +0,0 @@ - previous request following request return - ----------------- ----------------- ----------- - MCAST_JOIN_GROUP MCAST_JOIN_GROUP EADDRINUSE - MCAST_JOIN_GROUP MCAST_LEAVE_GROUP 0 - MCAST_JOIN_GROUP MCAST_JOIN_SOURCE_GROUP EINVAL - MCAST_JOIN_GROUP MCAST_LEAVE_SOURCE_GROUP EINVAL - MCAST_JOIN_GROUP MCAST_BLOCK_SOURCE 0 - MCAST_JOIN_SOURCE_GROUP MCAST_JOIN_GROUP EADDRINUSE - MCAST_JOIN_SOURCE_GROUP MCAST_LEAVE_GROUP 0 - MCAST_JOIN_SOURCE_GROUP MCAST_JOIN_SOURCE_GROUP (*1) - MCAST_JOIN_SOURCE_GROUP MCAST_LEAVE_SOURCE_GROUP (*2) - MCAST_JOIN_SOURCE_GROUP MCAST_BLOCK_SOURCE EINVAL - MCAST_JOIN_SOURCE_GROUP MCAST_UNBLOCK_SOURCE EINVAL - MCAST_BLOCK_SOURCE MCAST_JOIN_GROUP EADDRINUSE - MCAST_BLOCK_SOURCE MCAST_LEAVE_GROUP 0 - MCAST_BLOCK_SOURCE MCAST_JOIN_SOURCE_GROUP EINVAL - MCAST_BLOCK_SOURCE MCAST_LEAVE_SOURCE_GROUP EINVAL - MCAST_BLOCK_SOURCE MCAST_BLOCK_SOURCE (*1) - MCAST_BLOCK_SOURCE MCAST_UNBLOCK_SOURCE (*2) - -(*1) EADDRNOTAVAIL if source address is same of filtered one. Otherwise 0. -(*2) EADDRNOTAVAIL if source address is not same of filtered one. Otherwise 0. - - -http://planete.inria.fr/Hitoshi.Asaeda/mldv2/README.txt - - -The following steps apply for any-source applications: - - Use MCAST_JOIN_GROUP to join a group. - Use MCAST_BLOCK_SOURCE to turn off a given source, if required. - Use MCAST_UNBLOCK_SOURCE to re-allow a blocked source, if required. - Use MCAST_LEAVE_GROUP to leave the group. - -The following steps apply for controlled-source applications: - - Use MCAST_JOIN_SOURCE_GROUP to join each group/source pair. - Use MCAST_LEAVE_SOURCE_GROUP to leave each group/source, or use MCAST_LEAVE_GROUP to leave all sources, if the same group address is used by all sources. - -The following steps apply for any-source applications: - - Use IP_ADD_MEMBERSHIP to join a group (IPV6_ADD_MEMBERSHIP for IPv6). - Use IP_BLOCK_SOURCE to turn off a given source, if required. - Use IP_UNBLOCK_SOURCE to re-allow a blocked source, if required. - Use IP_DROP_MEMBERSHIP to leave the group (IPV6_DROP_MEMBERSHIP for IPv6). - -The following steps apply for controlled-source applications: - - Use IP_ADD_SOURCE_MEMBERSHIP to join each group/source pair. - Use IP_DROP_SOURCE_MEMBERSHIP to leave each group/source, or use IP_DROP_MEMBERSHIP to leave all sources, if the same group address is used by all sources. - -http://msdn.microsoft.com/en-us/library/ms738558(VS.85).aspx diff --git a/3rdparty/openpgm-svn-r1085/pgm/msfec.txt b/3rdparty/openpgm-svn-r1085/pgm/msfec.txt deleted file mode 100644 index 4b2c23a..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/msfec.txt +++ /dev/null @@ -1,33 +0,0 @@ -FEC parameters for Microsoft's PGM stack - - -FECBlockSize (n) [FECGroupSize+1, 255] -Maximum number of packets that can be sent for any group, including original data and parity packets. Maximum and default value is 255. - -FECProActivePackets -Number of packets to send proactively with each group. Use this option when the network is dispersed, and upstream NAK requests are expensive. - -FECGroupSize (k) [2, 128] -Number of packets to be treated as one group for the purpose of computing parity packets. Group size must be a power of two. In lossy networks, keep the group size relatively small. - -fFECOnDemandParityEnabled -Specifies whether the sender is enabled for sending parity repair packets. When TRUE, receivers should only request parity repair packets. - - -Reed Solomon codes: - - encode/decode time (us) -RS(255, 2) 4/6 -RS(255, 4) 7/10 -RS(255, 8) 14/18 -RS(255, 16) 29/34 -RS(255, 32) 57/64 -RS(255, 64) 119/134 -RS(255, 128) 236/fail(278) - -reference platform: Intel Xeon CPU 3.20Ghz - - -Implementation exact copy of Luigi Rizzo FEC code as demonstrated in RMDP: - -http://info.iet.unipi.it/~luigi/fec.html diff --git a/3rdparty/openpgm-svn-r1085/pgm/nametoindex.c b/3rdparty/openpgm-svn-r1085/pgm/nametoindex.c deleted file mode 100644 index 28444d1..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/nametoindex.c +++ /dev/null @@ -1,249 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Windows interface name to interface index function. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef _WIN32 -# include -# include -#endif -#include -#include - - -//#define NAMETOINDEX_DEBUG - -#define MAX_TRIES 3 -#define DEFAULT_BUFFER_SIZE 4096 - - -#ifdef _WIN32 -static inline -void* -_pgm_heap_alloc ( - const size_t n_bytes - ) -{ -# ifdef CONFIG_USE_HEAPALLOC - return HeapAlloc (GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, n_bytes); -# else - return pgm_malloc (n_bytes); -# endif -} - -static inline -void -_pgm_heap_free ( - void* mem - ) -{ -# ifdef CONFIG_USE_HEAPALLOC - HeapFree (GetProcessHeap(), 0, mem); -# else - pgm_free (mem); -# endif -} - -/* Retrieve adapter index via name. - * Wine edition: First try GetAdapterIndex() then fallback to enumerating - * adapters via GetAdaptersInfo(). - * - * On error returns zero, no errors are defined. - */ - -static -unsigned /* type matching if_nametoindex() */ -_pgm_getadaptersinfo_nametoindex ( - const sa_family_t iffamily, - const char* ifname - ) -{ - pgm_return_val_if_fail (NULL != ifname, 0); - - pgm_assert (AF_INET6 != iffamily); - - DWORD dwRet, ifIndex; - ULONG ulOutBufLen = DEFAULT_BUFFER_SIZE; - PIP_ADAPTER_INFO pAdapterInfo = NULL; - PIP_ADAPTER_INFO pAdapter = NULL; - -/* loop to handle interfaces coming online causing a buffer overflow - * between first call to list buffer length and second call to enumerate. - */ - for (unsigned i = MAX_TRIES; i; i--) - { - pgm_debug ("IP_ADAPTER_INFO buffer length %lu bytes.", ulOutBufLen); - pAdapterInfo = (IP_ADAPTER_INFO*)_pgm_heap_alloc (ulOutBufLen); - dwRet = GetAdaptersInfo (pAdapterInfo, &ulOutBufLen); - if (ERROR_BUFFER_OVERFLOW == dwRet) { - _pgm_heap_free (pAdapterInfo); - pAdapterInfo = NULL; - } else { - break; - } - } - - switch (dwRet) { - case ERROR_SUCCESS: /* NO_ERROR */ - break; - case ERROR_BUFFER_OVERFLOW: - pgm_warn (_("GetAdaptersInfo repeatedly failed with ERROR_BUFFER_OVERFLOW.")); - if (pAdapterInfo) - _pgm_heap_free (pAdapterInfo); - return 0; - default: - pgm_warn (_("GetAdaptersInfo failed")); - if (pAdapterInfo) - _pgm_heap_free (pAdapterInfo); - return 0; - } - - for (pAdapter = pAdapterInfo; - pAdapter; - pAdapter = pAdapter->Next) - { - for (IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList; - pIPAddr; - pIPAddr = pIPAddr->Next) - { -/* skip null adapters */ - if (strlen (pIPAddr->IpAddress.String) == 0) - continue; - - if (0 == strncmp (ifname, pAdapter->AdapterName, IF_NAMESIZE)) { - ifIndex = pAdapter->Index; - _pgm_heap_free (pAdapterInfo); - return ifIndex; - } - } - } - - if (pAdapterInfo) - _pgm_heap_free (pAdapterInfo); - return 0; -} - -/* Retrieve adapter index via name. - * Windows edition: First try GetAdapterIndex() then fallback to enumerating - * adapters via GetAdaptersAddresses(). - * - * On error returns zero, no errors are defined. - */ - -static -unsigned /* type matching if_nametoindex() */ -_pgm_getadaptersaddresses_nametoindex ( - const sa_family_t iffamily, - const char* ifname - ) -{ - pgm_return_val_if_fail (NULL != ifname, 0); - - ULONG ifIndex; - DWORD dwSize = DEFAULT_BUFFER_SIZE, dwRet; - IP_ADAPTER_ADDRESSES *pAdapterAddresses = NULL, *adapter; - -/* first see if GetAdapterIndex is working - */ - dwRet = GetAdapterIndex ((const LPWSTR)ifname, &ifIndex); - if (NO_ERROR == dwRet) - return ifIndex; - -/* fallback to finding index via iterating adapter list */ - -/* loop to handle interfaces coming online causing a buffer overflow - * between first call to list buffer length and second call to enumerate. - */ - for (unsigned i = MAX_TRIES; i; i--) - { - pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_pgm_heap_alloc (dwSize); - dwRet = GetAdaptersAddresses (AF_UNSPEC, - GAA_FLAG_SKIP_ANYCAST | - GAA_FLAG_SKIP_DNS_SERVER | - GAA_FLAG_SKIP_FRIENDLY_NAME | - GAA_FLAG_SKIP_MULTICAST, - NULL, - pAdapterAddresses, - &dwSize); - if (ERROR_BUFFER_OVERFLOW == dwRet) { - _pgm_heap_free (pAdapterAddresses); - pAdapterAddresses = NULL; - } else { - break; - } - } - - switch (dwRet) { - case ERROR_SUCCESS: - break; - case ERROR_BUFFER_OVERFLOW: - pgm_warn (_("GetAdaptersAddresses repeatedly failed with ERROR_BUFFER_OVERFLOW")); - if (pAdapterAddresses) - _pgm_heap_free (pAdapterAddresses); - return 0; - default: - pgm_warn (_("GetAdaptersAddresses failed")); - if (pAdapterAddresses) - _pgm_heap_free (pAdapterAddresses); - return 0; - } - - for (adapter = pAdapterAddresses; - adapter; - adapter = adapter->Next) - { - if (0 == strcmp (ifname, adapter->AdapterName)) { - ifIndex = AF_INET6 == iffamily ? adapter->Ipv6IfIndex : adapter->IfIndex; - _pgm_heap_free (pAdapterAddresses); - return ifIndex; - } - } - - if (pAdapterAddresses) - _pgm_heap_free (pAdapterAddresses); - return 0; -} -#endif /* _WIN32 */ - -/* Retrieve interface index for a specified adapter name. - * On error returns zero, no errors are defined. - */ - -unsigned /* type matching if_nametoindex() */ -pgm_if_nametoindex ( -#ifndef _WIN32 - PGM_GNUC_UNUSED const sa_family_t iffamily, -#else - const sa_family_t iffamily, -#endif - const char* ifname - ) -{ - pgm_return_val_if_fail (NULL != ifname, 0); - -#ifndef _WIN32 - return if_nametoindex (ifname); -#elif defined(CONFIG_TARGET_WINE) - return _pgm_getadaptersinfo_nametoindex (iffamily, ifname); -#else - return _pgm_getadaptersaddresses_nametoindex (iffamily, ifname); -#endif -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/net-snmp.txt b/3rdparty/openpgm-svn-r1085/pgm/net-snmp.txt deleted file mode 100644 index 549bcc2..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/net-snmp.txt +++ /dev/null @@ -1,34 +0,0 @@ -net-snmp is hard coded on mib location, only the mib file names can -be specified outside of snmptranslate. - -$ mkdir -p ~/.snmp/mibs -$ cp mibs/PGM-MIB-petrova-01.txt ~/.snmp/mibs - -Basic test: - -$ snmptranslate -m ALL -IR pgmMIB -PGM-MIB::pgmMIB - -Display full pretty tree: - -$ snmptranslate -m ALL -Tp -IR pgmMIB -+--pgmMIB(112) - | - +--pgm(1) - | | - | +--pgmNetworkElement(1) - | | | -... - - -Now the framework tool can be used: - -$ env MIBS="+ALL" mib2c pgmMIB - -... - -To run with SNMP install snmpd, enable "master agentx" and walk: - -$ env MIBS="+ALL" snmpwalk -v 1 -c public localhost pgmMIB -End of MIB - diff --git a/3rdparty/openpgm-svn-r1085/pgm/net.c b/3rdparty/openpgm-svn-r1085/pgm/net.c deleted file mode 100644 index 5b2f9e9..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/net.c +++ /dev/null @@ -1,175 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * network send wrapper. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#ifdef CONFIG_HAVE_POLL -# include -#endif -#ifndef _WIN32 -# include -# include -# include -#endif -#include -#include -#include -#include - - -#define NET_DEBUG - - -#if !defined(ENETUNREACH) && defined(WSAENETUNREACH) -# define ENETUNREACH WSAENETUNREACH -#endif -#if !defined(EHOSTUNREACH) && defined(WSAEHOSTUNREACH) -# define EHOSTUNREACH WSAEHOSTUNREACH -#endif -#if !defined(ENOBUFS) && defined(WSAENOBUFS) -# define ENOBUFS WSAENOBUFS -#endif - - -/* locked and rate regulated sendto - * - * on success, returns number of bytes sent. on error, -1 is returned, and - * errno set appropriately. - */ - -ssize_t -pgm_sendto ( - pgm_sock_t* sock, - bool use_rate_limit, - bool use_router_alert, - const void* restrict buf, - size_t len, - const struct sockaddr* restrict to, - socklen_t tolen - ) -{ - pgm_assert( NULL != sock ); - pgm_assert( NULL != buf ); - pgm_assert( len > 0 ); - pgm_assert( NULL != to ); - pgm_assert( tolen > 0 ); - -#ifdef NET_DEBUG - char saddr[INET_ADDRSTRLEN]; - pgm_sockaddr_ntop (to, saddr, sizeof(saddr)); - pgm_debug ("pgm_sendto (sock:%p use_rate_limit:%s use_router_alert:%s buf:%p len:%zu to:%s [toport:%d] tolen:%d)", - (const void*)sock, - use_rate_limit ? "TRUE" : "FALSE", - use_router_alert ? "TRUE" : "FALSE", - (const void*)buf, - len, - saddr, - ntohs (((const struct sockaddr_in*)to)->sin_port), - (int)tolen); -#endif - - const int send_sock = use_router_alert ? sock->send_with_router_alert_sock : sock->send_sock; - - if (use_rate_limit && - !pgm_rate_check (&sock->rate_control, len, sock->is_nonblocking)) - { - errno = ENOBUFS; - return (const ssize_t)-1; - } - - if (!use_router_alert && sock->can_send_data) - pgm_mutex_lock (&sock->send_mutex); - - ssize_t sent = sendto (send_sock, buf, len, 0, to, (socklen_t)tolen); - pgm_debug ("sendto returned %zd", sent); - if (sent < 0) { - int save_errno = pgm_sock_errno(); - if (PGM_UNLIKELY(errno != ENETUNREACH && /* Network is unreachable */ - errno != EHOSTUNREACH && /* No route to host */ - errno != EAGAIN)) /* would block on non-blocking send */ - { -#ifdef CONFIG_HAVE_POLL -/* poll for cleared socket */ - struct pollfd p = { - .fd = send_sock, - .events = POLLOUT, - .revents = 0 - }; - const int ready = poll (&p, 1, 500 /* ms */); -#else - fd_set writefds; - FD_ZERO(&writefds); - FD_SET(send_sock, &writefds); - struct timeval tv = { - .tv_sec = 0, - .tv_usec = 500 /* ms */ * 1000 - }; - const int ready = select (1, NULL, &writefds, NULL, &tv); -#endif /* CONFIG_HAVE_POLL */ - if (ready > 0) - { - sent = sendto (send_sock, buf, len, 0, to, (socklen_t)tolen); - if ( sent < 0 ) - { - save_errno = pgm_sock_errno(); - pgm_warn (_("sendto() %s failed: %s"), - inet_ntoa( ((const struct sockaddr_in*)to)->sin_addr ), - pgm_sock_strerror (save_errno)); - } - } - else if (ready == 0) - { - pgm_warn (_("sendto() %s failed: socket timeout."), - inet_ntoa( ((const struct sockaddr_in*)to)->sin_addr )); - } - else - { - save_errno = pgm_sock_errno(); - pgm_warn (_("blocked socket failed: %s"), - pgm_sock_strerror (save_errno)); - } - } - } - - if (!use_router_alert && sock->can_send_data) - pgm_mutex_unlock (&sock->send_mutex); - return sent; -} - -/* socket helper, for setting pipe ends non-blocking - * - * on success, returns 0. on error, returns -1, and sets errno appropriately. - */ - -int -pgm_set_nonblocking ( - int fd[2] - ) -{ -/* pre-conditions */ - pgm_assert (fd[0]); - pgm_assert (fd[1]); - - pgm_sockaddr_nonblocking (fd[0], TRUE); - pgm_sockaddr_nonblocking (fd[1], TRUE); - return 0; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/net_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/net_unittest.c deleted file mode 100644 index fc684ca..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/net_unittest.c +++ /dev/null @@ -1,375 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for network send wrapper. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include - - -/* mock state */ - -#define pgm_rate_check mock_pgm_rate_check -#define sendto mock_sendto -#define poll mock_poll -#define select mock_select -#define fcntl mock_fcntl - -#define NET_DEBUG -#include "net.c" - - -static -pgm_sock_t* -generate_sock (void) -{ - pgm_sock_t* sock = g_malloc0 (sizeof(pgm_sock_t)); - return sock; -} - -static -char* -flags_string ( - int flags - ) -{ - static char s[1024]; - - s[0] = '\0'; - if (flags & MSG_OOB) - strcat (s, "MSG_OOB"); -#define MSG(flag) \ - do { \ - if (flags & flag) { \ - strcat (s, s[0] ? ("|" #flag) : (#flag)); \ - } \ - } while (0) -#ifdef MSG_PEEK - MSG(MSG_PEEK); -#endif -#ifdef MSG_DONTROUTE - MSG(MSG_DONTROUTE); -#endif -#ifdef MSG_CTRUNC - MSG(MSG_CTRUNC); -#endif -#ifdef MSG_PROXY - MSG(MSG_PROXY); -#endif -#ifdef MSG_TRUNC - MSG(MSG_TRUNC); -#endif -#ifdef MSG_DONTWAIT - MSG(MSG_DONTWAIT); -#endif -#ifdef MSG_EOR - MSG(MSG_EOR); -#endif -#ifdef MSG_WAITALL - MSG(MSG_WAITALL); -#endif -#ifdef MSG_FIN - MSG(MSG_FIN); -#endif -#ifdef MSG_SYN - MSG(MSG_SYN); -#endif -#ifdef MSG_CONFIRM - MSG(MSG_CONFIRM); -#endif -#ifdef MSG_RST - MSG(MSG_RST); -#endif -#ifdef MSG_ERRQUEUE - MSG(MSG_ERRQUEUE); -#endif -#ifdef MSG_NOSIGNAL - MSG(MSG_NOSIGNAL); -#endif -#ifdef MSG_MORE - MSG(MSG_MORE); -#endif -#ifdef MSG_CMSG_CLOEXEC - MSG(MSG_CMSG_CLOEXEC); -#endif - if (!s[0]) { - if (flags) - sprintf (s, "0x%x", flags); - else - strcpy (s, "0"); - } - return s; -} - - -/* mock functions for external references */ - -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return 0; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_rate_check ( - pgm_rate_t* bucket, - const size_t data_size, - const bool is_nonblocking - ) -{ - g_debug ("mock_pgm_rate_check (bucket:%p data-size:%zu is-nonblocking:%s)", - (gpointer)bucket, data_size, is_nonblocking ? "TRUE" : "FALSE"); - return TRUE; -} - -ssize_t -mock_sendto ( - int s, - const void* buf, - size_t len, - int flags, - const struct sockaddr* to, - socklen_t tolen - ) -{ - char saddr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop (to, saddr, sizeof(saddr)); - g_debug ("mock_sendto (s:%i buf:%p len:%d flags:%s to:%s tolen:%d)", - s, buf, len, flags_string (flags), saddr, tolen); - return len; -} - -#ifdef CONFIG_HAVE_POLL -int -mock_poll ( - struct pollfd* fds, - nfds_t nfds, - int timeout - ) -{ - g_debug ("mock_poll (fds:%p nfds:%d timeout:%d)", - (gpointer)fds, (int)nfds, timeout); - return 0; -} -#else -int -mock_select ( - int nfds, - fd_set* readfds, - fd_set* writefds, - fd_set* exceptfds, - struct timeval* timeout - ) -{ - g_debug ("mock_select (nfds:%d readfds:%p writefds:%p exceptfds:%p timeout:%p)", - nfds, (gpointer)readfds, (gpointer)writefds, (gpointer)exceptfds, (gpointer)timeout); - return 0; -} -#endif - -int -mock_fcntl ( - int fd, - int cmd, - ... - ) -{ - long arg; - va_list args; - if (F_GETFL == cmd) { - g_debug ("mock_fcntl (fd:%d cmd:F_GETFL)", fd); - return 0; - } - if (F_SETFL == cmd) { - va_start (args, cmd); - arg = va_arg (args, long); - va_end (args); - g_debug ("mock_fcntl (fd:%d cmd:F_SETFL arg:%ld)", fd, arg); - return arg; - } - g_assert_not_reached(); -} - - -/* target: - * ssize_t - * pgm_sendto ( - * pgm_sock_t* sock, - * bool use_rate_limit, - * bool use_router_alert, - * const void* buf, - * size_t len, - * const struct sockaddr* to, - * socklen_t tolen - * ) - */ - -START_TEST (test_sendto_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - const char* buf = "i am not a string"; - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr ("172.12.90.1") - }; - gssize len = pgm_sendto (sock, FALSE, FALSE, buf, sizeof(buf), (struct sockaddr*)&addr, sizeof(addr)); - fail_unless (sizeof(buf) == len, "sendto underrun"); -} -END_TEST - -START_TEST (test_sendto_fail_001) -{ - const char* buf = "i am not a string"; - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr ("172.12.90.1") - }; - gssize len = pgm_sendto (NULL, FALSE, FALSE, buf, sizeof(buf), (struct sockaddr*)&addr, sizeof(addr)); - fail ("reached"); -} -END_TEST - -START_TEST (test_sendto_fail_002) -{ - pgm_sock_t* sock = generate_sock (); - const char* buf = "i am not a string"; - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr ("172.12.90.1") - }; - gssize len = pgm_sendto (sock, FALSE, FALSE, NULL, sizeof(buf), (struct sockaddr*)&addr, sizeof(addr)); - fail ("reached"); -} -END_TEST - -START_TEST (test_sendto_fail_003) -{ - pgm_sock_t* sock = generate_sock (); - const char* buf = "i am not a string"; - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr ("172.12.90.1") - }; - gssize len = pgm_sendto (sock, FALSE, FALSE, buf, 0, (struct sockaddr*)&addr, sizeof(addr)); - fail ("reached"); -} -END_TEST - -START_TEST (test_sendto_fail_004) -{ - pgm_sock_t* sock = generate_sock (); - const char* buf = "i am not a string"; - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr ("172.12.90.1") - }; - gssize len = pgm_sendto (sock, FALSE, FALSE, buf, sizeof(buf), NULL, sizeof(addr)); - fail ("reached"); -} -END_TEST - -START_TEST (test_sendto_fail_005) -{ - pgm_sock_t* sock = generate_sock (); - const char* buf = "i am not a string"; - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr ("172.12.90.1") - }; - gssize len = pgm_sendto (sock, FALSE, FALSE, buf, sizeof(buf), (struct sockaddr*)&addr, 0); - fail ("reached"); -} -END_TEST - -/* target: - * int - * pgm_set_nonblocking ( - * int filedes[2] - * ) - */ - -START_TEST (test_set_nonblocking_pass_001) -{ - int filedes[2] = { fileno (stdout), fileno (stderr) }; - int retval = pgm_set_nonblocking (filedes); -} -END_TEST - -START_TEST (test_set_nonblocking_fail_001) -{ - int filedes[2] = { 0, 0 }; - int retval = pgm_set_nonblocking (filedes); - fail ("reached"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_sendto = tcase_create ("sendto"); - suite_add_tcase (s, tc_sendto); - tcase_add_test (tc_sendto, test_sendto_pass_001); - tcase_add_test_raise_signal (tc_sendto, test_sendto_fail_001, SIGABRT); - tcase_add_test_raise_signal (tc_sendto, test_sendto_fail_002, SIGABRT); - tcase_add_test_raise_signal (tc_sendto, test_sendto_fail_003, SIGABRT); - tcase_add_test_raise_signal (tc_sendto, test_sendto_fail_004, SIGABRT); - tcase_add_test_raise_signal (tc_sendto, test_sendto_fail_005, SIGABRT); - - TCase* tc_set_nonblocking = tcase_create ("set-nonblocking"); - suite_add_tcase (s, tc_set_nonblocking); - tcase_add_test (tc_set_nonblocking, test_set_nonblocking_pass_001); - tcase_add_test_raise_signal (tc_set_nonblocking, test_set_nonblocking_fail_001, SIGABRT); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/options.txt b/3rdparty/openpgm-svn-r1085/pgm/options.txt deleted file mode 100644 index cb01da0..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/options.txt +++ /dev/null @@ -1,158 +0,0 @@ - OPT_LENGTH 0x00 - Option's Length - -pgm_opt_header -pgm_opt_length - -first option, always present. - --------------------------------------------------------------------------------- - - OPT_FRAGMENT 0x01 - Fragmentation - -pgm_opt_header -pgm_opt_fragment - -may be present for odata, rdata. 'MAY' exist for others, although a bit strange. - --------------------------------------------------------------------------------- - - OPT_NAK_LIST 0x02 - List of NAK entries - -pgm_opt_header -pgm_opt_nak_list - -may be present for naks. - --------------------------------------------------------------------------------- - - OPT_JOIN 0x03 - Late Joining - -pgm_opt_header -pgm_opt_join - -may be present for odata, rdata, spm. - -requires SPM to learn NLA already so not overly useful with odata/rdata, could be -used with video streaming to last i-frame data sequence number. - --------------------------------------------------------------------------------- - - OPT_REDIRECT 0x07 - Redirect - -pgm_opt_header -pgm_opt_redirect -pgm_opt_redirect6 - -should be present for polrs from a dlr. - --------------------------------------------------------------------------------- - - OPT_SYN 0x0D - Synchronization - -pgm_opt_header -pgm_opt_syn - -must only appear with odata or rdata. - --------------------------------------------------------------------------------- - - OPT_FIN 0x0E - Session Fin receivers, conventional - feedbackish - -pgm_opt_header -opt_opt_fin - -may be present for odata, rdata, must appear in following spms. - --------------------------------------------------------------------------------- - - OPT_RST 0x0F - Session Reset - -pgm_opt_header -pgm_opt_rst - -must only appear in spms. not many 'unrecoverable error conditions' exist though. - --------------------------------------------------------------------------------- - - OPT_PARITY - -must appear in odata or rdata to indicate pro-active or on-demand parity data, -nak to request parity repair data, ncf to confirm parity nak. - - - OPT_VAR_PKTLEN - -may be present in odata or data to indicate variable size packets. - - - OPT_PARITY_PRM 0x08 - Forward Error Correction Parameters - -pgm_opt_header -pgm_opt_parity_prm - -appended to spms to inform of pro-active or on-demand parity. - --------------------------------------------------------------------------------- - - OPT_PARITY_GRP 0x09 - Forward Error Correction Group Number - -pgm_opt_parity_grp - -appended to odata and rdata parity packets. - --------------------------------------------------------------------------------- - - OPT_CURR_TGSIZE 0x0A - Forward Error Correction Group Size - -pgm_opt_curr_tgsize - -must appear in last odata or rdata packet of variable transmission group, may -appear in spms. - --------------------------------------------------------------------------------- - - OPT_CR 0x10 - Congestion Report - -pgm_opt_header -pgm_opt_cr - --------------------------------------------------------------------------------- - - OPT_CRQST 0x11 - Congestion Report Request - -pgm_opt_header -pgm_opt_crqst - --------------------------------------------------------------------------------- - - OPT_NAK_BO_IVL 0x04 - NAK Back-Off Interval - -pgm_opt_header -pgm_opt_nak_bo_ivl - --------------------------------------------------------------------------------- - - OPT_NAK_BO_RNG 0x05 - NAK Back-Off Range - -pgm_opt_header -pgm_opt_nak_bo_rng - --------------------------------------------------------------------------------- - - OPT_NBR_UNREACH 0x0B - Neighbor Unreachable - -pgm_opt_header -pgm_opt_nbr_unreach - --------------------------------------------------------------------------------- - - OPT_PATH_NLA 0x0C - Path NLA - -pgm_opt_header -pgm_opt_path_nla -pgm_opt6_path_nla - --------------------------------------------------------------------------------- - - OPT_INVALID 0x7F - Option invalidated diff --git a/3rdparty/openpgm-svn-r1085/pgm/packet_parse.c b/3rdparty/openpgm-svn-r1085/pgm/packet_parse.c deleted file mode 100644 index 0fad8ca..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/packet_parse.c +++ /dev/null @@ -1,615 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM packet formats, RFC 3208. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include - - -//#define PACKET_DEBUG - -#ifndef PACKET_DEBUG -# define PGM_DISABLE_ASSERT -#endif - - -/* locals */ - -static bool pgm_parse (struct pgm_sk_buff_t*const restrict, pgm_error_t**restrict); - - -/* Parse a raw-IP packet for IP and PGM header and any payload. - */ - -#define PGM_MIN_SIZE ( \ - sizeof(struct pgm_ip) + /* IPv4 header */ \ - sizeof(struct pgm_header) /* PGM header */ \ - ) - -bool -pgm_parse_raw ( - struct pgm_sk_buff_t* const restrict skb, /* data will be modified */ - struct sockaddr* const restrict dst, - pgm_error_t** restrict error - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - pgm_assert (NULL != dst); - - pgm_debug ("pgm_parse_raw (skb:%p dst:%p error:%p)", - (const void*)skb, (const void*)dst, (const void*)error); - -/* minimum size should be IPv4 header plus PGM header, check IP version later */ - if (PGM_UNLIKELY(skb->len < PGM_MIN_SIZE)) - { - pgm_set_error (error, - PGM_ERROR_DOMAIN_PACKET, - PGM_ERROR_BOUNDS, - _("IP packet too small at %" PRIu16 " bytes, expecting at least %" PRIu16 " bytes."), - skb->len, (uint16_t)PGM_MIN_SIZE); - return FALSE; - } - -/* IP packet header: IPv4 - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |Version| HL | ToS | Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Fragment ID |R|D|M| Fragment Offset | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | TTL | Protocol | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source IP Address | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Destination IP Address | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | IP Options when present ... - * +-+-+-+-+-+-+-+-+-+-+-+-+ ... - * | Data ... - * +-+-+- ... - * - * IPv6 - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |Version| Traffic Class | Flow Label | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Payload Length | Next Header | Hop Limit | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * | Source IP Address | - * | | - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * | Destination IP Address | - * | | - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | IP Options when present ... - * +-+-+-+-+-+-+-+-+-+-+-+-+ ... - * | Data ... - * +-+-+- ... - * - */ - -/* decode IP header */ - const struct pgm_ip* ip = (struct pgm_ip*)skb->data; - switch (ip->ip_v) { - case 4: { - struct sockaddr_in* sin = (struct sockaddr_in*)dst; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = ip->ip_dst.s_addr; - break; - } - - case 6: - pgm_set_error (error, - PGM_ERROR_DOMAIN_PACKET, - PGM_ERROR_AFNOSUPPORT, - _("IPv6 is not supported for raw IP header parsing.")); - return FALSE; - - default: - pgm_set_error (error, - PGM_ERROR_DOMAIN_PACKET, - PGM_ERROR_AFNOSUPPORT, - _("IP header reports an invalid version %d."), - ip->ip_v); - return FALSE; - } - - const size_t ip_header_length = ip->ip_hl * 4; /* IP header length in 32bit octets */ - if (PGM_UNLIKELY(ip_header_length < sizeof(struct pgm_ip))) - { - pgm_set_error (error, - PGM_ERROR_DOMAIN_PACKET, - PGM_ERROR_BOUNDS, - _("IP header reports an invalid header length %zu bytes."), - ip_header_length); - return FALSE; - } - -#ifndef CONFIG_HOST_ORDER_IP_LEN - size_t packet_length = ntohs (ip->ip_len); /* total packet length */ -#else - size_t packet_length = ip->ip_len; /* total packet length */ -#endif - - -/* ip_len can equal packet_length - ip_header_length in FreeBSD/NetBSD - * Stevens/Fenner/Rudolph, Unix Network Programming Vol.1, p.739 - * - * RFC3828 allows partial packets such that len < packet_length with UDP lite - */ - if (skb->len == packet_length + ip_header_length) { - packet_length += ip_header_length; - } - - if (PGM_UNLIKELY(skb->len < packet_length)) { /* redundant: often handled in kernel */ - pgm_set_error (error, - PGM_ERROR_DOMAIN_PACKET, - PGM_ERROR_BOUNDS, - _("IP packet received at %" PRIu16 " bytes whilst IP header reports %zu bytes."), - skb->len, packet_length); - return FALSE; - } - -/* packets that fail checksum will generally not be passed upstream except with rfc3828 - */ -#if PGM_CHECK_IN_CKSUM - const uint16_t sum = in_cksum (data, packet_length, 0); - if (PGM_UNLIKELY(0 != sum)) { - const uint16_t ip_sum = ntohs (ip->ip_sum); - pgm_set_error (error, - PGM_ERROR_DOMAIN_PACKET, - PGM_ERROR_CKSUM, - _("IP packet checksum mismatch, reported 0x%x whilst calculated 0x%x."), - ip_sum, sum); - return FALSE; - } -#endif - -/* fragmentation offset, bit 0: 0, bit 1: do-not-fragment, bit 2: more-fragments */ -#ifndef CONFIG_HOST_ORDER_IP_OFF - const uint16_t offset = ntohs (ip->ip_off); -#else - const uint16_t offset = ip->ip_off; -#endif - if (PGM_UNLIKELY((offset & 0x1fff) != 0)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_PACKET, - PGM_ERROR_PROTO, - _("IP header reports packet fragmentation, offset %u."), - offset & 0x1fff); - return FALSE; - } - -/* PGM payload, header looks as follows: - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source Port | Destination Port | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Options | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Global Source ID ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ... Global Source ID | TSDU Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type specific data ... - * +-+-+-+-+-+-+-+-+-+- ... - */ - - skb->pgm_header = (void*)( (char*)skb->data + ip_header_length ); - -/* advance DATA pointer to PGM packet */ - skb->data = skb->pgm_header; - skb->len -= ip_header_length; - return pgm_parse (skb, error); -} - -bool -pgm_parse_udp_encap ( - struct pgm_sk_buff_t* restrict skb, /* will be modified */ - pgm_error_t** restrict error - ) -{ - pgm_assert (NULL != skb); - - if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_header))) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_PACKET, - PGM_ERROR_BOUNDS, - _("UDP payload too small for PGM packet at %" PRIu16 " bytes, expecting at least %zu bytes."), - skb->len, sizeof(struct pgm_header)); - return FALSE; - } - -/* DATA payload is PGM packet, no headers */ - skb->pgm_header = skb->data; - return pgm_parse (skb, error); -} - -/* will modify packet contents to calculate and check PGM checksum - */ -static -bool -pgm_parse ( - struct pgm_sk_buff_t* const restrict skb, /* will be modified to calculate checksum */ - pgm_error_t** restrict error - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - -/* pgm_checksum == 0 means no transmitted checksum */ - if (skb->pgm_header->pgm_checksum) - { - const uint16_t sum = skb->pgm_header->pgm_checksum; - skb->pgm_header->pgm_checksum = 0; - const uint16_t pgm_sum = pgm_csum_fold (pgm_csum_partial ((const char*)skb->pgm_header, skb->len, 0)); - skb->pgm_header->pgm_checksum = sum; - if (PGM_UNLIKELY(pgm_sum != sum)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_PACKET, - PGM_ERROR_CKSUM, - _("PGM packet checksum mismatch, reported 0x%x whilst calculated 0x%x."), - pgm_sum, sum); - return FALSE; - } - } else { - if (PGM_ODATA == skb->pgm_header->pgm_type || - PGM_RDATA == skb->pgm_header->pgm_type) - { - pgm_set_error (error, - PGM_ERROR_DOMAIN_PACKET, - PGM_ERROR_PROTO, - _("PGM checksum missing whilst mandatory for %cDATA packets."), - PGM_ODATA == skb->pgm_header->pgm_type ? 'O' : 'R'); - return FALSE; - } - pgm_debug ("No PGM checksum :O"); - } - -/* copy packets source transport identifier */ - memcpy (&skb->tsi.gsi, skb->pgm_header->pgm_gsi, sizeof(pgm_gsi_t)); - skb->tsi.sport = skb->pgm_header->pgm_sport; - return TRUE; -} - -/* 8.1. Source Path Messages (SPM) - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | SPM's Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Trailing Edge Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Leading Edge Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Path NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * NLA = Network Layer Address - * NLA AFI = NLA Address Family Indicator: rfc 1700 (ADDRESS FAMILY NUMBERS) - * => Path NLA = IP address of last network element - */ - -#define PGM_MIN_SPM_SIZE ( sizeof(struct pgm_spm) ) - -bool -pgm_verify_spm ( - const struct pgm_sk_buff_t* const skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - - const struct pgm_spm* spm = (const struct pgm_spm*)skb->data; - switch (ntohs (spm->spm_nla_afi)) { -/* truncated packet */ - case AFI_IP6: - if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_spm6))) - return FALSE; - break; - case AFI_IP: - if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_spm))) - return FALSE; - break; - - default: - return FALSE; - } - - return TRUE; -} - -/* 14.7.1. Poll Request - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLL's Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLL's Round | POLL's Sub-type | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Path NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | POLL's Back-off Interval | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Random String | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Matching Bit-Mask | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * Sent to ODATA multicast group with IP Router Alert option. - */ - -#define PGM_MIN_POLL_SIZE ( sizeof(struct pgm_poll) ) - -bool -pgm_verify_poll ( - const struct pgm_sk_buff_t* const skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - - const struct pgm_poll* poll4 = (const struct pgm_poll*)skb->data; - switch (ntohs (poll4->poll_nla_afi)) { -/* truncated packet */ - case AFI_IP6: - if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_poll6))) - return FALSE; - break; - case AFI_IP: - if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_poll))) - return FALSE; - break; - - default: - return FALSE; - } - - return TRUE; -} - -/* 14.7.2. Poll Response - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLR's Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLR's Round | reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -bool -pgm_verify_polr ( - const struct pgm_sk_buff_t* const skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - -/* truncated packet */ - if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_polr))) - return FALSE; - return TRUE; -} - -/* 8.2. Data Packet - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Data Packet Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Trailing Edge Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Data ... - * +-+-+- ... - */ - -/* no verification api */ - -/* 8.3. NAK - * - * Technically the AFI of the source and multicast group can be different - * but that would be very wibbly wobbly. One example is using a local DLR - * with a IPv4 address to reduce NAK cost for recovery on wide IPv6 - * distribution. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Requested Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Multicast Group NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | Option Extensions when present ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... - */ - -#define PGM_MIN_NAK_SIZE ( sizeof(struct pgm_nak) ) - -bool -pgm_verify_nak ( - const struct pgm_sk_buff_t* const skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - - pgm_debug ("pgm_verify_nak (skb:%p)", (const void*)skb); - -/* truncated packet */ - if (PGM_UNLIKELY(skb->len < PGM_MIN_NAK_SIZE)) - return FALSE; - - const struct pgm_nak* nak = (struct pgm_nak*)skb->data; - const uint16_t nak_src_nla_afi = ntohs (nak->nak_src_nla_afi); - uint16_t nak_grp_nla_afi = 0; - -/* check source NLA: unicast address of the ODATA sender */ - switch (nak_src_nla_afi) { - case AFI_IP: - nak_grp_nla_afi = ntohs (nak->nak_grp_nla_afi); - break; - - case AFI_IP6: - nak_grp_nla_afi = ntohs (((const struct pgm_nak6*)nak)->nak6_grp_nla_afi); - break; - - default: - return FALSE; - } - -/* check multicast group NLA */ - switch (nak_grp_nla_afi) { - case AFI_IP6: - switch (nak_src_nla_afi) { -/* IPv4 + IPv6 NLA */ - case AFI_IP: - if (PGM_UNLIKELY(skb->len < ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) ))) - return FALSE; - break; - -/* IPv6 + IPv6 NLA */ - case AFI_IP6: - if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_nak6))) - return FALSE; - break; - } - - case AFI_IP: - break; - - default: - return FALSE; - } - - return TRUE; -} - -/* 8.3. N-NAK - */ - -bool -pgm_verify_nnak ( - const struct pgm_sk_buff_t* const skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - - return pgm_verify_nak (skb); -} - -/* 8.3. NCF - */ - -bool -pgm_verify_ncf ( - const struct pgm_sk_buff_t* const skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - - return pgm_verify_nak (skb); -} - -/* 13.6. SPM Request - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... - */ - -bool -pgm_verify_spmr ( - PGM_GNUC_UNUSED const struct pgm_sk_buff_t* skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - - return TRUE; -} - -/* PGMCC: ACK - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | RX_MAX | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Received Packet Bitmap | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... - */ - -#define PGM_MIN_ACK_SIZE ( sizeof(struct pgm_ack) ) - -bool -pgm_verify_ack ( - PGM_GNUC_UNUSED const struct pgm_sk_buff_t* skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - - return TRUE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/packet_parse_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/packet_parse_unittest.c deleted file mode 100644 index 94b06d2..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/packet_parse_unittest.c +++ /dev/null @@ -1,382 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for PGM packet handling. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - - -/* mock state */ - -#define PACKET_DEBUG -#include "packet_parse.c" - - -static -struct pgm_sk_buff_t* -generate_raw_pgm (void) -{ - const char source[] = "i am not a string"; - const guint source_len = sizeof(source); - struct pgm_sk_buff_t* skb; - GError* err = NULL; - - skb = pgm_alloc_skb (1500); - skb->sock = (pgm_sock_t*)0x1; - skb->tstamp = 0x1; - skb->data = skb->head; - skb->len = sizeof(struct pgm_ip) + sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len; - skb->tail = (guint8*)skb->data + skb->len; - -/* add IP header */ - struct pgm_ip* iphdr = skb->data; - iphdr->ip_hl = sizeof(struct pgm_ip) / 4; - iphdr->ip_v = 4; - iphdr->ip_tos = 0; - iphdr->ip_len = g_htons (skb->len); - iphdr->ip_id = 0; - iphdr->ip_off = 0; - iphdr->ip_ttl = 16; - iphdr->ip_p = IPPROTO_PGM; - iphdr->ip_sum = 0; - iphdr->ip_src.s_addr = inet_addr ("127.0.0.1"); - iphdr->ip_dst.s_addr = inet_addr ("127.0.0.2"); - -/* add PGM header */ - struct pgm_header* pgmhdr = (gpointer)(iphdr + 1); - pgmhdr->pgm_sport = g_htons ((guint16)1000); - pgmhdr->pgm_dport = g_htons ((guint16)7500); - pgmhdr->pgm_type = PGM_ODATA; - pgmhdr->pgm_options = 0; - pgmhdr->pgm_gsi[0] = 1; - pgmhdr->pgm_gsi[1] = 2; - pgmhdr->pgm_gsi[2] = 3; - pgmhdr->pgm_gsi[3] = 4; - pgmhdr->pgm_gsi[4] = 5; - pgmhdr->pgm_gsi[5] = 6; - pgmhdr->pgm_tsdu_length = g_htons (source_len); - -/* add ODATA header */ - struct pgm_data* datahdr = (gpointer)(pgmhdr + 1); - datahdr->data_sqn = g_htonl ((guint32)0); - datahdr->data_trail = g_htonl ((guint32)-1); - -/* add payload */ - gpointer data = (gpointer)(datahdr + 1); - memcpy (data, source, source_len); - -/* finally PGM checksum */ - pgmhdr->pgm_checksum = 0; - pgmhdr->pgm_checksum = pgm_csum_fold (pgm_csum_partial (pgmhdr, sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len, 0)); - -/* and IP checksum */ - iphdr->ip_sum = pgm_inet_checksum (skb->head, skb->len, 0); - - return skb; -} - -static -struct pgm_sk_buff_t* -generate_udp_encap_pgm (void) -{ - const char source[] = "i am not a string"; - const guint source_len = sizeof(source); - struct pgm_sk_buff_t* skb; - GError* err = NULL; - - skb = pgm_alloc_skb (1500); - skb->sock = (pgm_sock_t*)0x1; - skb->tstamp = 0x1; - skb->data = skb->head; - skb->len = sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len; - skb->tail = (guint8*)skb->data + skb->len; - -/* add PGM header */ - struct pgm_header* pgmhdr = skb->head; - pgmhdr->pgm_sport = g_htons ((guint16)1000); - pgmhdr->pgm_dport = g_htons ((guint16)7500); - pgmhdr->pgm_type = PGM_ODATA; - pgmhdr->pgm_options = 0; - pgmhdr->pgm_gsi[0] = 1; - pgmhdr->pgm_gsi[1] = 2; - pgmhdr->pgm_gsi[2] = 3; - pgmhdr->pgm_gsi[3] = 4; - pgmhdr->pgm_gsi[4] = 5; - pgmhdr->pgm_gsi[5] = 6; - pgmhdr->pgm_tsdu_length = g_htons (source_len); - -/* add ODATA header */ - struct pgm_data* datahdr = (gpointer)(pgmhdr + 1); - datahdr->data_sqn = g_htonl ((guint32)0); - datahdr->data_trail = g_htonl ((guint32)-1); - -/* add payload */ - gpointer data = (gpointer)(datahdr + 1); - memcpy (data, source, source_len); - -/* finally PGM checksum */ - pgmhdr->pgm_checksum = 0; - pgmhdr->pgm_checksum = pgm_csum_fold (pgm_csum_partial (pgmhdr, sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len, 0)); - - return skb; -} - -/* mock functions for external references */ - -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return 0; -} - - -/* target: - * bool - * pgm_parse_raw ( - * struct pgm_sk_buff_t* const skb, - * struct sockaddr* const addr, - * pgm_error_t** error - * ) - */ - -START_TEST (test_parse_raw_pass_001) -{ - struct sockaddr_storage addr; - pgm_error_t* err = NULL; - struct pgm_sk_buff_t* skb = generate_raw_pgm (); - gboolean success = pgm_parse_raw (skb, (struct sockaddr*)&addr, &err); - if (!success && err) { - g_error ("Parsing raw packet: %s", err->message); - } - fail_unless (TRUE == success, "parse_raw failed"); - char saddr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); - g_message ("Decoded destination NLA: %s", saddr); -} -END_TEST - -START_TEST (test_parse_raw_fail_001) -{ - struct sockaddr_storage addr; - pgm_error_t* err = NULL; - pgm_parse_raw (NULL, (struct sockaddr*)&addr, &err); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_parse_udp_encap ( - * struct pgm_sk_buff_t* const skb, - * pgm_error_t** error - * ) - */ - -START_TEST (test_parse_udp_encap_pass_001) -{ - pgm_error_t* err = NULL; - struct pgm_sk_buff_t* skb = generate_udp_encap_pgm (); - gboolean success = pgm_parse_udp_encap (skb, &err); - if (!success && err) { - g_error ("Parsing UDP encapsulated packet: %s", err->message); - } - fail_unless (TRUE == success, "parse_udp_encap failed"); -} -END_TEST - -START_TEST (test_parse_udp_encap_fail_001) -{ - pgm_error_t* err = NULL; - pgm_parse_udp_encap (NULL, &err); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_verify_spm ( - * struct pgm_sk_buff_t* const skb - * ) - */ - -START_TEST (test_verify_spm_pass_001) -{ -} -END_TEST - -START_TEST (test_verify_spm_fail_001) -{ - pgm_verify_spm (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_verify_spmr ( - * struct pgm_sk_buff_t* const skb - * ) - */ - -START_TEST (test_verify_spmr_pass_001) -{ -} -END_TEST - -START_TEST (test_verify_spmr_fail_001) -{ - pgm_verify_spmr (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_verify_nak ( - * struct pgm_sk_buff_t* const skb - * ) - */ - -START_TEST (test_verify_nak_pass_001) -{ -} -END_TEST - -START_TEST (test_verify_nak_fail_001) -{ - pgm_verify_nak (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_verify_nnak ( - * struct pgm_sk_buff_t* const skb - * ) - */ - -START_TEST (test_verify_nnak_pass_001) -{ -} -END_TEST - -START_TEST (test_verify_nnak_fail_001) -{ - pgm_verify_nnak (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_verify_ncf ( - * struct pgm_sk_buff_t* const skb - * ) - */ - -START_TEST (test_verify_ncf_pass_001) -{ -} -END_TEST - -START_TEST (test_verify_ncf_fail_001) -{ - pgm_verify_ncf (NULL); - fail ("reached"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_parse_raw = tcase_create ("parse-raw"); - suite_add_tcase (s, tc_parse_raw); - tcase_add_test (tc_parse_raw, test_parse_raw_pass_001); - tcase_add_test_raise_signal (tc_parse_raw, test_parse_raw_fail_001, SIGABRT); - - TCase* tc_parse_udp_encap = tcase_create ("parse-udp-encap"); - suite_add_tcase (s, tc_parse_udp_encap); - tcase_add_test (tc_parse_udp_encap, test_parse_udp_encap_pass_001); - tcase_add_test_raise_signal (tc_parse_udp_encap, test_parse_udp_encap_fail_001, SIGABRT); - - TCase* tc_verify_spm = tcase_create ("verify-spm"); - suite_add_tcase (s, tc_verify_spm); - tcase_add_test (tc_verify_spm, test_verify_spm_pass_001); - tcase_add_test_raise_signal (tc_verify_spm, test_verify_spm_fail_001, SIGABRT); - - TCase* tc_verify_spmr = tcase_create ("verify-spmr"); - suite_add_tcase (s, tc_verify_spmr); - tcase_add_test (tc_verify_spmr, test_verify_spmr_pass_001); - tcase_add_test_raise_signal (tc_verify_spmr, test_verify_spmr_fail_001, SIGABRT); - - TCase* tc_verify_nak = tcase_create ("verify-nak"); - suite_add_tcase (s, tc_verify_nak); - tcase_add_test (tc_verify_nak, test_verify_nak_pass_001); - tcase_add_test_raise_signal (tc_verify_nak, test_verify_nak_fail_001, SIGABRT); - - TCase* tc_verify_nnak = tcase_create ("verify-nnak"); - suite_add_tcase (s, tc_verify_nnak); - tcase_add_test (tc_verify_nnak, test_verify_nnak_pass_001); - tcase_add_test_raise_signal (tc_verify_nnak, test_verify_nnak_fail_001, SIGABRT); - - TCase* tc_verify_ncf = tcase_create ("verify-ncf"); - suite_add_tcase (s, tc_verify_ncf); - tcase_add_test (tc_verify_ncf, test_verify_ncf_pass_001); - tcase_add_test_raise_signal (tc_verify_ncf, test_verify_ncf_fail_001, SIGABRT); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/packet_test.c b/3rdparty/openpgm-svn-r1085/pgm/packet_test.c deleted file mode 100644 index 6ac469f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/packet_test.c +++ /dev/null @@ -1,1158 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM packet formats, RFC 3208. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define __STDC_FORMAT_MACROS -#include -#include -#include -#ifndef _WIN32 -# include -# include -# include -# include -#endif -#include -#include -#include - - -//#define PACKET_DEBUG - - -static bool pgm_print_spm (const struct pgm_header* const, const void*, const size_t); -static bool pgm_print_poll (const struct pgm_header* const, const void*, const size_t); -static bool pgm_print_polr (const struct pgm_header* const, const void*, const size_t); -static bool pgm_print_odata (const struct pgm_header* const, const void*, const size_t); -static bool pgm_print_rdata (const struct pgm_header* const, const void*, const size_t); -static bool pgm_print_nak (const struct pgm_header* const, const void*, const size_t); -static bool pgm_print_nnak (const struct pgm_header* const, const void*, const size_t); -static bool pgm_print_ncf (const struct pgm_header* const, const void*, const size_t); -static bool pgm_print_spmr (const struct pgm_header* const, const void*, const size_t); -static bool pgm_print_ack (const struct pgm_header* const, const void*, const size_t); -static ssize_t pgm_print_options (const void*, size_t); - -bool -pgm_print_packet ( - const void* data, - size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != data); - pgm_assert (len > 0); - -/* minimum size should be IP header plus PGM header */ - if (len < (sizeof(struct pgm_ip) + sizeof(struct pgm_header))) - { - printf ("Packet size too small: %zu bytes, expecting at least %zu bytes.\n", - len, sizeof(struct pgm_ip) + sizeof(struct pgm_header)); - return FALSE; - } - -/* decode IP header */ - const struct pgm_ip* ip = (const struct pgm_ip*)data; - if (ip->ip_v != 4) /* IP version, 4 or 6 */ - { - puts ("not IP4 packet :/"); /* v6 not currently handled */ - return FALSE; - } - printf ("IP "); - - const size_t ip_header_length = ip->ip_hl * 4; /* IP header length in 32bit octets */ - if (ip_header_length < sizeof(struct pgm_ip)) - { - puts ("bad IP header length :("); - return FALSE; - } - - size_t packet_length = ntohs(ip->ip_len); /* total packet length */ - -/* ip_len can equal packet_length - ip_header_length in FreeBSD/NetBSD - * Stevens/Fenner/Rudolph, Unix Network Programming Vol.1, p.739 - * - * RFC3828 allows partial packets such that len < packet_length with UDP lite - */ - if (len == packet_length + ip_header_length) { - packet_length += ip_header_length; - } - - if (len < packet_length) { /* redundant: often handled in kernel */ - puts ("truncated IP packet"); - return FALSE; - } - -/* TCP Segmentation Offload (TSO) might have zero length here */ - if (packet_length < ip_header_length) { - puts ("bad length :("); - return FALSE; - } - - const uint16_t offset = ntohs(ip->ip_off); - -/* 3 bits routing priority, 4 bits type of service: delay, throughput, reliability, cost */ - printf ("(tos 0x%x", (int)ip->ip_tos); - switch (ip->ip_tos & 0x3) - { - case 1: printf (",ECT(1)"); break; - case 2: printf (",ECT(0)"); break; - case 3: printf (",CE"); break; - default: break; - } - -/* time to live */ - if (ip->ip_ttl >= 1) printf (", ttl %u", ip->ip_ttl); - -/* fragmentation */ -#define IP_RDF 0x8000 -#define IP_DF 0x4000 -#define IP_MF 0x2000 -#define IP_OFFMASK 0x1fff - - printf (", id %u, offset %u, flags [%s%s]", - ntohs(ip->ip_id), - (offset & 0x1fff) * 8, - ((offset & IP_DF) ? "DF" : ""), - ((offset & IP_MF) ? "+" : "")); - printf (", length %zu", packet_length); - -/* IP options */ - if ((ip_header_length - sizeof(struct pgm_ip)) > 0) { - printf (", options ("); - pgm_ipopt_print((const void*)(ip + 1), ip_header_length - sizeof(struct pgm_ip)); - printf (" )"); - } - -/* packets that fail checksum will generally not be passed upstream except with rfc3828 - */ - const uint16_t ip_sum = pgm_inet_checksum(data, packet_length, 0); - if (ip_sum != 0) { - const uint16_t encoded_ip_sum = ntohs(ip->ip_sum); - printf (", bad cksum! %i", encoded_ip_sum); - } - - printf (") "); - -/* fragmentation offset, bit 0: 0, bit 1: do-not-fragment, bit 2: more-fragments */ - if ((offset & 0x1fff) != 0) { - puts ("fragmented packet :/"); - return FALSE; - } - -/* PGM payload, header looks as follows: - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source Port | Destination Port | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Options | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Global Source ID ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ... Global Source ID | TSDU Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type specific data ... - * +-+-+-+-+-+-+-+-+-+- ... - */ - const struct pgm_header* pgm_header = (const struct pgm_header*)((const char*)data + ip_header_length); - const size_t pgm_length = packet_length - ip_header_length; - - if (pgm_length < sizeof(pgm_header)) { - puts ("bad packet size :("); - return FALSE; - } - - printf ("%s.%s > ", - pgm_gethostbyaddr((const struct in_addr*)&ip->ip_src), pgm_udpport_string(pgm_header->pgm_sport)); - printf ("%s.%s: PGM\n", - pgm_gethostbyaddr((const struct in_addr*)&ip->ip_dst), pgm_udpport_string(pgm_header->pgm_dport)); - - printf ("type: %s [%i] (version=%i, reserved=%i)\n" - "options: extensions=%s, network-significant=%s, parity packet=%s (variable size=%s)\n" - "global source id: %i.%i.%i.%i.%i.%i\n" - "tsdu length: %i\n", - - /* packet type */ /* packet version */ /* reserved = 0x0 */ - pgm_type_string(pgm_header->pgm_type & 0xf), - (pgm_header->pgm_type & 0xf), ((pgm_header->pgm_type & 0xc0) >> 6), ((pgm_header->pgm_type & 0x30) >> 4), - -/* bit 0 set => one or more option extensions are present */ - ((pgm_header->pgm_options & (0x1 << 7)) ? "true" : "false"), -/* bit 1 set => one or more options are network-significant */ - ((pgm_header->pgm_options & (0x1 << 6)) ? "true" : "false"), -/* bit 7 set => parity packet (OPT_PARITY) */ - ((pgm_header->pgm_options & (0x1 << 0)) ? "true" : "false"), -/* bit 6 set => parity packet for variable packet sizes (OPT_VAR_PKTLEN) */ - ((pgm_header->pgm_options & (0x1 << 1)) ? "true" : "false"), - - pgm_header->pgm_gsi[0], pgm_header->pgm_gsi[1], pgm_header->pgm_gsi[2], pgm_header->pgm_gsi[3], pgm_header->pgm_gsi[4], pgm_header->pgm_gsi[5], - ntohs(pgm_header->pgm_tsdu_length)); - - if (pgm_header->pgm_checksum) - { -#if 0 - const uint16_t encoded_pgm_sum = pgm_header->pgm_checksum; -/* requires modification of data buffer */ - pgm_header->pgm_checksum = 0; - const uint16_t pgm_sum = pgm_csum_fold (pgm_csum_partial((const char*)pgm_header, pgm_length, 0)); - if (pgm_sum != encoded_pgm_sum) { - printf ("PGM checksum incorrect, packet %x calculated %x :(\n", encoded_pgm_sum, pgm_sum); - return FALSE; - } -#endif - } else { - puts ("No PGM checksum :O"); - } - -/* now decode PGM packet types */ - const void* pgm_data = pgm_header + 1; - const size_t pgm_data_length = pgm_length - sizeof(pgm_header); /* can equal zero for SPMR's */ - - bool err = FALSE; - switch (pgm_header->pgm_type) { - case PGM_SPM: err = pgm_print_spm (pgm_header, pgm_data, pgm_data_length); break; - case PGM_POLL: err = pgm_print_poll (pgm_header, pgm_data, pgm_data_length); break; - case PGM_POLR: err = pgm_print_polr (pgm_header, pgm_data, pgm_data_length); break; - case PGM_ODATA: err = pgm_print_odata (pgm_header, pgm_data, pgm_data_length); break; - case PGM_RDATA: err = pgm_print_rdata (pgm_header, pgm_data, pgm_data_length); break; - case PGM_NAK: err = pgm_print_nak (pgm_header, pgm_data, pgm_data_length); break; - case PGM_NNAK: err = pgm_print_nnak (pgm_header, pgm_data, pgm_data_length); break; - case PGM_NCF: err = pgm_print_ncf (pgm_header, pgm_data, pgm_data_length); break; - case PGM_SPMR: err = pgm_print_spmr (pgm_header, pgm_data, pgm_data_length); break; - case PGM_ACK: err = pgm_print_ack (pgm_header, pgm_data, pgm_data_length); break; - default: puts ("unknown packet type :("); break; - } - - return err; -} - -/* 8.1. Source Path Messages (SPM) - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | SPM's Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Trailing Edge Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Leading Edge Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Path NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * NLA = Network Layer Address - * NLA AFI = NLA Address Family Indicator: rfc 1700 (ADDRESS FAMILY NUMBERS) - * => Path NLA = IP address of last network element - */ - -#define PGM_MIN_SPM_SIZE ( sizeof(struct pgm_spm) ) - -static -bool -pgm_print_spm ( - const struct pgm_header* const header, - const void* data, - const size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != header); - pgm_assert (NULL != data); - pgm_assert (len > 0); - - printf ("SPM: "); - - if (len < PGM_MIN_SPM_SIZE) { - puts ("packet truncated :("); - return FALSE; - } - - const struct pgm_spm * spm = (const struct pgm_spm *)data; - const struct pgm_spm6* spm6 = (const struct pgm_spm6*)data; - const uint16_t spm_nla_afi = ntohs (spm->spm_nla_afi); - - printf ("sqn %" PRIu32 " trail %" PRIu32 "lu lead %" PRIu32 "lu nla-afi %u ", - ntohl(spm->spm_sqn), - ntohl(spm->spm_trail), - ntohl(spm->spm_lead), - spm_nla_afi); /* address family indicator */ - - char s[INET6_ADDRSTRLEN]; - const void* pgm_opt; - size_t pgm_opt_len; - switch (spm_nla_afi) { - case AFI_IP: - pgm_inet_ntop (AF_INET, &spm->spm_nla, s, sizeof(s)); - pgm_opt = (const uint8_t*)data + sizeof(struct pgm_spm); - pgm_opt_len = len - sizeof(struct pgm_spm); - break; - - case AFI_IP6: - if (len < sizeof (struct pgm_spm6)) { - puts ("packet truncated :("); - return FALSE; - } - - pgm_inet_ntop (AF_INET6, &spm6->spm6_nla, s, sizeof(s)); - pgm_opt = (const uint8_t*)data + sizeof(struct pgm_spm6); - pgm_opt_len = len - sizeof(struct pgm_spm6); - break; - - default: - printf ("unsupported afi"); - return FALSE; - } - - printf ("%s", s); - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT && - pgm_print_options (pgm_opt, pgm_opt_len) < 0 ) - { - return FALSE; - } - - printf ("\n"); - return TRUE; -} - -/* 14.7.1. Poll Request - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLL's Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLL's Round | POLL's Sub-type | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Path NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | POLL's Back-off Interval | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Random String | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Matching Bit-Mask | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * Sent to ODATA multicast group with IP Router Alert option. - */ - -#define PGM_MIN_POLL_SIZE ( sizeof(struct pgm_poll) ) - -static -bool -pgm_print_poll ( - const struct pgm_header* const header, - const void* data, - const size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != header); - pgm_assert (NULL != data); - pgm_assert (len > 0); - - printf ("POLL: "); - - if (len < PGM_MIN_POLL_SIZE) { - puts ("packet truncated :("); - return FALSE; - } - - const struct pgm_poll * poll4 = (const struct pgm_poll *)data; - const struct pgm_poll6* poll6 = (const struct pgm_poll6*)data; - const uint16_t poll_nla_afi = ntohs (poll4->poll_nla_afi); - - printf ("sqn %" PRIu32 " round %u sub-type %u nla-afi %u ", - ntohl(poll4->poll_sqn), - ntohs(poll4->poll_round), - ntohs(poll4->poll_s_type), - poll_nla_afi); /* address family indicator */ - - char s[INET6_ADDRSTRLEN]; - const void* pgm_opt; - size_t pgm_opt_len; - switch (poll_nla_afi) { - case AFI_IP: - pgm_inet_ntop (AF_INET, &poll4->poll_nla, s, sizeof(s)); - pgm_opt = (const uint8_t*)data + sizeof(struct pgm_poll); - pgm_opt_len = len - sizeof(struct pgm_poll); - printf ("%s", s); - -/* back-off interval in microseconds */ - printf (" bo_ivl %u", poll4->poll_bo_ivl); - -/* random string */ - printf (" rand [%c%c%c%c]", - isprint (poll4->poll_rand[0]) ? poll4->poll_rand[0] : '.', - isprint (poll4->poll_rand[1]) ? poll4->poll_rand[1] : '.', - isprint (poll4->poll_rand[2]) ? poll4->poll_rand[2] : '.', - isprint (poll4->poll_rand[3]) ? poll4->poll_rand[3] : '.' ); - -/* matching bit-mask */ - printf (" mask 0x%x", poll4->poll_mask); - break; - - case AFI_IP6: - if (len < sizeof (struct pgm_poll6)) { - puts ("packet truncated :("); - return FALSE; - } - - pgm_inet_ntop (AF_INET6, &poll6->poll6_nla, s, sizeof (s)); - pgm_opt = (const uint8_t*)data + sizeof(struct pgm_poll6); - pgm_opt_len = len - sizeof(struct pgm_poll6); - printf ("%s", s); - -/* back-off interval in microseconds */ - printf (" bo_ivl %u", poll6->poll6_bo_ivl); - -/* random string */ - printf (" rand [%c%c%c%c]", - isprint (poll6->poll6_rand[0]) ? poll6->poll6_rand[0] : '.', - isprint (poll6->poll6_rand[1]) ? poll6->poll6_rand[1] : '.', - isprint (poll6->poll6_rand[2]) ? poll6->poll6_rand[2] : '.', - isprint (poll6->poll6_rand[3]) ? poll6->poll6_rand[3] : '.' ); - -/* matching bit-mask */ - printf (" mask 0x%x", poll6->poll6_mask); - break; - - default: - printf ("unsupported afi"); - return FALSE; - } - - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT && - pgm_print_options (pgm_opt, pgm_opt_len) < 0 ) - { - return FALSE; - } - - printf ("\n"); - return TRUE; -} - -/* 14.7.2. Poll Response - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLR's Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLR's Round | reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -static -bool -pgm_print_polr ( - const struct pgm_header* const header, - const void* data, - const size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != header); - pgm_assert (NULL != data); - pgm_assert (len > 0); - - printf ("POLR: "); - - if (len < sizeof(struct pgm_polr)) { - puts ("packet truncated :("); - return FALSE; - } - - const struct pgm_polr* polr = (const struct pgm_polr*)data; - - printf("sqn %" PRIu32 " round %u", - ntohl(polr->polr_sqn), - ntohs(polr->polr_round)); - - const void* pgm_opt = (const uint8_t*)data + sizeof(struct pgm_polr); - size_t pgm_opt_len = len - sizeof(struct pgm_polr); - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT && - pgm_print_options (pgm_opt, pgm_opt_len) < 0 ) - { - return FALSE; - } - - printf ("\n"); - return TRUE; -} - -/* 8.2. Data Packet - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Data Packet Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Trailing Edge Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Data ... - * +-+-+- ... - */ - -static -bool -pgm_print_odata ( - const struct pgm_header* const header, - const void* data, - const size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != header); - pgm_assert (NULL != data); - pgm_assert (len > 0); - - printf ("ODATA: "); - - if (len < sizeof(struct pgm_data)) { - puts ("packet truncated :("); - return FALSE; - } - - const struct pgm_data* odata = (const struct pgm_data*)data; - - printf ("sqn %" PRIu32 " trail %" PRIu32 " [", - ntohl(odata->data_sqn), - ntohl(odata->data_trail)); - -/* option extensions */ - const void* pgm_opt = (const uint8_t*)data + sizeof(struct pgm_data); - size_t pgm_opt_len = len - sizeof(struct pgm_data); - const char* payload = pgm_opt; - - if (header->pgm_options & PGM_OPT_PRESENT) { - const ssize_t opt_len = pgm_print_options (pgm_opt, pgm_opt_len); - if (opt_len < 0) - return FALSE; - payload += opt_len; - } - -/* data */ - const char* end = payload + ntohs (header->pgm_tsdu_length); - while (payload < end) { - if (isprint (*payload)) - putchar (*payload); - else - putchar ('.'); - payload++; - } - - printf ("]\n"); - return TRUE; -} - -/* 8.2. Repair Data - */ - -static -bool -pgm_print_rdata ( - const struct pgm_header* const header, - const void* data, - const size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != header); - pgm_assert (NULL != data); - pgm_assert (len > 0); - - printf ("RDATA: "); - - if (len < sizeof(struct pgm_data)) { - puts ("packet truncated :("); - return FALSE; - } - - const struct pgm_data* rdata = (const struct pgm_data*)data; - - printf ("sqn %" PRIu32 " trail %" PRIu32 " [", - ntohl (rdata->data_sqn), - ntohl (rdata->data_trail)); - -/* option extensions */ - const void* pgm_opt = (const uint8_t*)data + sizeof(struct pgm_data); - size_t pgm_opt_len = len - sizeof(struct pgm_data); - const char* payload = pgm_opt; - - if (header->pgm_options & PGM_OPT_PRESENT) { - const ssize_t opt_len = pgm_print_options (pgm_opt, pgm_opt_len); - if (opt_len < 0) - return FALSE; - payload += opt_len; - } - -/* data */ - const char* end = payload + ntohs (header->pgm_tsdu_length); - while (payload < end) { - if (isprint (*payload)) - putchar (*payload); - else - putchar ('.'); - payload++; - } - - printf ("]\n"); - return TRUE; -} - -/* 8.3. NAK - * - * Technically the AFI of the source and multicast group can be different - * but that would be very wibbly wobbly. One example is using a local DLR - * with a IPv4 address to reduce NAK cost for recovery on wide IPv6 - * distribution. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Requested Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Multicast Group NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | Option Extensions when present ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... - */ - -#define PGM_MIN_NAK_SIZE ( sizeof(struct pgm_nak) ) - -static -bool -pgm_print_nak ( - const struct pgm_header* const header, - const void* data, - const size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != header); - pgm_assert (NULL != data); - pgm_assert (len > 0); - - printf ("NAK: "); - - if (len < PGM_MIN_NAK_SIZE) { - puts ("packet truncated :("); - return FALSE; - } - - const struct pgm_nak * nak = (const struct pgm_nak *)data; - const struct pgm_nak6* nak6 = (const struct pgm_nak6*)data; - const uint16_t nak_src_nla_afi = ntohs (nak->nak_src_nla_afi); - - printf ("sqn %" PRIu32 " src ", - ntohl(nak->nak_sqn)); - - char s[INET6_ADDRSTRLEN]; - const void* pgm_opt; - size_t pgm_opt_len; - -/* source nla */ - switch (nak_src_nla_afi) { - case AFI_IP: { - const uint16_t nak_grp_nla_afi = ntohs (nak->nak_grp_nla_afi); - if (nak_src_nla_afi != nak_grp_nla_afi) { - puts ("different source & group afi very wibbly wobbly :("); - return FALSE; - } - - pgm_inet_ntop (AF_INET, &nak->nak_src_nla, s, sizeof(s)); - pgm_opt = (const uint8_t*)data + sizeof(struct pgm_nak); - pgm_opt_len = len - sizeof(struct pgm_nak); - printf ("%s grp ", s); - - pgm_inet_ntop (AF_INET, &nak->nak_grp_nla, s, sizeof(s)); - printf ("%s", s); - break; - } - - case AFI_IP6: { - if (len < sizeof (struct pgm_nak6)) { - puts ("packet truncated :("); - return FALSE; - } - - const uint16_t nak_grp_nla_afi = ntohs (nak6->nak6_grp_nla_afi); - if (nak_src_nla_afi != nak_grp_nla_afi) { - puts ("different source & group afi very wibbly wobbly :("); - return FALSE; - } - - pgm_inet_ntop (AF_INET6, &nak6->nak6_src_nla, s, sizeof(s)); - pgm_opt = (const uint8_t*)data + sizeof(struct pgm_nak6); - pgm_opt_len = len - sizeof(struct pgm_nak6); - printf ("%s grp ", s); - - pgm_inet_ntop (AF_INET6, &nak6->nak6_grp_nla, s, sizeof(s)); - printf ("%s", s); - break; - } - - default: - puts ("unsupported afi"); - return FALSE; - } - - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT && - pgm_print_options (pgm_opt, pgm_opt_len) < 0 ) - { - return FALSE; - } - - printf ("\n"); - return TRUE; -} - -/* 8.3. N-NAK - */ - -static -bool -pgm_print_nnak ( - PGM_GNUC_UNUSED const struct pgm_header* const header, - PGM_GNUC_UNUSED const void* data, - const size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != header); - pgm_assert (NULL != data); - pgm_assert (len > 0); - - printf ("N-NAK: "); - - if (len < sizeof(struct pgm_nak)) { - puts ("packet truncated :("); - return FALSE; - } - -// struct pgm_nak* nnak = (struct pgm_nak*)data; - - return TRUE; -} - -/* 8.3. NCF - */ - -bool -pgm_print_ncf ( - PGM_GNUC_UNUSED const struct pgm_header* const header, - PGM_GNUC_UNUSED const void* data, - const size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != header); - pgm_assert (NULL != data); - pgm_assert (len > 0); - - printf ("NCF: "); - - if (len < sizeof(struct pgm_nak)) { - puts ("packet truncated :("); - return FALSE; - } - -// struct pgm_nak* ncf = (struct pgm_nak*)data; - - return TRUE; -} - -/* 13.6. SPM Request - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... - */ - -static -bool -pgm_print_spmr ( - const struct pgm_header* const header, - const void* data, - const size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != header); - pgm_assert (NULL != data); - pgm_assert (len > 0); - - printf ("SPMR: "); - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT && - pgm_print_options (data, len) < 0 ) - { - return FALSE; - } - - printf ("\n"); - return TRUE; -} - -/* PGMCC: ACK - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | RX_MAX | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Received Packet Bitmap | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... - */ - -static -bool -pgm_print_ack ( - const struct pgm_header* const header, - const void* data, - const size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != header); - pgm_assert (NULL != data); - pgm_assert (len > 0); - - printf ("ACK: "); - - const struct pgm_ack* ack = (const struct pgm_ack*)data; - char bitmap[33]; - - for (unsigned i = 31; i; i--) - bitmap[i] = (ack->ack_bitmap & (1 << i)) ? '1' : '0'; - bitmap[32] = '\0'; - - printf ("rx_max %" PRIu32 " bitmap [%s] ", - ntohl(ack->ack_rx_max), bitmap); - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT && - pgm_print_options (data, len) < 0 ) - { - return FALSE; - } - - printf ("\n"); - return TRUE; -} - - -/* Parse PGM options fields, alters contents of packet. - * - * returns -1 on failure, or total length in octets of the option fields - */ - -static -ssize_t -pgm_print_options ( - const void* data, - size_t len - ) -{ -/* pre-conditions */ - pgm_assert (NULL != data); - pgm_assert (len > 0); - - printf (" OPTIONS:"); - if (len < sizeof(struct pgm_opt_length)) { - puts (" packet truncated :("); - return -1; - } - - const struct pgm_opt_length* opt_len = (const struct pgm_opt_length*)data; - if (opt_len->opt_length != sizeof(struct pgm_opt_length)) { - printf (" bad opt_length length %u\n", (unsigned)opt_len->opt_length); - return -1; - } - - uint16_t opt_total_length = ntohs (opt_len->opt_total_length); - printf (" total len %u ", opt_total_length); - if (opt_total_length < (sizeof(struct pgm_opt_length) + sizeof(struct pgm_opt_header)) || - opt_total_length > len) - { - puts ("bad total length"); - return -1; - } - -/* total length includes opt_length option */ - opt_total_length -= sizeof(struct pgm_opt_length); - const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)(opt_len + 1); - -/* iterate through options (max 16) */ - unsigned count = 16; - while (opt_total_length && count) - { - if (opt_total_length < sizeof(struct pgm_opt_header) || - opt_header->opt_length > opt_total_length) - { - puts ("short on option data :o"); - return -1; - } - - if (opt_header->opt_type & PGM_OPT_END) { - printf ("OPT_END+"); - } - - switch (opt_header->opt_type & PGM_OPT_MASK) { - case PGM_OPT_FRAGMENT: - printf ("OPT_FRAGMENT "); - break; - - case PGM_OPT_NAK_LIST: - printf ("OPT_NAK_LIST "); - break; - - case PGM_OPT_JOIN: - printf ("OPT_JOIN "); - break; - - case PGM_OPT_REDIRECT: - printf ("OPT_REDIRECT "); - break; - - case PGM_OPT_SYN: - printf ("OPT_SYN "); - break; - - case PGM_OPT_FIN: - printf ("OPT_FIN "); - break; - - case PGM_OPT_RST: - printf ("OPT_RST "); - break; - - case PGM_OPT_PARITY_PRM: - printf ("OPT_PARITY_PRM "); - break; - - case PGM_OPT_CURR_TGSIZE: - printf ("OPT_CURR_TGSIZE "); - break; - - case PGM_OPT_CR: - printf ("OPT_CR "); - break; - - case PGM_OPT_CRQST: - printf ("OPT_CRQST "); - break; - - case PGM_OPT_PGMCC_DATA: - printf ("OPT_PGMCC_DATA "); - break; - - case PGM_OPT_PGMCC_FEEDBACK: - printf ("OPT_PGMCC_FEEDBACK "); - break; - - case PGM_OPT_NAK_BO_IVL: - printf ("OPT_NAK_BO_IVL "); - break; - - case PGM_OPT_NAK_BO_RNG: - printf ("OPT_NAK_BO_RNG "); - break; - - case PGM_OPT_NBR_UNREACH: - printf ("OPT_NBR_UNREACH "); - break; - - case PGM_OPT_PATH_NLA: - printf ("OPT_PATH_NLA "); - break; - - default: - printf ("OPT-%u{%u} ", opt_header->opt_type & PGM_OPT_MASK, opt_header->opt_length); - break; - } - - opt_total_length -= opt_header->opt_length; - opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); - - count--; - } - - if (!count) { - puts ("too many options found"); - return -1; - } - - return ((const uint8_t*)opt_header - (const uint8_t*)data); -} - -const char* -pgm_type_string ( - uint8_t type - ) -{ - const char* c; - - switch (type) { - case PGM_SPM: c = "PGM_SPM"; break; - case PGM_POLL: c = "PGM_POLL"; break; - case PGM_POLR: c = "PGM_POLR"; break; - case PGM_ODATA: c = "PGM_ODATA"; break; - case PGM_RDATA: c = "PGM_RDATA"; break; - case PGM_NAK: c = "PGM_NAK"; break; - case PGM_NNAK: c = "PGM_NNAK"; break; - case PGM_NCF: c = "PGM_NCF"; break; - case PGM_SPMR: c = "PGM_SPMR"; break; - case PGM_ACK: c = "PGM_ACK"; break; - default: c = "(unknown)"; break; - } - - return c; -} - -const char* -pgm_udpport_string ( - uint16_t port - ) -{ - static pgm_hashtable_t *services = NULL; - - if (!services) { - services = pgm_hashtable_new (pgm_int_hash, pgm_int_equal); - } - - const int hash_key = port; - void* service_string = pgm_hashtable_lookup (services, &hash_key); - if (service_string != NULL) { - return service_string; - } - - struct servent* se = getservbyport (port, "udp"); - if (se == NULL) { - char buf[sizeof("00000")]; - snprintf(buf, sizeof(buf), "%u", ntohs(port)); - service_string = pgm_strdup(buf); - } else { - service_string = pgm_strdup(se->s_name); - } - pgm_hashtable_insert (services, &hash_key, service_string); - return service_string; -} - -const char* -pgm_gethostbyaddr ( - const struct in_addr* ap - ) -{ - static pgm_hashtable_t *hosts = NULL; - - if (!hosts) { - hosts = pgm_hashtable_new (pgm_str_hash, pgm_int_equal); - } - - const int hash_key = (int)ap->s_addr; - void* host_string = pgm_hashtable_lookup (hosts, &hash_key); - if (host_string != NULL) { - return host_string; - } - - struct hostent* he = gethostbyaddr((const char*)ap, sizeof(struct in_addr), AF_INET); - if (he == NULL) { - struct in_addr in; - memcpy (&in, ap, sizeof(in)); - host_string = pgm_strdup(inet_ntoa(in)); - } else { - host_string = pgm_strdup(he->h_name); - } - pgm_hashtable_insert (hosts, &hash_key, host_string); - return host_string; -} - -void -pgm_ipopt_print ( - const void* ipopt, - size_t length - ) -{ -/* pre-conditions */ - pgm_assert (NULL != ipopt); - - const char* op = ipopt; - - while (length) - { - char len = (*op == PGM_IPOPT_NOP || *op == PGM_IPOPT_EOL) ? 1 : op[1]; - switch (*op) { - case PGM_IPOPT_EOL: printf(" eol"); break; - case PGM_IPOPT_NOP: printf(" nop"); break; - case PGM_IPOPT_RR: printf(" rr"); break; /* 1 route */ - case PGM_IPOPT_TS: printf(" ts"); break; /* 1 TS */ -#if 0 - case PGM_IPOPT_SECURITY: printf(" sec-level"); break; - case PGM_IPOPT_LSRR: printf(" lsrr"); break; /* 1 route */ - case PGM_IPOPT_SATID: printf(" satid"); break; - case PGM_IPOPT_SSRR: printf(" ssrr"); break; /* 1 route */ -#endif - default: printf(" %x{%d}", (int)*op, (int)len); break; - } - - if (!len) { - puts ("invalid IP opt length"); - return; - } - - op += len; - length -= len; - } -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/packet_test_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/packet_test_unittest.c deleted file mode 100644 index 7edefbb..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/packet_test_unittest.c +++ /dev/null @@ -1,169 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for PGM packet handling. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include - - -/* mock state */ - -#define PACKET_DEBUG -#include "packet_test.c" - - -static -struct pgm_sk_buff_t* -generate_raw_pgm (void) -{ - const char source[] = "i am not a string"; - const guint source_len = sizeof(source); - struct pgm_sk_buff_t* skb; - GError* err = NULL; - - skb = pgm_alloc_skb (1500); - skb->sock = (pgm_sock_t*)0x1; - skb->tstamp = 0x1; - skb->data = skb->head; - skb->len = sizeof(struct pgm_ip) + sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len; - skb->tail = (guint8*)skb->data + skb->len; - -/* add IP header */ - struct pgm_ip* iphdr = skb->data; - iphdr->ip_hl = sizeof(struct pgm_ip) / 4; - iphdr->ip_v = 4; - iphdr->ip_tos = 0; - iphdr->ip_len = g_htons (skb->len); - iphdr->ip_id = 0; - iphdr->ip_off = 0; - iphdr->ip_ttl = 16; - iphdr->ip_p = IPPROTO_PGM; - iphdr->ip_sum = 0; - iphdr->ip_src.s_addr = inet_addr ("127.0.0.1"); - iphdr->ip_dst.s_addr = inet_addr ("127.0.0.2"); - -/* add PGM header */ - struct pgm_header* pgmhdr = (gpointer)(iphdr + 1); - pgmhdr->pgm_sport = g_htons ((guint16)1000); - pgmhdr->pgm_dport = g_htons ((guint16)7500); - pgmhdr->pgm_type = PGM_ODATA; - pgmhdr->pgm_options = 0; - pgmhdr->pgm_gsi[0] = 1; - pgmhdr->pgm_gsi[1] = 2; - pgmhdr->pgm_gsi[2] = 3; - pgmhdr->pgm_gsi[3] = 4; - pgmhdr->pgm_gsi[4] = 5; - pgmhdr->pgm_gsi[5] = 6; - pgmhdr->pgm_tsdu_length = g_htons (source_len); - -/* add ODATA header */ - struct pgm_data* datahdr = (gpointer)(pgmhdr + 1); - datahdr->data_sqn = g_htonl ((guint32)0); - datahdr->data_trail = g_htonl ((guint32)-1); - -/* add payload */ - gpointer data = (gpointer)(datahdr + 1); - memcpy (data, source, source_len); - -/* finally PGM checksum */ - pgmhdr->pgm_checksum = 0; - pgmhdr->pgm_checksum = pgm_csum_fold (pgm_csum_partial (pgmhdr, sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len, 0)); - -/* and IP checksum */ - iphdr->ip_sum = pgm_inet_checksum (skb->head, skb->len, 0); - - return skb; -} - - -/* mock functions for external references */ - -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return 0; -} - - -/* target: - * gboolean - * pgm_print_packet ( - * gpointer data, - * gsize len - * ) - */ - -START_TEST (test_print_packet_pass_001) -{ - struct pgm_sk_buff_t* skb = generate_raw_pgm (); - pgm_print_packet (skb->head, skb->len); -} -END_TEST - -START_TEST (test_print_packet_fail_001) -{ - pgm_print_packet (NULL, 0); - fail ("reached"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_print_packet = tcase_create ("print-packet"); - suite_add_tcase (s, tc_print_packet); - tcase_add_test (tc_print_packet, test_print_packet_pass_001); - tcase_add_test_raise_signal (tc_print_packet, test_print_packet_fail_001, SIGABRT); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/pgmMIB.c b/3rdparty/openpgm-svn-r1085/pgm/pgmMIB.c deleted file mode 100644 index 1226c50..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/pgmMIB.c +++ /dev/null @@ -1,3212 +0,0 @@ -/* - * Note: this file originally auto-generated by mib2c using - * : mib2c.notify.conf,v 5.3 2004/04/15 12:29:19 dts12 Exp $ - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include "pgm/snmp.h" -#include "impl/pgmMIB.h" -#include "impl/pgmMIB_columns.h" -#include "impl/pgmMIB_enums.h" - - -//#define PGMMIB_DEBUG - - -/* locals */ - -struct pgm_snmp_context_t { - pgm_slist_t* list; - pgm_list_t* node; - int index; /* table index */ - unsigned instance; /* unique number per node */ -}; - -typedef struct pgm_snmp_context_t pgm_snmp_context_t; - -static const oid snmptrap_oid[] = {1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0}; - - -/* functions */ - -static int initialize_table_pgmSourceTable(void); -static Netsnmp_Node_Handler pgmSourceTable_handler; -static Netsnmp_First_Data_Point pgmSourceTable_get_first_data_point; -static Netsnmp_Next_Data_Point pgmSourceTable_get_next_data_point; -static Netsnmp_Free_Loop_Context pgmSourceTable_free_loop_context; - -static int initialize_table_pgmSourceConfigTable(void); -static Netsnmp_Node_Handler pgmSourceConfigTable_handler; -static Netsnmp_First_Data_Point pgmSourceConfigTable_get_first_data_point; -static Netsnmp_Next_Data_Point pgmSourceConfigTable_get_next_data_point; -static Netsnmp_Free_Loop_Context pgmSourceConfigTable_free_loop_context; - -static int initialize_table_pgmSourcePerformanceTable(void); -static Netsnmp_Node_Handler pgmSourcePerformanceTable_handler; -static Netsnmp_First_Data_Point pgmSourcePerformanceTable_get_first_data_point; -static Netsnmp_Next_Data_Point pgmSourcePerformanceTable_get_next_data_point; -static Netsnmp_Free_Loop_Context pgmSourcePerformanceTable_free_loop_context; - -static int initialize_table_pgmReceiverTable(void); -static Netsnmp_Node_Handler pgmReceiverTable_handler; -static Netsnmp_First_Data_Point pgmReceiverTable_get_first_data_point; -static Netsnmp_Next_Data_Point pgmReceiverTable_get_next_data_point; -static Netsnmp_Free_Loop_Context pgmReceiverTable_free_loop_context; - -static int initialize_table_pgmReceiverConfigTable(void); -static Netsnmp_Node_Handler pgmReceiverConfigTable_handler; -static Netsnmp_First_Data_Point pgmReceiverConfigTable_get_first_data_point; -static Netsnmp_Next_Data_Point pgmReceiverConfigTable_get_next_data_point; -static Netsnmp_Free_Loop_Context pgmReceiverConfigTable_free_loop_context; - -static int initialize_table_pgmReceiverPerformanceTable(void); -static Netsnmp_Node_Handler pgmReceiverPerformanceTable_handler; -static Netsnmp_First_Data_Point pgmReceiverPerformanceTable_get_first_data_point; -static Netsnmp_Next_Data_Point pgmReceiverPerformanceTable_get_next_data_point; -static Netsnmp_Free_Loop_Context pgmReceiverPerformanceTable_free_loop_context; - - -bool -pgm_mib_init ( - pgm_error_t** error - ) -{ - if (MIB_REGISTERED_OK != initialize_table_pgmSourceTable()) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SNMP, - PGM_ERROR_FAILED, - _("pgmSourceTable registration: see SNMP log for further details.")); - return FALSE; - } - if (MIB_REGISTERED_OK != initialize_table_pgmSourceConfigTable()) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SNMP, - PGM_ERROR_FAILED, - _("pgmSourceConfigTable registration: see SNMP log for further details.")); - return FALSE; - } - if (MIB_REGISTERED_OK != initialize_table_pgmSourcePerformanceTable()) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SNMP, - PGM_ERROR_FAILED, - _("pgmSourcePerformanceTable registration: see SNMP log for further details.")); - return FALSE; - } - if (MIB_REGISTERED_OK != initialize_table_pgmReceiverTable()) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SNMP, - PGM_ERROR_FAILED, - _("pgmReceiverTable registration: see SNMP log for further details.")); - return FALSE; - } - if (MIB_REGISTERED_OK != initialize_table_pgmReceiverConfigTable()) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SNMP, - PGM_ERROR_FAILED, - _("pgmReceiverConfigTable registration: see SNMP log for further details.")); - return FALSE; - } - if (MIB_REGISTERED_OK != initialize_table_pgmReceiverPerformanceTable()) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SNMP, - PGM_ERROR_FAILED, - _("pgmReceiverPerformanceTable registration: see SNMP log for further details.")); - return FALSE; - } - - return TRUE; -} - -/* - * pgmSourceTable - * - * returns MIB_REGISTERED_OK on success, failures include: - * MIB_REGISTRATION_FAILED - * MIB_DUPLICATE_REGISTRATION - * SNMPERR_GENERR - */ - -static -int -initialize_table_pgmSourceTable (void) -{ - pgm_debug ("initialize_table_pgmSourceTable ()"); - - static const oid pgmSourceTable_oid[] = {1,3,6,1,3,112,1,2,100,2}; - netsnmp_table_registration_info* table_info = NULL; - netsnmp_iterator_info* iinfo = NULL; - netsnmp_handler_registration* reg = NULL; - - reg = netsnmp_create_handler_registration ("pgmSourceTable", pgmSourceTable_handler, - pgmSourceTable_oid, OID_LENGTH( pgmSourceTable_oid ), - HANDLER_CAN_RONLY); - if (!reg) - goto error; - - table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); - if (!table_info) - goto error; - - table_info->min_column = COLUMN_PGMSOURCESOURCEADDRESS; - table_info->max_column = COLUMN_PGMSOURCESOURCEPORTNUMBER; - - netsnmp_table_helper_add_indexes (table_info, - ASN_OCTET_STR, /* index: pgmSourceGlobalId */ - ASN_UNSIGNED, /* index: pgmSourceSourcePort */ - 0); - - iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); - if (!iinfo) - goto error; - - iinfo->get_first_data_point = pgmSourceTable_get_first_data_point; - iinfo->get_next_data_point = pgmSourceTable_get_next_data_point; - iinfo->free_loop_context_at_end = pgmSourceTable_free_loop_context; - iinfo->table_reginfo = table_info; - - return netsnmp_register_table_iterator (reg, iinfo); - -error: - if (table_info && table_info->indexes) /* table_data_free_func() is internal */ - snmp_free_var (table_info->indexes); - SNMP_FREE( table_info ); - SNMP_FREE( iinfo ); - netsnmp_handler_registration_free (reg); - - return -1; -} - -/* called for first row of data in SNMP table - * - * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, - * optionally returns my_data_context. - * - * returns answer or NULL - */ - -static -netsnmp_variable_list* -pgmSourceTable_get_first_data_point( - void** my_loop_context, /* valid through one query of multiple "data points" */ - void** my_data_context, /* answer blob which is passed to handler() */ - netsnmp_variable_list* put_index_data, /* answer */ - netsnmp_iterator_info* mydata /* iinfo on init() */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmSourceTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_rwlock_reader_lock (&pgm_sock_list_lock); - - if (!pgm_sock_list) { - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - return NULL; - } - -/* create our own context for this SNMP loop */ - pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); - context->list = pgm_sock_list; - *my_loop_context = context; - -/* pass on for generic row access */ - return pgmSourceTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); -} - -static -netsnmp_variable_list* -pgmSourceTable_get_next_data_point( - void** my_loop_context, - void** my_data_context, - netsnmp_variable_list* put_index_data, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmSourceTable_get_next_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; - netsnmp_variable_list *idx = put_index_data; - - if (!context->list) - return NULL; - - pgm_sock_t* sock = context->list->data; - -/* pgmSourceGlobalId */ - char gsi[ PGM_GSISTRLEN ]; - pgm_gsi_print_r (&sock->tsi.gsi, gsi, sizeof(gsi)); - snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); - idx = idx->next_variable; - -/* pgmSourceSourcePort */ - const unsigned sport = ntohs (sock->tsi.sport); - snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); - - *my_data_context = sock; - context->list = context->list->next; - - return put_index_data; -} - -static -void -pgmSourceTable_free_loop_context ( - void* my_loop_context, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmSourceTable_free_loop_context (my_loop_context:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; - pgm_free (context); - my_loop_context = NULL; - - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); -} - -static -int -pgmSourceTable_handler ( - netsnmp_mib_handler* handler, - netsnmp_handler_registration* reginfo, - netsnmp_agent_request_info* reqinfo, - netsnmp_request_info* requests - ) -{ -/* pre-conditions */ - pgm_assert (NULL != handler); - pgm_assert (NULL != reginfo); - pgm_assert (NULL != reqinfo); - pgm_assert (NULL != requests); - - pgm_debug ("pgmSourceTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", - (const void*)handler, - (const void*)reginfo, - (const void*)reqinfo, - (const void*)requests); - - switch (reqinfo->mode) { - -/* Read-support (also covers GetNext requests) */ - - case MODE_GET: - for (netsnmp_request_info* request = requests; - request; - request = request->next) - { - const pgm_sock_t* sock = (pgm_sock_t*)netsnmp_extract_iterator_context (request); - - if (!sock) { - netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); - continue; - } - - netsnmp_variable_list *var = request->requestvb; - netsnmp_table_request_info* table_info = netsnmp_extract_table_info (request); - - if (!table_info) { - snmp_log (LOG_ERR, "pgmSourceTable_handler: empty table request info.\n"); - continue; - } - - switch (table_info->colnum) { - - case COLUMN_PGMSOURCESOURCEADDRESS: - { - struct sockaddr_in s4; - if (AF_INET == sock->send_gsr.gsr_source.ss_family) - memcpy (&s4, &sock->send_gsr.gsr_source, sizeof(s4)); - else - memset (&s4, 0, sizeof(s4)); - snmp_set_var_typed_value (var, ASN_IPADDRESS, - (const u_char*)&s4.sin_addr.s_addr, - sizeof(struct in_addr) ); - } - break; - - case COLUMN_PGMSOURCEGROUPADDRESS: - { - struct sockaddr_in s4; - if (AF_INET == sock->send_gsr.gsr_group.ss_family) - memcpy (&s4, &sock->send_gsr.gsr_group, sizeof(s4)); - else - memset (&s4, 0, sizeof(s4)); - snmp_set_var_typed_value (var, ASN_IPADDRESS, - (const u_char*)&s4.sin_addr.s_addr, - sizeof(struct in_addr) ); - } - break; - - case COLUMN_PGMSOURCEDESTPORT: - { - const unsigned dport = ntohs (sock->dport); - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&dport, sizeof(dport) ); - } - break; - -/* copy index[0] */ - case COLUMN_PGMSOURCESOURCEGSI: - snmp_set_var_typed_value (var, ASN_OCTET_STR, - (const u_char*)table_info->indexes->val.string, - table_info->indexes->val_len); - break; - -/* copy index[1] */ - case COLUMN_PGMSOURCESOURCEPORTNUMBER: - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)table_info->indexes->next_variable->val.integer, - table_info->indexes->next_variable->val_len); - - break; - - default: - snmp_log (LOG_ERR, "pgmSourceTable_handler: unknown column.\n"); - break; - } - } - break; - - case MODE_SET_RESERVE1: - default: - snmp_log (LOG_ERR, "pgmSourceTable_handler: unsupported mode.\n"); - break; - - } - - return SNMP_ERR_NOERROR; -} - -/* - * pgmSourceConfigTable - * - */ - -static -int -initialize_table_pgmSourceConfigTable(void) -{ - pgm_debug ("initialize_table_pgmSourceConfigTable ()"); - - static const oid pgmSourceConfigTable_oid[] = {1,3,6,1,3,112,1,2,100,3}; - netsnmp_table_registration_info* table_info = NULL; - netsnmp_iterator_info* iinfo = NULL; - netsnmp_handler_registration* reg = NULL; - - reg = netsnmp_create_handler_registration ("pgmSourceConfigTable", pgmSourceConfigTable_handler, - pgmSourceConfigTable_oid, OID_LENGTH( pgmSourceConfigTable_oid ), - HANDLER_CAN_RONLY); - if (!reg) - goto error; - - table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); - if (!table_info) - goto error; - - table_info->min_column = COLUMN_PGMSOURCETTL; - table_info->max_column = COLUMN_PGMSOURCESPMPATHADDRESS; - - netsnmp_table_helper_add_indexes (table_info, - ASN_OCTET_STR, /* index: pgmSourceConfigGlobalId */ - ASN_UNSIGNED, /* index: pgmSourceConfigSourcePort */ - 0); - - iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); - if (!iinfo) - goto error; - - iinfo->get_first_data_point = pgmSourceConfigTable_get_first_data_point; - iinfo->get_next_data_point = pgmSourceConfigTable_get_next_data_point; - iinfo->free_loop_context_at_end = pgmSourceConfigTable_free_loop_context; - iinfo->table_reginfo = table_info; - - return netsnmp_register_table_iterator (reg, iinfo); - -error: - if (table_info && table_info->indexes) /* table_data_free_func() is internal */ - snmp_free_var (table_info->indexes); - SNMP_FREE( table_info ); - SNMP_FREE( iinfo ); - netsnmp_handler_registration_free (reg); - - return -1; -} - -/* called for first row of data in SNMP table - * - * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, - * optionally returns my_data_context. - * - * returns answer or NULL - */ - -static -netsnmp_variable_list* -pgmSourceConfigTable_get_first_data_point( - void** my_loop_context, /* valid through one query of multiple "data points" */ - void** my_data_context, /* answer blob which is passed to handler() */ - netsnmp_variable_list* put_index_data, /* answer */ - netsnmp_iterator_info* mydata /* iinfo on init() */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmSourceConfigTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_rwlock_reader_lock (&pgm_sock_list_lock); - - if (!pgm_sock_list) { - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - return NULL; - } - -/* create our own context for this SNMP loop */ - pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); - context->list = pgm_sock_list; - *my_loop_context = context; - -/* pass on for generic row access */ - return pgmSourceConfigTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); -} - -static -netsnmp_variable_list* -pgmSourceConfigTable_get_next_data_point( - void** my_loop_context, - void** my_data_context, - netsnmp_variable_list* put_index_data, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmSourceConfigTable_get_next_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; - netsnmp_variable_list *idx = put_index_data; - - if (!context->list) - return NULL; - - pgm_sock_t* sock = context->list->data; - -/* pgmSourceGlobalId */ - char gsi[ PGM_GSISTRLEN ]; - pgm_gsi_print_r (&sock->tsi.gsi, gsi, sizeof(gsi)); - snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); - idx = idx->next_variable; - -/* pgmSourceSourcePort */ - const unsigned sport = ntohs (sock->tsi.sport); - snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); - - *my_data_context = sock; - context->list = context->list->next; - - return put_index_data; -} - -static -void -pgmSourceConfigTable_free_loop_context ( - void* my_loop_context, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmSourceConfigTable_free_loop_context (my_loop_context:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; - pgm_free (context); - my_loop_context = NULL; - - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); -} - -static -int -pgmSourceConfigTable_handler ( - netsnmp_mib_handler* handler, - netsnmp_handler_registration* reginfo, - netsnmp_agent_request_info* reqinfo, - netsnmp_request_info* requests - ) -{ -/* pre-conditions */ - pgm_assert (NULL != handler); - pgm_assert (NULL != reginfo); - pgm_assert (NULL != reqinfo); - pgm_assert (NULL != requests); - - pgm_debug ("pgmSourceConfigTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", - (const void*)handler, - (const void*)reginfo, - (const void*)reqinfo, - (const void*)requests); - - switch (reqinfo->mode) { - -/* Read-support (also covers GetNext requests) */ - - case MODE_GET: - for (netsnmp_request_info* request = requests; - request; - request = request->next) - { - const pgm_sock_t* sock = (pgm_sock_t*)netsnmp_extract_iterator_context (request); - - if (!sock) { - netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); - continue; - } - - netsnmp_variable_list *var = request->requestvb; - netsnmp_table_request_info* table_info = netsnmp_extract_table_info (request); - - if (!table_info) { - snmp_log (LOG_ERR, "pgmSourceTable_handler: empty table request info.\n"); - continue; - } - - switch (table_info->colnum) { - - case COLUMN_PGMSOURCETTL: - { - const unsigned hops = sock->hops; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&hops, sizeof(hops) ); - } - break; - - case COLUMN_PGMSOURCEADVMODE: - { - const unsigned adv_mode = 0 == sock->adv_mode ? PGMSOURCEADVMODE_TIME : PGMSOURCEADVMODE_DATA; - snmp_set_var_typed_value (var, ASN_INTEGER, - (const u_char*)&adv_mode, sizeof(adv_mode) ); - } - break; - -/* FIXED: pgmSourceLateJoin = disable(2) */ - case COLUMN_PGMSOURCELATEJOIN: - { - const unsigned late_join = PGMSOURCELATEJOIN_DISABLE; - snmp_set_var_typed_value (var, ASN_INTEGER, - (const u_char*)&late_join, sizeof(late_join) ); - } - break; - - case COLUMN_PGMSOURCETXWMAXRTE: - { - const unsigned txw_max_rte = sock->txw_max_rte; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&txw_max_rte, sizeof(txw_max_rte) ); - } - break; - - case COLUMN_PGMSOURCETXWSECS: - { - const unsigned txw_secs = sock->txw_secs; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&txw_secs, sizeof(txw_secs) ); - } - break; - -/* FIXED: TXW_ADV_SECS = 0 */ - case COLUMN_PGMSOURCETXWADVSECS: - { - const unsigned txw_adv_secs = 0; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&txw_adv_secs, sizeof(txw_adv_secs) ); - } - break; - -/* FIXED: pgmSourceAdvIvl = TXW_ADV_SECS * 1000 = 0 */ - case COLUMN_PGMSOURCEADVIVL: - { - const unsigned adv_ivl = 0; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&adv_ivl, sizeof(adv_ivl) ); - } - break; - - case COLUMN_PGMSOURCESPMIVL: - { - const unsigned spm_ivl = pgm_to_msecs (sock->spm_ambient_interval); - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&spm_ivl, sizeof(spm_ivl) ); - } - break; - -/* TODO: IHB_MIN */ - case COLUMN_PGMSOURCESPMHEARTBEATIVLMIN: - { - const unsigned ihb_min = 0; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&ihb_min, sizeof(ihb_min) ); - } - break; - -/* TODO: IHB_MAX */ - case COLUMN_PGMSOURCESPMHEARTBEATIVLMAX: - { - const unsigned ihb_max = 0; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&ihb_max, sizeof(ihb_max) ); - } - break; - -/* NAK_BO_IVL */ - case COLUMN_PGMSOURCERDATABACKOFFIVL: - { - const unsigned nak_bo_ivl = pgm_to_msecs (sock->nak_bo_ivl); - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&nak_bo_ivl, sizeof(nak_bo_ivl) ); - } - break; - -/* FIXED: pgmSourceFEC = disabled(1) */ - case COLUMN_PGMSOURCEFEC: - { - const unsigned fec = (sock->use_ondemand_parity || sock->use_proactive_parity) ? 1 : 0; - snmp_set_var_typed_value (var, ASN_INTEGER, - (const u_char*)&fec, sizeof(fec) ); - } - break; - -/* FIXED: pgmSourceFECTransmissionGrpSize = 0 */ - case COLUMN_PGMSOURCEFECTRANSMISSIONGRPSIZE: - { - const unsigned fec_tgs = sock->rs_k; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&fec_tgs, sizeof(fec_tgs) ); - } - break; - -/* FIXED: pgmSourceFECProactiveParitySize = 0 */ - case COLUMN_PGMSOURCEFECPROACTIVEPARITYSIZE: - { - const unsigned fec_paps = sock->rs_proactive_h; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&fec_paps, sizeof(fec_paps) ); - } - break; - -/* IPv6 not supported */ - case COLUMN_PGMSOURCESPMPATHADDRESS: - { - struct sockaddr_in s4; - if (AF_INET == sock->recv_gsr[0].gsr_source.ss_family) - memcpy (&s4, &sock->recv_gsr[0].gsr_source, sizeof(s4)); - else - memset (&s4, 0, sizeof(s4)); - snmp_set_var_typed_value (var, ASN_IPADDRESS, - (const u_char*)&s4.sin_addr.s_addr, - sizeof(struct in_addr) ); - } - break; - - default: - snmp_log (LOG_ERR, "pgmSourceConfigTable_handler: unknown column.\n"); - break; - } - } - break; - - case MODE_SET_RESERVE1: - default: - snmp_log (LOG_ERR, "pgmSourceConfigTable_handler: unsupported mode.\n"); - break; - - } - - return SNMP_ERR_NOERROR; -} - -/* - * pgmSourcePerformanceTable - */ - -static -int -initialize_table_pgmSourcePerformanceTable (void) -{ - pgm_debug ("initialize_table_pgmSourcePerformanceTable ()"); - - static const oid pgmSourcePerformanceTable_oid[] = {1,3,6,1,3,112,1,2,100,4}; - netsnmp_table_registration_info* table_info = NULL; - netsnmp_iterator_info* iinfo = NULL; - netsnmp_handler_registration* reg = NULL; - - reg = netsnmp_create_handler_registration ("pgmSourcePerformanceTable", pgmSourcePerformanceTable_handler, - pgmSourcePerformanceTable_oid, OID_LENGTH( pgmSourcePerformanceTable_oid ), - HANDLER_CAN_RONLY); - if (!reg) - goto error; - - table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); - if (!table_info) - goto error; - - table_info->min_column = COLUMN_PGMSOURCEDATABYTESSENT; - table_info->max_column = COLUMN_PGMSOURCENNAKERRORS; - - netsnmp_table_helper_add_indexes (table_info, - ASN_OCTET_STR, /* index: pgmSourceGlobalId */ - ASN_UNSIGNED, /* index: pgmSourceSourcePort */ - 0); - - iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); - if (!iinfo) - goto error; - - iinfo->get_first_data_point = pgmSourcePerformanceTable_get_first_data_point; - iinfo->get_next_data_point = pgmSourcePerformanceTable_get_next_data_point; - iinfo->free_loop_context_at_end = pgmSourcePerformanceTable_free_loop_context; - iinfo->table_reginfo = table_info; - - return netsnmp_register_table_iterator (reg, iinfo); - -error: - if (table_info && table_info->indexes) /* table_data_free_func() is internal */ - snmp_free_var (table_info->indexes); - SNMP_FREE( table_info ); - SNMP_FREE( iinfo ); - netsnmp_handler_registration_free (reg); - - return -1; -} - -/* called for first row of data in SNMP table - * - * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, - * optionally returns my_data_context. - * - * returns answer or NULL - */ - -static -netsnmp_variable_list* -pgmSourcePerformanceTable_get_first_data_point ( - void** my_loop_context, /* valid through one query of multiple "data points" */ - void** my_data_context, /* answer blob which is passed to handler() */ - netsnmp_variable_list* put_index_data, /* answer */ - netsnmp_iterator_info* mydata /* iinfo on init() */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmSourcePerformanceTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_rwlock_reader_lock (&pgm_sock_list_lock); - - if (!pgm_sock_list) { - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - return NULL; - } - -/* create our own context for this SNMP loop */ - pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); - context->list = pgm_sock_list; - *my_loop_context = context; - -/* pass on for generic row access */ - return pgmSourcePerformanceTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); -} - -static -netsnmp_variable_list* -pgmSourcePerformanceTable_get_next_data_point ( - void** my_loop_context, - void** my_data_context, - netsnmp_variable_list* put_index_data, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmSourcePerformanceTable_get_next_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; - netsnmp_variable_list *idx = put_index_data; - - if (!context->list) - return NULL; - - pgm_sock_t* sock = context->list->data; - -/* pgmSourceGlobalId */ - char gsi[ PGM_GSISTRLEN ]; - pgm_gsi_print_r (&sock->tsi.gsi, gsi, sizeof(gsi)); - snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); - idx = idx->next_variable; - -/* pgmSourceSourcePort */ - const unsigned sport = ntohs (sock->tsi.sport); - snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); - - *my_data_context = sock; - context->list = context->list->next; - - return put_index_data; -} - -static -void -pgmSourcePerformanceTable_free_loop_context ( - void* my_loop_context, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmPerformanceSourceTable_free_loop_context (my_loop_context:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; - pgm_free (context); - my_loop_context = NULL; - - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); -} - -static -int -pgmSourcePerformanceTable_handler ( - netsnmp_mib_handler* handler, - netsnmp_handler_registration* reginfo, - netsnmp_agent_request_info* reqinfo, - netsnmp_request_info* requests - ) -{ -/* pre-conditions */ - pgm_assert (NULL != handler); - pgm_assert (NULL != reginfo); - pgm_assert (NULL != reqinfo); - pgm_assert (NULL != requests); - - pgm_debug ("pgmSourcePerformanceTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", - (const void*)handler, - (const void*)reginfo, - (const void*)reqinfo, - (const void*)requests); - - switch (reqinfo->mode) { - -/* Read-support (also covers GetNext requests) */ - - case MODE_GET: - for (netsnmp_request_info* request = requests; - request; - request = request->next) - { - const pgm_sock_t* sock = (pgm_sock_t*)netsnmp_extract_iterator_context (request); - - if (!sock) { - netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); - continue; - } - - const pgm_txw_t* window = (const pgm_txw_t*)sock->window; - - netsnmp_variable_list *var = request->requestvb; - netsnmp_table_request_info* table_info = netsnmp_extract_table_info (request); - - if (!table_info) { - snmp_log (LOG_ERR, "pgmSourceTable_handler: empty table request info.\n"); - continue; - } - - switch (table_info->colnum) { - - case COLUMN_PGMSOURCEDATABYTESSENT: - { - const unsigned data_bytes = sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&data_bytes, sizeof(data_bytes) ); - } - break; - - case COLUMN_PGMSOURCEDATAMSGSSENT: - { - const unsigned data_msgs = sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&data_msgs, sizeof(data_msgs) ); - } - break; - - case COLUMN_PGMSOURCEBYTESBUFFERED: - { - const unsigned bytes_buffered = sock->can_send_data ? pgm_txw_size (window) : 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&bytes_buffered, sizeof(bytes_buffered) ); - } - break; - - case COLUMN_PGMSOURCEMSGSBUFFERED: - { - const unsigned msgs_buffered = sock->can_send_data ? pgm_txw_length (window) : 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&msgs_buffered, sizeof(msgs_buffered) ); - } - break; - -/* PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED + COLUMN_PGMSOURCEPARITYBYTESRETRANSMITTED */ - case COLUMN_PGMSOURCEBYTESRETRANSMITTED: - { - const unsigned bytes_resent = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&bytes_resent, sizeof(bytes_resent) ); - } - break; - -/* PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED + COLUMN_PGMSOURCEPARITYMSGSRETRANSMITTED */ - case COLUMN_PGMSOURCEMSGSRETRANSMITTED: - { - const unsigned msgs_resent = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&msgs_resent, sizeof(msgs_resent) ); - } - break; - - case COLUMN_PGMSOURCEBYTESSENT: - { - const unsigned bytes_sent = sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&bytes_sent, sizeof(bytes_sent) ); - } - break; - -/* COLUMN_PGMSOURCEPARITYNAKPACKETSRECEIVED + COLUMN_PGMSOURCESELECTIVENAKPACKETSRECEIVED */ - case COLUMN_PGMSOURCERAWNAKSRECEIVED: - { - const unsigned nak_packets = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&nak_packets, sizeof(nak_packets) ); - } - break; - -/* PGM_PC_SOURCE_SELECTIVE_NAKS_IGNORED + COLUMN_PGMSOURCEPARITYNAKSIGNORED */ - case COLUMN_PGMSOURCENAKSIGNORED: - { - const unsigned naks_ignored = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_IGNORED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&naks_ignored, sizeof(naks_ignored) ); - } - break; - - case COLUMN_PGMSOURCECKSUMERRORS: - { - const unsigned cksum_errors = sock->cumulative_stats[PGM_PC_SOURCE_CKSUM_ERRORS]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&cksum_errors, sizeof(cksum_errors) ); - } - break; - - case COLUMN_PGMSOURCEMALFORMEDNAKS: - { - const unsigned malformed_naks = sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&malformed_naks, sizeof(malformed_naks) ); - } - break; - - case COLUMN_PGMSOURCEPACKETSDISCARDED: - { - const unsigned packets_discarded = sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&packets_discarded, sizeof(packets_discarded) ); - } - break; - -/* PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED + COLUMN_PGMSOURCEPARITYNAKSRECEIVED */ - case COLUMN_PGMSOURCENAKSRCVD: - { - const unsigned naks_received = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&naks_received, sizeof(naks_received) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMSOURCEPARITYBYTESRETRANSMITTED: - { - const unsigned parity_bytes_resent = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&parity_bytes_resent, sizeof(parity_bytes_resent) ); - } - break; - - case COLUMN_PGMSOURCESELECTIVEBYTESRETRANSMITED: - { - const unsigned selective_bytes_resent = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&selective_bytes_resent, sizeof(selective_bytes_resent) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMSOURCEPARITYMSGSRETRANSMITTED: - { - const unsigned parity_msgs_resent = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&parity_msgs_resent, sizeof(parity_msgs_resent) ); - } - break; - - case COLUMN_PGMSOURCESELECTIVEMSGSRETRANSMITTED: - { - const unsigned selective_msgs_resent = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&selective_msgs_resent, sizeof(selective_msgs_resent) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMSOURCEBYTESADMIT: - { - const unsigned bytes_admit = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&bytes_admit, sizeof(bytes_admit) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMSOURCEMSGSADMIT: - { - const unsigned msgs_admit = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&msgs_admit, sizeof(msgs_admit) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMSOURCEPARITYNAKPACKETSRECEIVED: - { - const unsigned parity_nak_packets = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&parity_nak_packets, sizeof(parity_nak_packets) ); - } - break; - - case COLUMN_PGMSOURCESELECTIVENAKPACKETSRECEIVED: - { - const unsigned selective_nak_packets = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&selective_nak_packets, sizeof(selective_nak_packets) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMSOURCEPARITYNAKSRECEIVED: - { - const unsigned parity_naks = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&parity_naks, sizeof(parity_naks) ); - } - break; - - case COLUMN_PGMSOURCESELECTIVENAKSRECEIVED: - { - const unsigned selective_naks = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&selective_naks, sizeof(selective_naks) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMSOURCEPARITYNAKSIGNORED: - { - const unsigned parity_naks_ignored = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&parity_naks_ignored, sizeof(parity_naks_ignored) ); - } - break; - - case COLUMN_PGMSOURCESELECTIVENAKSIGNORED: - { - const unsigned selective_naks_ignored = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_IGNORED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&selective_naks_ignored, sizeof(selective_naks_ignored) ); - } - break; - - case COLUMN_PGMSOURCEACKERRORS: - { - const unsigned ack_errors = sock->cumulative_stats[PGM_PC_SOURCE_ACK_ERRORS];; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&ack_errors, sizeof(ack_errors) ); - } - break; - - case COLUMN_PGMSOURCEPGMCCACKER: - { - struct sockaddr_in s4; - if (AF_INET == sock->acker_nla.ss_family) - memcpy (&s4, &sock->acker_nla, sizeof(s4)); - else - memset (&s4, 0, sizeof(s4)); - snmp_set_var_typed_value (var, ASN_IPADDRESS, - (const u_char*)&s4.sin_addr.s_addr, - sizeof(struct in_addr) ); - } - break; - - case COLUMN_PGMSOURCETRANSMISSIONCURRENTRATE: - { - const unsigned tx_current_rate = sock->cumulative_stats[PGM_PC_SOURCE_TRANSMISSION_CURRENT_RATE]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&tx_current_rate, sizeof(tx_current_rate) ); - } - break; - - case COLUMN_PGMSOURCEACKPACKETSRECEIVED: - { - const unsigned ack_packets = sock->cumulative_stats[PGM_PC_SOURCE_ACK_PACKETS_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&ack_packets, sizeof(ack_packets) ); - } - break; - -/* COLUMN_PGMSOURCEPARITYNNAKPACKETSRECEIVED + COLUMN_PGMSOURCESELECTIVENNAKPACKETSRECEIVED */ - case COLUMN_PGMSOURCENNAKPACKETSRECEIVED: - { - const unsigned nnak_packets = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&nnak_packets, sizeof(nnak_packets) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMSOURCEPARITYNNAKPACKETSRECEIVED: - { - const unsigned parity_nnak_packets = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&parity_nnak_packets, sizeof(parity_nnak_packets) ); - } - break; - - case COLUMN_PGMSOURCESELECTIVENNAKPACKETSRECEIVED: - { - const unsigned selective_nnak_packets = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&selective_nnak_packets, sizeof(selective_nnak_packets) ); - } - break; - -/* COLUMN_PGMSOURCEPARITYNNAKSRECEIVED + COLUMN_PGMSOURCESELECTIVENNAKSRECEIVED */ - case COLUMN_PGMSOURCENNAKSRECEIVED: - { - const unsigned nnaks_received = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&nnaks_received, sizeof(nnaks_received) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMSOURCEPARITYNNAKSRECEIVED: - { - const unsigned parity_nnaks = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&parity_nnaks, sizeof(parity_nnaks) ); - } - break; - - case COLUMN_PGMSOURCESELECTIVENNAKSRECEIVED: - { - const unsigned selective_nnaks = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&selective_nnaks, sizeof(selective_nnaks) ); - } - break; - - case COLUMN_PGMSOURCENNAKERRORS: - { - const unsigned malformed_nnaks = sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&malformed_nnaks, sizeof(malformed_nnaks) ); - } - break; - - default: - snmp_log (LOG_ERR, "pgmSourcePerformanceTable_handler: unknown column.\n"); - break; - } - } - break; - - case MODE_SET_RESERVE1: - default: - snmp_log (LOG_ERR, "pgmSourcePerformanceTable_handler: unsupported mode.\n"); - break; - - } - - return SNMP_ERR_NOERROR; -} - -/* - * pgmReceiverTable - */ - -static -int -initialize_table_pgmReceiverTable(void) -{ - pgm_debug ("initialize_table_pgmReceiverTable ()"); - - static const oid pgmReceiverTable_oid[] = {1,3,6,1,3,112,1,3,100,2}; - netsnmp_table_registration_info* table_info = NULL; - netsnmp_iterator_info* iinfo = NULL; - netsnmp_handler_registration* reg = NULL; - - reg = netsnmp_create_handler_registration ("pgmReceiverTable", pgmReceiverTable_handler, - pgmReceiverTable_oid, OID_LENGTH( pgmReceiverTable_oid ), - HANDLER_CAN_RONLY); - if (!reg) - goto error; - - table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); - if (!table_info) - goto error; - - table_info->min_column = COLUMN_PGMRECEIVERGROUPADDRESS; - table_info->max_column = COLUMN_PGMRECEIVERUNIQUEINSTANCE; - - netsnmp_table_helper_add_indexes (table_info, - ASN_OCTET_STR, /* index: pgmReceiverGlobalId */ - ASN_UNSIGNED, /* index: pgmReceiverSourcePort */ - ASN_UNSIGNED, /* index: pgmReceiverInstance */ - 0); - - iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); - if (!iinfo) - goto error; - - iinfo->get_first_data_point = pgmReceiverTable_get_first_data_point; - iinfo->get_next_data_point = pgmReceiverTable_get_next_data_point; - iinfo->free_loop_context_at_end = pgmReceiverTable_free_loop_context; - iinfo->table_reginfo = table_info; - - return netsnmp_register_table_iterator (reg, iinfo); - -error: - if (table_info && table_info->indexes) /* table_data_free_func() is internal */ - snmp_free_var (table_info->indexes); - SNMP_FREE( table_info ); - SNMP_FREE( iinfo ); - netsnmp_handler_registration_free (reg); - - return -1; -} - -/* called for first row of data in SNMP table - * - * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, - * optionally returns my_data_context. - * - * returns answer or NULL - */ - -static -netsnmp_variable_list* -pgmReceiverTable_get_first_data_point ( - void** my_loop_context, /* valid through one query of multiple "data points" */ - void** my_data_context, /* answer blob which is passed to handler() */ - netsnmp_variable_list* put_index_data, /* answer */ - netsnmp_iterator_info* mydata /* iinfo on init() */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmReceiverTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_rwlock_reader_lock (&pgm_sock_list_lock); - - if (!pgm_sock_list) { - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - return NULL; - } - -/* create our own context for this SNMP loop */ - pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); - -/* hunt to find first node, through all socks */ - for (context->list = pgm_sock_list; - context->list; - context->list = context->list->next) - { -/* and through all peers for each sock */ - pgm_sock_t* sock = (pgm_sock_t*)context->list->data; - pgm_rwlock_reader_lock (&sock->peers_lock); - context->node = sock->peers_list; - if (context->node) { -/* maintain this sock's peers lock */ - break; - } - - pgm_rwlock_reader_unlock (&sock->peers_lock); - } - -/* no node found */ - if (!context->node) { - pgm_free (context); - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - return NULL; - } - - *my_loop_context = context; - -/* pass on for generic row access */ - return pgmReceiverTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); -} - -static -netsnmp_variable_list* -pgmReceiverTable_get_next_data_point ( - void** my_loop_context, - void** my_data_context, - netsnmp_variable_list* put_index_data, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmReceiverTable_get_next_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; - netsnmp_variable_list *idx = put_index_data; - - if (!context->list) - return NULL; - - pgm_sock_t* sock = context->list->data; - - if (!context->node) - return NULL; - - pgm_peer_t* peer = context->node->data; - -/* pgmReceiverGlobalId */ - char gsi[ PGM_GSISTRLEN ]; - pgm_gsi_print_r (&peer->tsi.gsi, gsi, sizeof(gsi)); - snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); - idx = idx->next_variable; - -/* pgmReceiverSourcePort */ - const unsigned sport = ntohs (peer->tsi.sport); - snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); - idx = idx->next_variable; - -/* pgmReceiverInstance */ - const unsigned instance = context->instance++; - snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&instance, sizeof(instance)); - -/* set data context to pass to handler callback */ - *my_data_context = peer; - -/* hunt for next valid node */ - if (context->node->next) { - context->node = context->node->next; - } else { - context->node = NULL; - while (context->list->next) - { - pgm_rwlock_reader_unlock (&sock->peers_lock); - context->list = context->list->next; - sock = context->list->data; - pgm_rwlock_reader_lock (&sock->peers_lock); - context->node = sock->peers_list; - if (context->node) { -/* keep lock */ - break; - } - } - } - - return put_index_data; -} - -static -void -pgmReceiverTable_free_loop_context ( - void* my_loop_context, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmReceiverTable_free_loop_context (my_loop_context:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; - -/* check for intra-peer state */ - if (context->list) { - pgm_sock_t* sock = context->list->data; - pgm_rwlock_reader_unlock (&sock->peers_lock); - } - - pgm_free (context); - my_loop_context = NULL; - - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); -} - -static -int -pgmReceiverTable_handler ( - netsnmp_mib_handler* handler, - netsnmp_handler_registration* reginfo, - netsnmp_agent_request_info* reqinfo, - netsnmp_request_info* requests - ) -{ -/* pre-conditions */ - pgm_assert (NULL != handler); - pgm_assert (NULL != reginfo); - pgm_assert (NULL != reqinfo); - pgm_assert (NULL != requests); - - pgm_debug ("pgmReceiverTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", - (const void*)handler, - (const void*)reginfo, - (const void*)reqinfo, - (const void*)requests); - - switch (reqinfo->mode) { - -/* Read-support (also covers GetNext requests) */ - - case MODE_GET: - for (netsnmp_request_info* request = requests; - request; - request = request->next) - { - const pgm_peer_t* peer = (pgm_peer_t*)netsnmp_extract_iterator_context (request); - - if (!peer) { - netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); - continue; - } - - netsnmp_variable_list *var = request->requestvb; - netsnmp_table_request_info* table_info = netsnmp_extract_table_info(request); - - if (table_info == NULL) { - snmp_log (LOG_ERR, "pgmReceiverTable_handler: empty table request info.\n"); - continue; - } - - switch (table_info->colnum) { - - case COLUMN_PGMRECEIVERGROUPADDRESS: - { - struct sockaddr_in s4; - if (AF_INET == peer->group_nla.ss_family) - memcpy (&s4, &peer->group_nla, sizeof(s4)); - else - memset (&s4, 0, sizeof(s4)); - snmp_set_var_typed_value (var, ASN_IPADDRESS, - (const u_char*)&s4.sin_addr.s_addr, - sizeof(struct in_addr) ); - } - break; - -/* by definition same as sock */ - case COLUMN_PGMRECEIVERDESTPORT: - { - const unsigned dport = ntohs (peer->sock->dport); - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&dport, sizeof(dport) ); - } - break; - - case COLUMN_PGMRECEIVERSOURCEADDRESS: - { - struct sockaddr_in s4; - if (AF_INET == peer->nla.ss_family) - memcpy (&s4, &peer->nla, sizeof(s4)); - else - memset (&s4, 0, sizeof(s4)); - snmp_set_var_typed_value (var, ASN_IPADDRESS, - (const u_char*)&s4.sin_addr.s_addr, - sizeof(struct in_addr) ); - } - break; - - case COLUMN_PGMRECEIVERLASTHOP: - { - struct sockaddr_in s4; - if (AF_INET == peer->local_nla.ss_family) - memcpy (&s4, &peer->local_nla, sizeof(s4)); - else - memset (&s4, 0, sizeof(s4)); - snmp_set_var_typed_value (var, ASN_IPADDRESS, - (const u_char*)&s4.sin_addr.s_addr, - sizeof(struct in_addr) ); - } - break; - -/* copy index[0] */ - case COLUMN_PGMRECEIVERSOURCEGSI: - snmp_set_var_typed_value (var, ASN_OCTET_STR, - (const u_char*)table_info->indexes->val.string, - table_info->indexes->val_len); - break; - -/* copy index[1] */ - case COLUMN_PGMRECEIVERSOURCEPORTNUMBER: - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)table_info->indexes->next_variable->val.integer, - table_info->indexes->next_variable->val_len); - break; - -/* copy index[2] */ - case COLUMN_PGMRECEIVERUNIQUEINSTANCE: - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)table_info->indexes->next_variable->next_variable->val.integer, - table_info->indexes->next_variable->next_variable->val_len); - break; - - default: - snmp_log (LOG_ERR, "pgmReceiverTable_handler: unknown column.\n"); - break; - } - } - break; - - case MODE_SET_RESERVE1: - default: - snmp_log (LOG_ERR, "pgmReceiverTable_handler: unsupported mode.\n"); - break; - - } - - return SNMP_ERR_NOERROR; -} - -/* - * pgmReceiverConfigTable - * - */ - -static -int -initialize_table_pgmReceiverConfigTable(void) -{ - pgm_debug ("initialize_table_pgmReceiverConfigTable ()"); - - static const oid pgmReceiverConfigTable_oid[] = {1,3,6,1,3,112,1,3,100,3}; - netsnmp_table_registration_info* table_info = NULL; - netsnmp_iterator_info* iinfo = NULL; - netsnmp_handler_registration* reg = NULL; - - reg = netsnmp_create_handler_registration ("pgmReceiverConfigTable", pgmReceiverConfigTable_handler, - pgmReceiverConfigTable_oid, OID_LENGTH(pgmReceiverConfigTable_oid), - HANDLER_CAN_RONLY); - if (!reg) - goto error; - - table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); - if (!table_info) - goto error; - - table_info->min_column = COLUMN_PGMRECEIVERNAKBACKOFFIVL; - table_info->max_column = COLUMN_PGMRECEIVERNAKFAILURETHRESHOLD; - - netsnmp_table_helper_add_indexes (table_info, - ASN_OCTET_STR, /* index: pgmReceiverConfigGlobalId */ - ASN_UNSIGNED, /* index: pgmReceiverConfigSourcePort */ - ASN_UNSIGNED, /* index: pgmReceiverInstance */ - 0); - - iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); - if (!iinfo) - goto error; - - iinfo->get_first_data_point = pgmReceiverConfigTable_get_first_data_point; - iinfo->get_next_data_point = pgmReceiverConfigTable_get_next_data_point; - iinfo->free_loop_context_at_end = pgmReceiverConfigTable_free_loop_context; - iinfo->table_reginfo = table_info; - - return netsnmp_register_table_iterator (reg, iinfo); - -error: - if (table_info && table_info->indexes) /* table_data_free_func() is internal */ - snmp_free_var (table_info->indexes); - SNMP_FREE( table_info ); - SNMP_FREE( iinfo ); - netsnmp_handler_registration_free (reg); - - return -1; -} - -/* called for first row of data in SNMP table - * - * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, - * optionally returns my_data_context. - * - * returns answer or NULL - */ - -static -netsnmp_variable_list* -pgmReceiverConfigTable_get_first_data_point( - void** my_loop_context, /* valid through one query of multiple "data points" */ - void** my_data_context, /* answer blob which is passed to handler() */ - netsnmp_variable_list* put_index_data, /* answer */ - netsnmp_iterator_info* mydata /* iinfo on init() */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmReceiverConfigTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_rwlock_reader_lock (&pgm_sock_list_lock); - - if (!pgm_sock_list) { - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - return NULL; - } - -/* create our own context for this SNMP loop */ - pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); - -/* hunt to find first node, through all socks */ - for (context->list = pgm_sock_list; - context->list; - context->list = context->list->next) - { -/* and through all peers for each sock */ - pgm_sock_t* sock = (pgm_sock_t*)context->list->data; - pgm_rwlock_reader_lock (&sock->peers_lock); - context->node = sock->peers_list; - if (context->node) - break; - - pgm_rwlock_reader_unlock (&sock->peers_lock); - } - -/* no node found */ - if (!context->node) { - pgm_free (context); - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - return NULL; - } - - *my_loop_context = context; - -/* pass on for generic row access */ - return pgmReceiverConfigTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); -} - -static -netsnmp_variable_list* -pgmReceiverConfigTable_get_next_data_point( - void** my_loop_context, - void** my_data_context, - netsnmp_variable_list* put_index_data, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmReceiverConfigTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; - netsnmp_variable_list *idx = put_index_data; - - if (!context->list) - return NULL; - - pgm_sock_t* sock = context->list->data; - - if (!context->node) - return NULL; - - pgm_peer_t* peer = context->node->data; - -/* pgmReceiverGlobalId */ - char gsi[ PGM_GSISTRLEN ]; - pgm_gsi_print_r (&peer->tsi.gsi, gsi, sizeof(gsi)); - snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); - idx = idx->next_variable; - -/* pgmReceiverSourcePort */ - const unsigned sport = ntohs (peer->tsi.sport); - snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); - idx = idx->next_variable; - -/* pgmReceiverInstance */ - const unsigned instance = context->instance++; - snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&instance, sizeof(instance)); - -/* set data context to pass to handler callback */ - *my_data_context = peer; - -/* hunt for next valid node */ - if (context->node->next) { - context->node = context->node->next; - } else { - context->node = NULL; - while (context->list->next) - { - pgm_rwlock_reader_unlock (&sock->peers_lock); - context->list = context->list->next; - sock = context->list->data; - pgm_rwlock_reader_lock (&sock->peers_lock); - context->node = sock->peers_list; - if (context->node) { -/* keep lock */ - break; - } - } - } - - return put_index_data; -} - -static -void -pgmReceiverConfigTable_free_loop_context ( - void* my_loop_context, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmReceiverConfigTable_free_loop_context (my_loop_context:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; - -/* check for intra-peer state */ - if (context->list) { - pgm_sock_t* sock = context->list->data; - pgm_rwlock_reader_unlock (&sock->peers_lock); - } - - pgm_free (context); - my_loop_context = NULL; - - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); -} - -static -int -pgmReceiverConfigTable_handler ( - netsnmp_mib_handler* handler, - netsnmp_handler_registration* reginfo, - netsnmp_agent_request_info* reqinfo, - netsnmp_request_info* requests - ) -{ -/* pre-conditions */ - pgm_assert (NULL != handler); - pgm_assert (NULL != reginfo); - pgm_assert (NULL != reqinfo); - pgm_assert (NULL != requests); - - pgm_debug ("pgmReceiverConfigTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", - (const void*)handler, - (const void*)reginfo, - (const void*)reqinfo, - (const void*)requests); - - switch (reqinfo->mode) { - -/* Read-support (also covers GetNext requests) */ - - case MODE_GET: - for (netsnmp_request_info* request = requests; - request; - request = request->next) - { - const pgm_peer_t* peer = (pgm_peer_t*)netsnmp_extract_iterator_context(request); - - if (peer == NULL) { - netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); - continue; - } - - netsnmp_variable_list *var = request->requestvb; - netsnmp_table_request_info* table_info = netsnmp_extract_table_info(request); - - if (table_info == NULL) { - snmp_log (LOG_ERR, "pgmReceiverTable_handler: empty table request info.\n"); - continue; - } - - switch (table_info->colnum) { - -/* nak_bo_ivl from sock */ - case COLUMN_PGMRECEIVERNAKBACKOFFIVL: - { - const unsigned nak_bo_ivl = peer->sock->nak_bo_ivl; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&nak_bo_ivl, sizeof(nak_bo_ivl) ); - } - break; - -/* nak_rpt_ivl from sock */ - case COLUMN_PGMRECEIVERNAKREPEATIVL: - { - const unsigned nak_rpt_ivl = peer->sock->nak_rpt_ivl; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&nak_rpt_ivl, sizeof(nak_rpt_ivl) ); - } - break; - -/* nak_ncf_retries from sock */ - case COLUMN_PGMRECEIVERNAKNCFRETRIES: - { - const unsigned nak_ncf_retries = peer->sock->nak_ncf_retries; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&nak_ncf_retries, sizeof(nak_ncf_retries) ); - } - break; - -/* nak_rdata_ivl from sock */ - case COLUMN_PGMRECEIVERNAKRDATAIVL: - { - const unsigned nak_rdata_ivl = peer->sock->nak_rdata_ivl; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&nak_rdata_ivl, sizeof(nak_rdata_ivl) ); - } - break; - -/* nak_data_retries from sock */ - case COLUMN_PGMRECEIVERNAKDATARETRIES: - { - const unsigned nak_data_retries = peer->sock->nak_data_retries; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&nak_data_retries, sizeof(nak_data_retries) ); - } - break; - -/* FIXED: pgmReceiverSendNaks = enabled(1) */ - case COLUMN_PGMRECEIVERSENDNAKS: - { - const unsigned send_naks = PGMRECEIVERSENDNAKS_ENABLED; - snmp_set_var_typed_value (var, ASN_INTEGER, - (const u_char*)&send_naks, sizeof(send_naks) ); - } - break; - -/* FIXED: pgmReceiverLateJoin = disabled(2) */ - case COLUMN_PGMRECEIVERLATEJOIN: - { - const unsigned late_join = PGMRECEIVERLATEJOIN_DISABLED; - snmp_set_var_typed_value (var, ASN_INTEGER, - (const u_char*)&late_join, sizeof(late_join) ); - } - break; - -/* FIXED: 1 for multicast */ - case COLUMN_PGMRECEIVERNAKTTL: - { - const unsigned nak_hops = 1; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&nak_hops, sizeof(nak_hops) ); - } - break; - -/* FIXED: pgmReceiverDeliveryOrder = ordered(2) */ - case COLUMN_PGMRECEIVERDELIVERYORDER: - { - const unsigned delivery_order = PGMRECEIVERDELIVERYORDER_ORDERED; - snmp_set_var_typed_value (var, ASN_INTEGER, - (const u_char*)&delivery_order, sizeof(delivery_order) ); - } - break; - -/* FIXED: pgmReceiverMcastNaks = disabled(2) */ - case COLUMN_PGMRECEIVERMCASTNAKS: - { - const unsigned mcast_naks = PGMRECEIVERMCASTNAKS_DISABLED; - snmp_set_var_typed_value (var, ASN_INTEGER, - (const u_char*)&mcast_naks, sizeof(mcast_naks) ); - } - break; - -/* TODO: traps */ - case COLUMN_PGMRECEIVERNAKFAILURETHRESHOLDTIMER: - case COLUMN_PGMRECEIVERNAKFAILURETHRESHOLD: - { - const unsigned threshold = 0; - snmp_set_var_typed_value (var, ASN_UNSIGNED, - (const u_char*)&threshold, sizeof(threshold) ); - } - break; - - default: - snmp_log (LOG_ERR, "pgmReceiverTable_handler: unknown column.\n"); - break; - } - } - break; - - case MODE_SET_RESERVE1: - default: - snmp_log (LOG_ERR, "pgmReceiverTable_handler: unsupported mode.\n"); - break; - - } - - return SNMP_ERR_NOERROR; -} - -/* - * pgmReceiverPerformanceTable - */ - -static -int -initialize_table_pgmReceiverPerformanceTable (void) -{ - pgm_debug ("initialize_table_pgmReceiverPerformanceTable ()"); - - static const oid pgmReceiverPerformanceTable_oid[] = {1,3,6,1,3,112,1,3,100,4}; - netsnmp_table_registration_info* table_info = NULL; - netsnmp_iterator_info* iinfo = NULL; - netsnmp_handler_registration* reg = NULL; - - reg = netsnmp_create_handler_registration ("pgmReceiverPerformanceTable", pgmReceiverPerformanceTable_handler, - pgmReceiverPerformanceTable_oid, OID_LENGTH( pgmReceiverPerformanceTable_oid ), - HANDLER_CAN_RONLY); - if (!reg) - goto error; - - table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); - if (!table_info) - goto error; - - table_info->min_column = COLUMN_PGMRECEIVERDATABYTESRECEIVED; - table_info->max_column = COLUMN_PGMRECEIVERLASTINTERVALNAKFAILURES; - - netsnmp_table_helper_add_indexes (table_info, - ASN_OCTET_STR, /* index: pgmReceiverGlobalId */ - ASN_UNSIGNED, /* index: pgmReceiverSourcePort */ - ASN_UNSIGNED, /* index: pgmReceiverInstance */ - 0); - - iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); - if (!iinfo) - goto error; - - iinfo->get_first_data_point = pgmReceiverPerformanceTable_get_first_data_point; - iinfo->get_next_data_point = pgmReceiverPerformanceTable_get_next_data_point; - iinfo->free_loop_context_at_end = pgmReceiverPerformanceTable_free_loop_context; - iinfo->table_reginfo = table_info; - - return netsnmp_register_table_iterator (reg, iinfo); - -error: - if (table_info && table_info->indexes) /* table_data_free_func() is internal */ - snmp_free_var (table_info->indexes); - SNMP_FREE( table_info ); - SNMP_FREE( iinfo ); - netsnmp_handler_registration_free (reg); - - return -1; -} - -/* called for first row of data in SNMP table - * - * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, - * optionally returns my_data_context. - * - * returns answer or NULL - */ - -static -netsnmp_variable_list* -pgmReceiverPerformanceTable_get_first_data_point ( - void** my_loop_context, /* valid through one query of multiple "data points" */ - void** my_data_context, /* answer blob which is passed to handler() */ - netsnmp_variable_list* put_index_data, /* answer */ - netsnmp_iterator_info* mydata /* iinfo on init() */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmReceiverPerformanceTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_rwlock_reader_lock (&pgm_sock_list_lock); - - if (!pgm_sock_list) { - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - return NULL; - } - -/* create our own context for this SNMP loop */ - pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); - -/* hunt to find first node, through all socks */ - for (context->list = pgm_sock_list; - context->list; - context->list = context->list->next) - { -/* and through all peers for each sock */ - pgm_sock_t* sock = (pgm_sock_t*)context->list->data; - pgm_rwlock_reader_lock (&sock->peers_lock); - context->node = sock->peers_list; - if (context->node) - break; - - pgm_rwlock_reader_unlock (&sock->peers_lock); - } - -/* no node found */ - if (!context->node) { - pgm_free (context); - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); - return NULL; - } - - *my_loop_context = context; - -/* pass on for generic row access */ - return pgmReceiverPerformanceTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); -} - -static -netsnmp_variable_list* -pgmReceiverPerformanceTable_get_next_data_point ( - void** my_loop_context, - void** my_data_context, - netsnmp_variable_list* put_index_data, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != my_data_context); - pgm_assert (NULL != put_index_data); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmReceiverPerformanceTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)my_data_context, - (const void*)put_index_data, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; - netsnmp_variable_list *idx = put_index_data; - - if (!context->list) - return NULL; - - pgm_sock_t* sock = context->list->data; - - if (!context->node) - return NULL; - - pgm_peer_t* peer = context->node->data; - -/* pgmReceiverGlobalId */ - char gsi[ PGM_GSISTRLEN ]; - pgm_gsi_print_r (&peer->tsi.gsi, gsi, sizeof(gsi)); - snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); - idx = idx->next_variable; - -/* pgmReceiverSourcePort */ - const unsigned sport = ntohs (peer->tsi.sport); - snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); - idx = idx->next_variable; - -/* pgmReceiverInstance */ - const unsigned instance = context->instance++; - snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&instance, sizeof(instance)); - -/* set data context to pass to handler callback */ - *my_data_context = peer; - -/* hunt for next valid node */ - if (context->node->next) { - context->node = context->node->next; - } else { - context->node = NULL; - while (context->list->next) - { - pgm_rwlock_reader_unlock (&sock->peers_lock); - context->list = context->list->next; - sock = context->list->data; - pgm_rwlock_reader_lock (&sock->peers_lock); - context->node = sock->peers_list; - - if (context->node) - break; - } - } - - return put_index_data; -} - -static -void -pgmReceiverPerformanceTable_free_loop_context ( - void* my_loop_context, - netsnmp_iterator_info* mydata - ) -{ -/* pre-conditions */ - pgm_assert (NULL != my_loop_context); - pgm_assert (NULL != mydata); - - pgm_debug ("pgmReceiverPerformanceTable_free_loop_context (my_loop_context:%p mydata:%p)", - (const void*)my_loop_context, - (const void*)mydata); - - pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; - -/* check for intra-peer state */ - if (context->list) { - pgm_sock_t* sock = context->list->data; - pgm_rwlock_reader_unlock (&sock->peers_lock); - } - - pgm_free (context); - my_loop_context = NULL; - - pgm_rwlock_reader_unlock (&pgm_sock_list_lock); -} - -static -int -pgmReceiverPerformanceTable_handler ( - netsnmp_mib_handler* handler, - netsnmp_handler_registration* reginfo, - netsnmp_agent_request_info* reqinfo, - netsnmp_request_info* requests - ) -{ -/* pre-conditions */ - pgm_assert (NULL != handler); - pgm_assert (NULL != reginfo); - pgm_assert (NULL != reqinfo); - pgm_assert (NULL != requests); - - pgm_debug ("pgmReceiverPerformanceTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", - (const void*)handler, - (const void*)reginfo, - (const void*)reqinfo, - (const void*)requests); - - switch (reqinfo->mode) { - -/* Read-support (also covers GetNext requests) */ - - case MODE_GET: - for (netsnmp_request_info* request = requests; - request; - request = request->next) - { - const pgm_peer_t* peer = (pgm_peer_t*)netsnmp_extract_iterator_context (request); - - if (!peer) { - netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); - continue; - } - - const pgm_rxw_t* window = (const pgm_rxw_t*)peer->window; - - netsnmp_variable_list *var = request->requestvb; - netsnmp_table_request_info* table_info = netsnmp_extract_table_info (request); - - if (!table_info) { - snmp_log (LOG_ERR, "pgmReceiverTable_handler: empty table request info.\n"); - continue; - } - - switch (table_info->colnum) { - - case COLUMN_PGMRECEIVERDATABYTESRECEIVED: - { - const unsigned data_bytes = peer->cumulative_stats[PGM_PC_RECEIVER_DATA_BYTES_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&data_bytes, sizeof(data_bytes) ); - } - break; - - case COLUMN_PGMRECEIVERDATAMSGSRECEIVED: - { - const unsigned data_msgs = peer->cumulative_stats[PGM_PC_RECEIVER_DATA_MSGS_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&data_msgs, sizeof(data_msgs) ); - } - break; - -/* total */ - case COLUMN_PGMRECEIVERNAKSSENT: - { - const unsigned naks_sent = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&naks_sent, sizeof(naks_sent) ); - } - break; - -/* total */ - case COLUMN_PGMRECEIVERNAKSRETRANSMITTED: - { - const unsigned naks_resent = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_RETRANSMITTED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&naks_resent, sizeof(naks_resent) ); - } - break; - -/* total */ - case COLUMN_PGMRECEIVERNAKFAILURES: - { - const unsigned nak_failures = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_FAILED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&nak_failures, sizeof(nak_failures) ); - } - break; - - case COLUMN_PGMRECEIVERBYTESRECEIVED: - { - const unsigned bytes_received = peer->cumulative_stats[PGM_PC_RECEIVER_BYTES_RECEIVED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&bytes_received, sizeof(bytes_received) ); - } - break; - -/* total */ - case COLUMN_PGMRECEIVERNAKSSUPPRESSED: - { - const unsigned naks_suppressed = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&naks_suppressed, sizeof(naks_suppressed) ); - } - break; - -/* bogus: same as source checksum errors */ - case COLUMN_PGMRECEIVERCKSUMERRORS: - { - const unsigned cksum_errors = peer->sock->cumulative_stats[PGM_PC_SOURCE_CKSUM_ERRORS]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&cksum_errors, sizeof(cksum_errors) ); - } - break; - - case COLUMN_PGMRECEIVERMALFORMEDSPMS: - { - const unsigned malformed_spms = peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&malformed_spms, sizeof(malformed_spms) ); - } - break; - - case COLUMN_PGMRECEIVERMALFORMEDODATA: - { - const unsigned malformed_odata = peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_ODATA]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&malformed_odata, sizeof(malformed_odata) ); - } - break; - - case COLUMN_PGMRECEIVERMALFORMEDRDATA: - { - const unsigned malformed_rdata = peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_RDATA]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&malformed_rdata, sizeof(malformed_rdata) ); - } - break; - - case COLUMN_PGMRECEIVERMALFORMEDNCFS: - { - const unsigned malformed_ncfs = peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&malformed_ncfs, sizeof(malformed_ncfs) ); - } - break; - - case COLUMN_PGMRECEIVERPACKETSDISCARDED: - { - const unsigned packets_discarded = peer->cumulative_stats[PGM_PC_RECEIVER_PACKETS_DISCARDED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&packets_discarded, sizeof(packets_discarded) ); - } - break; - - case COLUMN_PGMRECEIVERLOSSES: - { - const unsigned losses = window->cumulative_losses; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&losses, sizeof(losses) ); - } - break; - - case COLUMN_PGMRECEIVERBYTESDELIVEREDTOAPP: - { - const unsigned bytes_delivered =window->bytes_delivered; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&bytes_delivered, sizeof(bytes_delivered) ); - } - break; - - case COLUMN_PGMRECEIVERMSGSDELIVEREDTOAPP: - { - const unsigned msgs_delivered = window->msgs_delivered; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&msgs_delivered, sizeof(msgs_delivered) ); - } - break; - - case COLUMN_PGMRECEIVERDUPSPMS: - { - const unsigned dup_spms = peer->cumulative_stats[PGM_PC_RECEIVER_DUP_SPMS]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&dup_spms, sizeof(dup_spms) ); - } - break; - - case COLUMN_PGMRECEIVERDUPDATAS: - { - const unsigned dup_data = peer->cumulative_stats[PGM_PC_RECEIVER_DUP_DATAS]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&dup_data, sizeof(dup_data) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMRECEIVERDUPPARITIES: - { - const unsigned dup_parity = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&dup_parity, sizeof(dup_parity) ); - } - break; - -/* COLUMN_PGMRECEIVERPARITYNAKPACKETSSENT + COLUMN_PGMRECEIVERSELECTIVENAKPACKETSSENT */ - case COLUMN_PGMRECEIVERNAKPACKETSSENT: - { - const unsigned nak_packets = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&nak_packets, sizeof(nak_packets) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMRECEIVERPARITYNAKPACKETSSENT: - { - const unsigned parity_naks = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&parity_naks, sizeof(parity_naks) ); - } - break; - - case COLUMN_PGMRECEIVERSELECTIVENAKPACKETSSENT: - { - const unsigned nak_packets = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&nak_packets, sizeof(nak_packets) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMRECEIVERPARITYNAKSSENT: - { - const unsigned parity_naks = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&parity_naks, sizeof(parity_naks) ); - } - break; - - case COLUMN_PGMRECEIVERSELECTIVENAKSSENT: - { - const unsigned naks_sent = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&naks_sent, sizeof(naks_sent) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMRECEIVERPARITYNAKSRETRANSMITTED: - { - const unsigned parity_resent = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&parity_resent, sizeof(parity_resent) ); - } - break; - - case COLUMN_PGMRECEIVERSELECTIVENAKSRETRANSMITTED: - { - const unsigned naks_resent = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_RETRANSMITTED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&naks_resent, sizeof(naks_resent) ); - } - break; - -/* COLUMN_PGMRECEIVERPARITYNAKSFAILED + COLUMN_PGMRECEIVERSELECTIVENAKSFAILED */ - case COLUMN_PGMRECEIVERNAKSFAILED: - { - const unsigned naks_failed = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_FAILED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&naks_failed, sizeof(naks_failed) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMRECEIVERPARITYNAKSFAILED: - { - const unsigned parity_failed = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&parity_failed, sizeof(parity_failed) ); - } - break; - - case COLUMN_PGMRECEIVERSELECTIVENAKSFAILED: - { - const unsigned naks_failed = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_FAILED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&naks_failed, sizeof(naks_failed) ); - } - break; - - case COLUMN_PGMRECEIVERNAKSFAILEDRXWADVANCED: - { - const unsigned rxw_failed = peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_RXW_ADVANCED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&rxw_failed, sizeof(rxw_failed) ); - } - break; - - case COLUMN_PGMRECEIVERNAKSFALEDNCFRETRIESEXCEEDED: - { - const unsigned ncf_retries = peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_NCF_RETRIES_EXCEEDED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&ncf_retries, sizeof(ncf_retries) ); - } - break; - - case COLUMN_PGMRECEIVERNAKSFAILEDDATARETRIESEXCEEDED: - { - const unsigned data_retries = peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_DATA_RETRIES_EXCEEDED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&data_retries, sizeof(data_retries) ); - } - break; - -/* FIXED: 0 - absolutely no idea what this means */ - case COLUMN_PGMRECEIVERNAKSFAILEDGENEXPIRED: - { - const unsigned happy_pandas = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&happy_pandas, sizeof(happy_pandas) ); - } - break; - - case COLUMN_PGMRECEIVERNAKFAILURESDELIVERED: - { - const unsigned delivered = peer->cumulative_stats[PGM_PC_RECEIVER_NAK_FAILURES_DELIVERED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&delivered, sizeof(delivered) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMRECEIVERPARITYNAKSSUPPRESSED: - { - const unsigned suppressed = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&suppressed, sizeof(suppressed) ); - } - break; - - case COLUMN_PGMRECEIVERSELECTIVENAKSSUPPRESSED: - { - const unsigned suppressed = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&suppressed, sizeof(suppressed) ); - } - break; - - case COLUMN_PGMRECEIVERNAKERRORS: - { - const unsigned malformed_naks = peer->cumulative_stats[PGM_PC_RECEIVER_NAK_ERRORS]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&malformed_naks, sizeof(malformed_naks) ); - } - break; - -/* FIXED: 0 */ - case COLUMN_PGMRECEIVEROUTSTANDINGPARITYNAKS: - { - const unsigned outstanding_parity = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&outstanding_parity, sizeof(outstanding_parity) ); - } - break; - - case COLUMN_PGMRECEIVEROUTSTANDINGSELECTIVENAKS: - { - const unsigned outstanding_selective = window->nak_backoff_queue.length + - window->wait_ncf_queue.length + - window->wait_data_queue.length; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&outstanding_selective, sizeof(outstanding_selective) ); - } - break; - - case COLUMN_PGMRECEIVERLASTACTIVITY: - { - union { - unsigned uint_value; - time_t time_t_value; - } last_activity; - pgm_time_since_epoch (&peer->last_packet, &last_activity.time_t_value); - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&last_activity.uint_value, sizeof(last_activity.uint_value) ); - } - break; - - case COLUMN_PGMRECEIVERNAKSVCTIMEMIN: - { - const unsigned min_repair_time = window->min_fill_time; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&min_repair_time, sizeof(min_repair_time) ); - } - break; - - case COLUMN_PGMRECEIVERNAKSVCTIMEMEAN: - { - const unsigned mean_repair_time = peer->cumulative_stats[PGM_PC_RECEIVER_NAK_SVC_TIME_MEAN]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&mean_repair_time, sizeof(mean_repair_time) ); - } - break; - - case COLUMN_PGMRECEIVERNAKSVCTIMEMAX: - { - const unsigned max_repair_time = window->max_fill_time; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&max_repair_time, sizeof(max_repair_time) ); - } - break; - - case COLUMN_PGMRECEIVERNAKFAILTIMEMIN: - { - const unsigned min_fail_time = peer->min_fail_time; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&min_fail_time, sizeof(min_fail_time) ); - } - break; - - case COLUMN_PGMRECEIVERNAKFAILTIMEMEAN: - { - const unsigned mean_fail_time = peer->cumulative_stats[PGM_PC_RECEIVER_NAK_FAIL_TIME_MEAN]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&mean_fail_time, sizeof(mean_fail_time) ); - } - break; - - case COLUMN_PGMRECEIVERNAKFAILTIMEMAX: - { - const unsigned max_fail_time = peer->max_fail_time; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&max_fail_time, sizeof(max_fail_time) ); - } - break; - - case COLUMN_PGMRECEIVERNAKTRANSMITMIN: - { - const unsigned min_transmit_count = window->min_nak_transmit_count; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&min_transmit_count, sizeof(min_transmit_count) ); - } - break; - - case COLUMN_PGMRECEIVERNAKTRANSMITMEAN: - { - const unsigned mean_transmit_count = peer->cumulative_stats[PGM_PC_RECEIVER_TRANSMIT_MEAN]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&mean_transmit_count, sizeof(mean_transmit_count) ); - } - break; - - case COLUMN_PGMRECEIVERNAKTRANSMITMAX: - { - const unsigned max_transmit_count = window->max_nak_transmit_count; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&max_transmit_count, sizeof(max_transmit_count) ); - } - break; - - case COLUMN_PGMRECEIVERACKSSENT: - { - const unsigned acks_sent = peer->cumulative_stats[PGM_PC_RECEIVER_ACKS_SENT]; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&acks_sent, sizeof(acks_sent) ); - } - break; - - case COLUMN_PGMRECEIVERRXWTRAIL: - { - const unsigned rxw_trail = window->rxw_trail; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&rxw_trail, sizeof(rxw_trail) ); - } - break; - - case COLUMN_PGMRECEIVERRXWLEAD: - { - const unsigned rxw_lead = window->lead; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&rxw_lead, sizeof(rxw_lead) ); - } - break; - -/* TODO: traps */ - case COLUMN_PGMRECEIVERNAKFAILURESLASTINTERVAL: - case COLUMN_PGMRECEIVERLASTINTERVALNAKFAILURES: - { - const unsigned failures = 0; - snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ - (const u_char*)&failures, sizeof(failures) ); - } - break; - - default: - snmp_log (LOG_ERR, "pgmReceiverTable_handler: unknown column.\n"); - break; - } - } - break; - - case MODE_SET_RESERVE1: - default: - snmp_log (LOG_ERR, "pgmReceiverTable_handler: unsupported mode.\n"); - break; - - } - - return SNMP_ERR_NOERROR; -} - -/* - * SNMP TRAPS - */ - -int -send_pgmStart_trap (void) -{ - pgm_debug ("send_pgmStart_trap ()"); - - netsnmp_variable_list *var_list = NULL; - static const oid pgmStart_oid[] = { 1,3,6,1,3,112,2,0,1 }; - -/* - * Set the snmpTrapOid.0 value - */ - snmp_varlist_add_variable (&var_list, - snmptrap_oid, OID_LENGTH( snmptrap_oid ), - ASN_OBJECT_ID, - (const u_char*)pgmStart_oid, sizeof(pgmStart_oid)); -/* - * Add any extra (optional) objects here - */ - -/* - * Send the trap to the list of configured destinations - * and clean up - */ - send_v2trap (var_list); - snmp_free_varbind (var_list); - return SNMP_ERR_NOERROR; -} - -int -send_pgmStop_trap (void) -{ - pgm_debug ("send_pgmStop_trap ()"); - - netsnmp_variable_list *var_list = NULL; - static const oid pgmStop_oid[] = { 1,3,6,1,3,112,2,0,2 }; - -/* - * Set the snmpTrapOid.0 value - */ - snmp_varlist_add_variable (&var_list, - snmptrap_oid, OID_LENGTH(snmptrap_oid), - ASN_OBJECT_ID, - (const u_char*)pgmStop_oid, sizeof(pgmStop_oid)); - - -/* - * Add any extra (optional) objects here - */ - -/* - * Send the trap to the list of configured destinations - * and clean up - */ - send_v2trap (var_list); - snmp_free_varbind (var_list); - return SNMP_ERR_NOERROR; -} - -int -send_pgmNewSourceTrap_trap (void) -{ - pgm_debug ("send_pgmNewSourceTrap_trap ()"); - - netsnmp_variable_list *var_list = NULL; - static const oid pgmNewSourceTrap_oid[] = { 1,3,6,1,3,112,2,0,3 }; - static const oid pgmSourceSourceGsi_oid[] = { 1,3,6,1,3,112,1,2,100,2,1,6, /* insert index here */ }; - static const oid pgmSourceSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,2,100,2,1,7, /* insert index here */ }; - -/* - * Set the snmpTrapOid.0 value - */ - snmp_varlist_add_variable (&var_list, - snmptrap_oid, OID_LENGTH(snmptrap_oid), - ASN_OBJECT_ID, - (const u_char*)pgmNewSourceTrap_oid, sizeof(pgmNewSourceTrap_oid)); -/* - * Add any objects from the trap definition - */ - snmp_varlist_add_variable (&var_list, - pgmSourceSourceGsi_oid, OID_LENGTH(pgmSourceSourceGsi_oid), - ASN_OCTET_STR, -/* Set an appropriate value for pgmSourceSourceGsi */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmSourceSourcePortNumber_oid, OID_LENGTH(pgmSourceSourcePortNumber_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmSourceSourcePortNumber */ - NULL, 0); -/* - * Add any extra (optional) objects here - */ - -/* - * Send the trap to the list of configured destinations - * and clean up - */ - send_v2trap (var_list); - snmp_free_varbind (var_list); - return SNMP_ERR_NOERROR; -} - -int -send_pgmClosedSourceTrap_trap (void) -{ - pgm_debug ("send_pgmClosedSourceTrap_trap ()"); - - netsnmp_variable_list *var_list = NULL; - static const oid pgmClosedSourceTrap_oid[] = { 1,3,6,1,3,112,2,0,4 }; - static const oid pgmSourceSourceGsi_oid[] = { 1,3,6,1,3,112,1,2,100,2,1,6, /* insert index here */ }; - static const oid pgmSourceSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,2,100,2,1,7, /* insert index here */ }; - -/* - * Set the snmpTrapOid.0 value - */ - snmp_varlist_add_variable (&var_list, - snmptrap_oid, OID_LENGTH(snmptrap_oid), - ASN_OBJECT_ID, - (const u_char*)pgmClosedSourceTrap_oid, sizeof(pgmClosedSourceTrap_oid)); -/* - * Add any objects from the trap definition - */ - snmp_varlist_add_variable (&var_list, - pgmSourceSourceGsi_oid, OID_LENGTH(pgmSourceSourceGsi_oid), - ASN_OCTET_STR, -/* Set an appropriate value for pgmSourceSourceGsi */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmSourceSourcePortNumber_oid, OID_LENGTH(pgmSourceSourcePortNumber_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmSourceSourcePortNumber */ - NULL, 0); -/* - * Add any extra (optional) objects here - */ - -/* - * Send the trap to the list of configured destinations - * and clean up - */ - send_v2trap (var_list); - snmp_free_varbind (var_list); - return SNMP_ERR_NOERROR; -} - -int -send_pgmNewReceiverTrap_trap (void) -{ - pgm_debug ("send_pgmNewReceiverTrap_trap ()"); - - netsnmp_variable_list *var_list = NULL; - static const oid pgmNewReceiverTrap_oid[] = { 1,3,6,1,3,112,2,0,5 }; - static const oid pgmReceiverSourceGsi_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,8, /* insert index here */ }; - static const oid pgmReceiverSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,9, /* insert index here */ }; - static const oid pgmReceiverUniqueInstance_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,10, /* insert index here */ }; - -/* - * Set the snmpTrapOid.0 value - */ - snmp_varlist_add_variable (&var_list, - snmptrap_oid, OID_LENGTH(snmptrap_oid), - ASN_OBJECT_ID, - (const u_char*)pgmNewReceiverTrap_oid, sizeof(pgmNewReceiverTrap_oid)); -/* - * Add any objects from the trap definition - */ - snmp_varlist_add_variable (&var_list, - pgmReceiverSourceGsi_oid, OID_LENGTH(pgmReceiverSourceGsi_oid), - ASN_OCTET_STR, -/* Set an appropriate value for pgmReceiverSourceGsi */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmReceiverSourcePortNumber_oid, OID_LENGTH(pgmReceiverSourcePortNumber_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmReceiverSourcePortNumber */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmReceiverUniqueInstance_oid, OID_LENGTH(pgmReceiverUniqueInstance_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmReceiverUniqueInstance */ - NULL, 0); -/* - * Add any extra (optional) objects here - */ - -/* - * Send the trap to the list of configured destinations - * and clean up - */ - send_v2trap (var_list); - snmp_free_varbind (var_list); - return SNMP_ERR_NOERROR; -} - -int -send_pgmClosedReceiverTrap_trap (void) -{ - pgm_debug ("send_pgmClosedReceiverTrap_trap ()"); - - netsnmp_variable_list *var_list = NULL; - static const oid pgmClosedReceiverTrap_oid[] = { 1,3,6,1,3,112,2,0,6 }; - static const oid pgmReceiverSourceGsi_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,8, /* insert index here */ }; - static const oid pgmReceiverSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,9, /* insert index here */ }; - static const oid pgmReceiverUniqueInstance_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,10, /* insert index here */ }; - -/* - * Set the snmpTrapOid.0 value - */ - snmp_varlist_add_variable (&var_list, - snmptrap_oid, OID_LENGTH(snmptrap_oid), - ASN_OBJECT_ID, - (const u_char*)pgmClosedReceiverTrap_oid, sizeof(pgmClosedReceiverTrap_oid)); -/* - * Add any objects from the trap definition - */ - snmp_varlist_add_variable (&var_list, - pgmReceiverSourceGsi_oid, OID_LENGTH(pgmReceiverSourceGsi_oid), - ASN_OCTET_STR, -/* Set an appropriate value for pgmReceiverSourceGsi */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmReceiverSourcePortNumber_oid, OID_LENGTH(pgmReceiverSourcePortNumber_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmReceiverSourcePortNumber */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmReceiverUniqueInstance_oid, OID_LENGTH(pgmReceiverUniqueInstance_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmReceiverUniqueInstance */ - NULL, 0); -/* - * Add any extra (optional) objects here - */ - -/* - * Send the trap to the list of configured destinations - * and clean up - */ - send_v2trap (var_list); - snmp_free_varbind (var_list); - return SNMP_ERR_NOERROR; -} - -int -send_pgmNakFailuresTrap_trap (void) -{ - pgm_debug ("send_pgmNakFailuresTrap_trap ()"); - - netsnmp_variable_list *var_list = NULL; - static const oid pgmNakFailuresTrap_oid[] = { 1,3,6,1,3,112,2,0,7 }; - static const oid pgmReceiverSourceGsi_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,8, /* insert index here */ }; - static const oid pgmReceiverSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,9, /* insert index here */ }; - static const oid pgmReceiverUniqueInstance_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,10, /* insert index here */ }; - static const oid pgmReceiverNakFailureThresholdTimer_oid[] = { 1,3,6,1,3,112,1,3,100,3,1,14, /* insert index here */ }; - static const oid pgmReceiverNakFailureThreshold_oid[] = { 1,3,6,1,3,112,1,3,100,3,1,15, /* insert index here */ }; - static const oid pgmReceiverNakFailuresLastInterval_oid[] = { 1,3,6,1,3,112,1,3,100,4,1,56, /* insert index here */ }; - static const oid pgmReceiverLastIntervalNakFailures_oid[] = { 1,3,6,1,3,112,1,3,100,4,1,57, /* insert index here */ }; - -/* - * Set the snmpTrapOid.0 value - */ - snmp_varlist_add_variable (&var_list, - snmptrap_oid, OID_LENGTH(snmptrap_oid), - ASN_OBJECT_ID, - (const u_char*)pgmNakFailuresTrap_oid, sizeof(pgmNakFailuresTrap_oid)); -/* - * Add any objects from the trap definition - */ - snmp_varlist_add_variable (&var_list, - pgmReceiverSourceGsi_oid, OID_LENGTH(pgmReceiverSourceGsi_oid), - ASN_OCTET_STR, -/* Set an appropriate value for pgmReceiverSourceGsi */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmReceiverSourcePortNumber_oid, OID_LENGTH(pgmReceiverSourcePortNumber_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmReceiverSourcePortNumber */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmReceiverUniqueInstance_oid, OID_LENGTH(pgmReceiverUniqueInstance_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmReceiverUniqueInstance */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmReceiverNakFailureThresholdTimer_oid, OID_LENGTH(pgmReceiverNakFailureThresholdTimer_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmReceiverNakFailureThresholdTimer */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmReceiverNakFailureThreshold_oid, OID_LENGTH(pgmReceiverNakFailureThreshold_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmReceiverNakFailureThreshold */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmReceiverNakFailuresLastInterval_oid, OID_LENGTH(pgmReceiverNakFailuresLastInterval_oid), - ASN_COUNTER, -/* Set an appropriate value for pgmReceiverNakFailuresLastInterval */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmReceiverLastIntervalNakFailures_oid, OID_LENGTH(pgmReceiverLastIntervalNakFailures_oid), - ASN_COUNTER, -/* Set an appropriate value for pgmReceiverLastIntervalNakFailures */ - NULL, 0); -/* - * Add any extra (optional) objects here - */ - -/* - * Send the trap to the list of configured destinations - * and clean up - */ - send_v2trap (var_list); - snmp_free_varbind (var_list); - return SNMP_ERR_NOERROR; -} - -int -send_pgmNewDlrSourceTrap_trap (void) -{ - pgm_debug ("send_pgmNewDlrSourceTrap_trap ()"); - - netsnmp_variable_list *var_list = NULL; - static const oid pgmNewDlrSourceTrap_oid[] = { 1,3,6,1,3,112,2,0,8 }; - static const oid pgmDlrSourceSourceGsi_oid[] = { 1,3,6,1,3,112,1,4,100,2,1,4, /* insert index here */ }; - static const oid pgmDlrSourceSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,4,100,2,1,5, /* insert index here */ }; - -/* - * Set the snmpTrapOid.0 value - */ - snmp_varlist_add_variable (&var_list, - snmptrap_oid, OID_LENGTH(snmptrap_oid), - ASN_OBJECT_ID, - (const u_char*)pgmNewDlrSourceTrap_oid, sizeof(pgmNewDlrSourceTrap_oid)); -/* - * Add any objects from the trap definition - */ - snmp_varlist_add_variable (&var_list, - pgmDlrSourceSourceGsi_oid, OID_LENGTH(pgmDlrSourceSourceGsi_oid), - ASN_OCTET_STR, -/* Set an appropriate value for pgmDlrSourceSourceGsi */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmDlrSourceSourcePortNumber_oid, OID_LENGTH(pgmDlrSourceSourcePortNumber_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmDlrSourceSourcePortNumber */ - NULL, 0); -/* - * Add any extra (optional) objects here - */ - -/* - * Send the trap to the list of configured destinations - * and clean up - */ - send_v2trap (var_list); - snmp_free_varbind (var_list); - return SNMP_ERR_NOERROR; -} - -int -send_pgmClosedDlrSourceTrap_trap (void) -{ - pgm_debug ("send_pgmClosedDlrSourceTrap_trap ()"); - - netsnmp_variable_list *var_list = NULL; - static const oid pgmClosedDlrSourceTrap_oid[] = { 1,3,6,1,3,112,2,0,9 }; - static const oid pgmDlrSourceSourceGsi_oid[] = { 1,3,6,1,3,112,1,4,100,2,1,4, /* insert index here */ }; - static const oid pgmDlrSourceSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,4,100,2,1,5, /* insert index here */ }; - -/* - * Set the snmpTrapOid.0 value - */ - snmp_varlist_add_variable (&var_list, - snmptrap_oid, OID_LENGTH(snmptrap_oid), - ASN_OBJECT_ID, - (const u_char*)pgmClosedDlrSourceTrap_oid, sizeof(pgmClosedDlrSourceTrap_oid)); - -/* - * Add any objects from the trap definition - */ - snmp_varlist_add_variable (&var_list, - pgmDlrSourceSourceGsi_oid, OID_LENGTH(pgmDlrSourceSourceGsi_oid), - ASN_OCTET_STR, -/* Set an appropriate value for pgmDlrSourceSourceGsi */ - NULL, 0); - snmp_varlist_add_variable (&var_list, - pgmDlrSourceSourcePortNumber_oid, OID_LENGTH(pgmDlrSourceSourcePortNumber_oid), - ASN_UNSIGNED, -/* Set an appropriate value for pgmDlrSourceSourcePortNumber */ - NULL, 0); -/* - * Add any extra (optional) objects here - */ - -/* - * Send the trap to the list of configured destinations - * and clean up - */ - send_v2trap (var_list); - snmp_free_varbind (var_list); - return SNMP_ERR_NOERROR; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/pgmMIB_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/pgmMIB_unittest.c deleted file mode 100644 index 4cb4672..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/pgmMIB_unittest.c +++ /dev/null @@ -1,257 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for PGM MIB routines. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include - - -/* mock state */ - -static GStaticRWLock mock_pgm_transport_list_lock = G_STATIC_RW_LOCK_INIT; -static GSList* mock_pgm_transport_list = NULL; - - -/* mock functions for external references */ - -static -netsnmp_handler_registration* -mock_netsnmp_create_handler_registration ( - const char* name, - Netsnmp_Node_Handler* handler_access_method, - oid* reg_oid, - size_t reg_oid_len, - int modes - ) -{ - netsnmp_handler_registration* handler = g_malloc0 (sizeof(netsnmp_handler_registration)); - return handler; -} - -static -void -mock_netsnmp_handler_registration_free ( - netsnmp_handler_registration* handler - ) -{ - g_assert (NULL != handler); - g_free (handler); -} - -static -void -mock_netsnmp_table_helper_add_indexes ( - netsnmp_table_registration_info* tinfo, - ... - ) -{ -} - -static -int -mock_netsnmp_register_table_iterator ( - netsnmp_handler_registration* reginfo, - netsnmp_iterator_info* iinfo - ) -{ - return MIB_REGISTERED_OK; -} - -static -int -mock_netsnmp_set_request_error ( - netsnmp_agent_request_info* reqinfo, - netsnmp_request_info* request, - int error_value - ) -{ - return 0; -} - -static -void* -mock_netsnmp_extract_iterator_context ( - netsnmp_request_info* reqinfo - ) -{ - return (void*)0x1; -} - -static -netsnmp_table_request_info* -mock_netsnmp_extract_table_info ( - netsnmp_request_info* reqinfo - ) -{ - return NULL; -} - -static -int -mock_snmp_set_var_typed_value ( - netsnmp_variable_list* newvar, - u_char type, - const u_char* val_str, - size_t val_len - ) -{ - return 0; -} - -static -netsnmp_variable_list* -mock_snmp_varlist_add_variable ( - netsnmp_variable_list** varlist, - const oid* oid, - size_t name_length, - u_char type, - const u_char* value, - size_t len - ) -{ - return NULL; -} - -static -void -mock_snmp_free_varbind ( - netsnmp_variable_list* var - ) -{ -} - -static -void -mock_snmp_free_var ( - netsnmp_variable_list* var - ) -{ -} - -static -int -mock_snmp_log ( - int priority, - const char* format, - ... - ) -{ - return 0; -} - -static -void -mock_send_v2trap ( - netsnmp_variable_list* var - ) -{ -} - -/** time module */ - -static -void -mock_pgm_time_since_epoch ( - pgm_time_t* pgm_time_t_time, - time_t* time_t_time - ) -{ - *time_t_time = pgm_to_secs (*pgm_time_t_time + 0); -} - - -#define netsnmp_create_handler_registration mock_netsnmp_create_handler_registration -#define netsnmp_handler_registration_free mock_netsnmp_handler_registration_free -#define netsnmp_table_helper_add_indexes mock_netsnmp_table_helper_add_indexes -#define netsnmp_register_table_iterator mock_netsnmp_register_table_iterator -#define netsnmp_set_request_error mock_netsnmp_set_request_error -#define netsnmp_extract_iterator_context mock_netsnmp_extract_iterator_context -#define netsnmp_extract_table_info mock_netsnmp_extract_table_info -#define snmp_set_var_typed_value mock_snmp_set_var_typed_value -#define snmp_varlist_add_variable mock_snmp_varlist_add_variable -#define snmp_free_varbind mock_snmp_free_varbind -#define snmp_free_var mock_snmp_free_var -#define snmp_log mock_snmp_log -#define send_v2trap mock_send_v2trap -#define pgm_transport_list mock_pgm_transport_list -#define pgm_transport_list_lock mock_pgm_transport_list_lock -#define pgm_time_since_epoch mock_pgm_time_since_epoch - -#define PGMMIB_DEBUG -#include "pgmMIB.c" - - -/* target: - * gboolean - * pgm_mib_init ( - * GError** error - * ) - */ - -START_TEST (test_init_pass_001) -{ - GError* err = NULL; - fail_unless (TRUE == pgm_mib_init (&err)); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_init = tcase_create ("init"); - suite_add_tcase (s, tc_init); - tcase_add_test (tc_init, test_init_pass_001); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/plan.txt b/3rdparty/openpgm-svn-r1085/pgm/plan.txt deleted file mode 100644 index b1747ae..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/plan.txt +++ /dev/null @@ -1,238 +0,0 @@ -pgmdump -------- - -View all packets like tcpdump, but updated to full spec and allow dump of payload. - - -pgmtop ------- - -Dump realtime packet statistics in a ncurses display, mix of top/htop/netop. - - -basic_send ----------- - -Send an ODATA packet and terminate. - -Accept string payload and network parameters on command line. - -Send to multicast or send to unicast AFI. - -IPv4/6. - -Define optional session start, late join tags. - - -spm_idle --------- - -Idle in an event loop sending out SPM packets. - - -stream_send ------------ - -Send a constant stream of ODATA and SPM packets. - - -basic_http ----------- - -Simple embedded web server - - -basic_recv ----------- - -Listen to packets indicating data loss, view details through web interface. - - -basic_container ---------------- - -Test performance of glib containers for fast allocating for a dynamic transmit window. - - -basic_txw ---------- - -Test performance of a basic transmit window implementation. - - -nak_txw -------- - -Test performance of random access to packets inside the window. - - -stream_send_with_nak --------------------- - -Respond to NAK's with RDATA. - - -basic_recv_with_nak -------------------- - -Listen to packets and send NAK's to rebuild data. - - -dumpif ------- - -Display all IP based interfaces and basic details. - - -testif ------- - -Test various combinations of network specification. - - -sw_calc -------- - -Basic calculation tests of wrap-around sliding windows and a leading edge. - - -basic_recv_with_rxw -------------------- - -Listen to packets buffered with a receive window. - - -test_cpu_timers ---------------- - -Calculate drift between processors, cores, and hyper-threads. - - -pgmsend --------- - -basic_send updated to use transmit window. - - -pgmrecv --------- - -basic_recv_with_rxw without web interface, primary displays messages from pgmsend. - - -syncrecv --------- - -pgmrecv implemented outside GLib with a synchronous coding paradigm. - - -pgmping -------- - -Dual mode: one to send fixed messages like pgmsend and listen for response, two to listen for -messages and reply. - - -block_send ----------- - -Send APDUs over ODATA. - - -(pgmrecv can receive APDUs) - -test_rs -------- - -Test 8-bit symbol Reed Solomon encoding and decoding with errors & erasures. - -test_fec --------- - -Test fec creation and recovery. - - -send_with_fec --------------------- - -Send APDUs over ODATA with FEC. - - - -Scenarios to reproduce -********************** - -- Packet loss in stream causing NAK generation. -- Link saturation in sending causing API feedback. -- Link peak stable speed. -- Maxium NAK generation to determine NCF/RDATA throughput. -- Corrupt packets with invalid IP checksum (? generate IP HDR in sender) -- Corrupt packets with invalid PGM checksum. -- Invalid packet values. -- NAK to NCF latency. -- NAK to RDATA latency. -- Publish bandwidth: total, per packet type, payload, per recipient (?) -- Subscribe bandwidth: total, per packet type, payload, per publisher (?) -- Restarting a session with similar or dissimilar sequence numbering. - -Outstanding questions -********************* - -- Is it faster to use chunks containing multiple packets instead of one MTU - per packet. Does aligning with system page size matter? -- Can g_timers be dropped easily for gettimeofday and avoid floating point math? Possible - to pass timer upstream with contiguous data for easy access. -- Can time evaluation be dropped to at most once per main loop event? -- Does code work 32 bit and is it optimal? -- Should trash stacks be monitored and controlled externally? For example, clearing - up after bursts or administrative control. -- Should trash stacks have a upper limit to then free to the slice allocator? -- Should lost packets be managed as ranges or individual sequence numbers, how - does each method affect performance? - -* The initial draft of PGM included OPT_RANGE option for NAKs to specify a range of lost - packets, this was replaced in the final draft with NAK lists. Some research hints that - ranges are suitable: - - http://www.isoc.org/inet2001/CD_proceedings/T54/T54.htm - http://tools.ietf.org/html/draft-speakman-pgm-spec-01 - -- Are place holders necessary? Can state timeouts be managed without a per sequence number - object? For example by the next data object, or an extra object for an ncf extended window: - note that nak packet generation should easily dwarfs time spent unless advantage is taken - of the additional 62 naks in a opt_nak_list. Caution has to be taken with the cost of - splitting a range when a packet is inserted in the middle, although idealy it should - be sequential from the trailing edge. -- Is it better to have send sockets per transport, or shared, bound to each interface? -- Cost of sharing state helper lists between receive windows? On culling a peer the lists - have to be purged. Saves iterating the hash list of receivers. -- Encapsulated UDP lists two ports, 3305 for broadcast, 3306 for unicast, how is this - supposed to map to regular PGM, and why the split? - -Basic TODO list -*************** - -- Ensure standardised error handling and status reporting. -- Implement mechanism for data-loss feedback. -- OPT_SYN & OPT_FIN on sending side. -- Shared trash stacks between multiple receive windows (contexts). -- Shared trash stacks between transmit and receive windows. -- FEC: compatibility with SmartPGM FEC, MS FEC? -- NAK backoff learning. -- Full conformance testing. (nak backoffs remaining) -- Unit testing. -- System testing with valgrind. -- Performance testing with oprofile. -- Basic DLR. -- Implement PGM sender (only) support thread? -- eventfd instead of pipes for recent Linux kernels. - -Optionals -********* - -- Some form of broadcast statistics for passive monitoring. -- (fix) BCH Reed-Solomon codec as possibly faster alternative, albeit incompatible with Microsoft. -- Recommendations as per the RMT working group of the IETF for AL-FEC codecs: Raptor codes, LDPC- - staircase and LDPC-triangle codes. -- XDR based messaging format as example of binary encoded messaging. - diff --git a/3rdparty/openpgm-svn-r1085/pgm/queue.c b/3rdparty/openpgm-svn-r1085/pgm/queue.c deleted file mode 100644 index 351c7ef..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/queue.c +++ /dev/null @@ -1,110 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable double-ended queue. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - - -//#define QUEUE_DEBUG - -bool -pgm_queue_is_empty ( - const pgm_queue_t*const queue - ) -{ - pgm_return_val_if_fail (queue != NULL, TRUE); - - return queue->head == NULL; -} - -void -pgm_queue_push_head_link ( - pgm_queue_t* restrict queue, - pgm_list_t* restrict head_link - ) -{ - pgm_return_if_fail (queue != NULL); - pgm_return_if_fail (head_link != NULL); - pgm_return_if_fail (head_link->prev == NULL); - pgm_return_if_fail (head_link->next == NULL); - - head_link->next = queue->head; - if (queue->head) - queue->head->prev = head_link; - else - queue->tail = head_link; - queue->head = head_link; - queue->length++; -} - -pgm_list_t* -pgm_queue_pop_tail_link ( - pgm_queue_t* queue - ) -{ - pgm_return_val_if_fail (queue != NULL, NULL); - - if (queue->tail) - { - pgm_list_t *node = queue->tail; - - queue->tail = node->prev; - if (queue->tail) - { - queue->tail->next = NULL; - node->prev = NULL; - } - else - queue->head = NULL; - queue->length--; - - return node; - } - - return NULL; -} - -pgm_list_t* -pgm_queue_peek_tail_link ( - pgm_queue_t* queue - ) -{ - pgm_return_val_if_fail (queue != NULL, NULL); - - return queue->tail; -} - -void -pgm_queue_unlink ( - pgm_queue_t* restrict queue, - pgm_list_t* restrict target_link - ) -{ - pgm_return_if_fail (queue != NULL); - pgm_return_if_fail (target_link != NULL); - - if (target_link == queue->tail) - queue->tail = queue->tail->prev; - - queue->head = pgm_list_remove_link (queue->head, target_link); - queue->length--; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/rand.c b/3rdparty/openpgm-svn-r1085/pgm/rand.c deleted file mode 100644 index 91b71eb..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/rand.c +++ /dev/null @@ -1,137 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable weak pseudo-random generator. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _WIN32 -# include -# include -#endif -#include - - -//#define RAND_DEBUG - - -/* locals */ - -static pgm_rand_t global_rand = { .seed = 0 }; -static volatile uint32_t rand_ref_count = 0; -static pgm_mutex_t rand_mutex; - - -void -pgm_rand_init (void) -{ - if (pgm_atomic_exchange_and_add32 (&rand_ref_count, 1) > 0) - return; - - pgm_mutex_init (&rand_mutex); -} - -void -pgm_rand_shutdown (void) -{ - pgm_return_if_fail (pgm_atomic_read32 (&rand_ref_count) > 0); - - if (pgm_atomic_exchange_and_add32 (&rand_ref_count, (uint32_t)-1) != 1) - return; - - pgm_mutex_free (&rand_mutex); -} - -void -pgm_rand_create ( - pgm_rand_t* new_rand - ) -{ -/* pre-conditions */ - pgm_assert (NULL != new_rand); - -#ifndef _WIN32 -/* attempt to read seed from kernel - */ - FILE* fp; - do { - fp = fopen ("/dev/urandom", "rb"); - } while (PGM_UNLIKELY(EINTR == errno)); - if (fp) { - size_t items_read; - do { - items_read = fread (&new_rand->seed, sizeof(new_rand->seed), 1, fp); - } while (PGM_UNLIKELY(EINTR == errno)); - fclose (fp); - if (1 == items_read) - return; - } -#endif /* !_WIN32 */ - const pgm_time_t now = pgm_time_update_now(); - new_rand->seed = (uint32_t)pgm_to_msecs (now); -} - -/* derived from POSIX.1-2001 example implementation of rand() - */ - -uint32_t -pgm_rand_int ( - pgm_rand_t* r - ) -{ -/* pre-conditions */ - pgm_assert (NULL != r); - - r->seed = r->seed * 1103515245 + 12345; - return r->seed; -} - -int32_t -pgm_rand_int_range ( - pgm_rand_t* r, - int32_t begin, - int32_t end - ) -{ -/* pre-conditions */ - pgm_assert (NULL != r); - - return begin + pgm_rand_int (r) % (end - begin); -} - -uint32_t -pgm_random_int (void) -{ - pgm_mutex_lock (&rand_mutex); - if (PGM_UNLIKELY(!global_rand.seed)) - pgm_rand_create (&global_rand); - const uint32_t rand_value = pgm_rand_int (&global_rand); - pgm_mutex_unlock (&rand_mutex); - return rand_value; -} - -int32_t -pgm_random_int_range ( - int32_t begin, - int32_t end - ) -{ - const uint32_t rand_value = pgm_random_int(); - return begin + rand_value % (end - begin); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/rate_control.c b/3rdparty/openpgm-svn-r1085/pgm/rate_control.c deleted file mode 100644 index 2baceeb..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/rate_control.c +++ /dev/null @@ -1,158 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Rate regulation. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - - -/* create machinery for rate regulation. - * the rate_per_sec is ammortized over millisecond time periods. - * - * NB: bucket MUST be memset 0 before calling. - */ - -void -pgm_rate_create ( - pgm_rate_t* bucket, - const ssize_t rate_per_sec, /* 0 = disable */ - const size_t iphdr_len, - const uint16_t max_tpdu - ) -{ -/* pre-conditions */ - pgm_assert (NULL != bucket); - pgm_assert (rate_per_sec >= max_tpdu); - - bucket->rate_per_sec = rate_per_sec; - bucket->iphdr_len = iphdr_len; - bucket->last_rate_check = pgm_time_update_now (); -/* pre-fill bucket */ - if ((rate_per_sec / 1000) >= max_tpdu) { - bucket->rate_per_msec = bucket->rate_per_sec / 1000; - bucket->rate_limit = bucket->rate_per_msec; - } else { - bucket->rate_limit = bucket->rate_per_sec; - } - pgm_spinlock_init (&bucket->spinlock); -} - -void -pgm_rate_destroy ( - pgm_rate_t* bucket - ) -{ -/* pre-conditions */ - pgm_assert (NULL != bucket); - - pgm_spinlock_free (&bucket->spinlock); -} - -/* check bit bucket whether an operation can proceed or should wait. - * - * returns TRUE when leaky bucket permits unless non-blocking flag is set. - * returns FALSE if operation should block and non-blocking flag is set. - */ - -bool -pgm_rate_check ( - pgm_rate_t* bucket, - const size_t data_size, - const bool is_nonblocking - ) -{ - int new_rate_limit; - -/* pre-conditions */ - pgm_assert (NULL != bucket); - pgm_assert (data_size > 0); - - if (0 == bucket->rate_per_sec) - return TRUE; - - pgm_spinlock_lock (&bucket->spinlock); - pgm_time_t now = pgm_time_update_now(); - pgm_time_t time_since_last_rate_check = now - bucket->last_rate_check; - - if (bucket->rate_per_msec) - { - if (time_since_last_rate_check > pgm_msecs(1)) - new_rate_limit = bucket->rate_per_msec; - else { - new_rate_limit = bucket->rate_limit + ((bucket->rate_per_msec * time_since_last_rate_check) / 1000UL); - if (new_rate_limit > bucket->rate_per_msec) - new_rate_limit = bucket->rate_per_msec; - } - } - else - { - if (time_since_last_rate_check > pgm_secs(1)) - new_rate_limit = bucket->rate_per_sec; - else { - new_rate_limit = bucket->rate_limit + ((bucket->rate_per_sec * time_since_last_rate_check) / 1000000UL); - if (new_rate_limit > bucket->rate_per_sec) - new_rate_limit = bucket->rate_per_sec; - } - } - - new_rate_limit -= ( bucket->iphdr_len + data_size ); - if (is_nonblocking && new_rate_limit < 0) { - pgm_spinlock_unlock (&bucket->spinlock); - return FALSE; - } - - bucket->rate_limit = new_rate_limit; - bucket->last_rate_check = now; - if (bucket->rate_limit < 0) { - int sleep_amount; - do { - pgm_thread_yield(); - now = pgm_time_update_now(); - time_since_last_rate_check = now - bucket->last_rate_check; - sleep_amount = pgm_to_secs (bucket->rate_per_sec * time_since_last_rate_check); - } while (sleep_amount + bucket->rate_limit < 0); - bucket->rate_limit += sleep_amount; - bucket->last_rate_check = now; - } - pgm_spinlock_unlock (&bucket->spinlock); - return TRUE; -} - -pgm_time_t -pgm_rate_remaining ( - pgm_rate_t* bucket, - const size_t n - ) -{ -/* pre-conditions */ - pgm_assert (NULL != bucket); - - if (PGM_UNLIKELY(0 == bucket->rate_per_sec)) - return 0; - - pgm_spinlock_lock (&bucket->spinlock); - const pgm_time_t now = pgm_time_update_now(); - const pgm_time_t time_since_last_rate_check = now - bucket->last_rate_check; - const int bucket_bytes = bucket->rate_limit + pgm_to_secs (bucket->rate_per_sec * time_since_last_rate_check) - n; - pgm_spinlock_unlock (&bucket->spinlock); - - return bucket_bytes >= 0 ? 0 : (bucket->rate_per_sec / -bucket_bytes); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/rate_control_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/rate_control_unittest.c deleted file mode 100644 index 7da5128..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/rate_control_unittest.c +++ /dev/null @@ -1,241 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for rate regulation. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include -#include -#include - - -/* mock state */ - - -#define pgm_time_now mock_pgm_time_now -#define pgm_time_update_now mock_pgm_time_update_now - -#define RATE_CONTROL_DEBUG -#include "rate_control.c" - -static pgm_time_t mock_pgm_time_now = 0x1; -static pgm_time_t _mock_pgm_time_update_now (void); -pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; - - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - -static -pgm_time_t -_mock_pgm_time_update_now (void) -{ - g_debug ("mock_pgm_time_now: %" PGM_TIME_FORMAT, mock_pgm_time_now); - return mock_pgm_time_now; -} - - -/* target: - * void - * pgm_rate_create ( - * pgm_rate_t* bucket_, - * const ssize_t rate_per_sec, - * const size_t iphdr_len, - * const uint16_t max_tpdu - * ) - */ - -START_TEST (test_create_pass_001) -{ - pgm_rate_t rate; - memset (&rate, 0, sizeof(rate)); - pgm_rate_create (&rate, 100*1000, 10, 1500); -} -END_TEST - -START_TEST (test_create_fail_001) -{ - pgm_rate_create (NULL, 0, 0, 1500); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_rate_destroy ( - * pgm_rate_t* bucket - * ) - */ - -START_TEST (test_destroy_pass_001) -{ - pgm_rate_t rate; - memset (&rate, 0, sizeof(rate)); - pgm_rate_create (&rate, 100*1000, 10, 1500); - pgm_rate_destroy (&rate); -} -END_TEST - -START_TEST (test_destroy_fail_001) -{ - pgm_rate_destroy (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_rate_check ( - * pgm_rate_t* bucket, - * const size_t data_size, - * const bool is_nonblocking - * ) - * - * 001: should use seconds resolution to allow 2 packets through then fault. - */ - -START_TEST (test_check_pass_001) -{ - pgm_rate_t rate; - memset (&rate, 0, sizeof(rate)); - pgm_rate_create (&rate, 2*1010, 10, 1500); - mock_pgm_time_now += pgm_secs(2); - fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - pgm_rate_destroy (&rate); -} -END_TEST - -START_TEST (test_check_fail_001) -{ - pgm_rate_check (NULL, 1000, FALSE); - fail ("reached"); -} -END_TEST - -/* 002: assert that only one packet should pass through small bucket - */ - -START_TEST (test_check_pass_002) -{ - pgm_rate_t rate; - memset (&rate, 0, sizeof(rate)); - pgm_rate_create (&rate, 2*900, 10, 1500); - mock_pgm_time_now += pgm_secs(2); - fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - pgm_rate_destroy (&rate); -} -END_TEST - -/* 003: millisecond resolution should initiate millisecond fills. - */ - -START_TEST (test_check_pass_003) -{ - pgm_rate_t rate; - memset (&rate, 0, sizeof(rate)); - pgm_rate_create (&rate, 2*1010*1000, 10, 1500); - mock_pgm_time_now += pgm_secs(2); - fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); -/* duplicate check at same time point */ - fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); -/* advance time causing a millisecond fill to occur */ - mock_pgm_time_now += pgm_msecs(1); - fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); -/* advance time to fill bucket enough for only one packet */ - mock_pgm_time_now += pgm_usecs(500); - fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); -/* advance time to fill the bucket a little but not enough for one packet */ - mock_pgm_time_now += pgm_usecs(100); - fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); -/* advance time a lot, should be limited to millisecond fill rate */ - mock_pgm_time_now += pgm_secs(10); - fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); - pgm_rate_destroy (&rate); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_create = tcase_create ("create"); - suite_add_tcase (s, tc_create); - tcase_add_test (tc_create, test_create_pass_001); - tcase_add_test_raise_signal (tc_create, test_create_fail_001, SIGABRT); - - TCase* tc_destroy = tcase_create ("destroy"); - suite_add_tcase (s, tc_destroy); - tcase_add_test (tc_destroy, test_destroy_pass_001); - tcase_add_test_raise_signal (tc_destroy, test_destroy_fail_001, SIGABRT); - - TCase* tc_check = tcase_create ("check"); - suite_add_tcase (s, tc_check); - tcase_add_test (tc_check, test_check_pass_001); - tcase_add_test (tc_check, test_check_pass_002); - tcase_add_test (tc_check, test_check_pass_003); - tcase_add_test_raise_signal (tc_check, test_check_fail_001, SIGABRT); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/receiver.c b/3rdparty/openpgm-svn-r1085/pgm/receiver.c deleted file mode 100644 index 8f26353..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/receiver.c +++ /dev/null @@ -1,2268 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM receiver socket. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -//#define RECEIVER_DEBUG -//#define SPM_DEBUG - -#ifndef RECEIVER_DEBUG -# define PGM_DISABLE_ASSERT -#endif - -#if !defined(ENOBUFS) && defined(WSAENOBUFS) -# define ENOBUFS WSAENOBUFS -#endif -#if !defined(ECONNRESET) && defined(WSAECONNRESET) -# define ECONNRESET WSAECONNRESET -#endif - -static bool send_spmr (pgm_sock_t*const restrict, pgm_peer_t*const restrict); -static bool send_nak (pgm_sock_t*const restrict, pgm_peer_t*const restrict, const uint32_t); -static bool send_parity_nak (pgm_sock_t*const restrict, pgm_peer_t*const restrict, const unsigned, const unsigned); -static bool send_nak_list (pgm_sock_t*const restrict, pgm_peer_t*const restrict, const struct pgm_sqn_list_t*const restrict); -static bool nak_rb_state (pgm_peer_t*, const pgm_time_t); -static void nak_rpt_state (pgm_peer_t*, const pgm_time_t); -static void nak_rdata_state (pgm_peer_t*, const pgm_time_t); -static inline pgm_peer_t* _pgm_peer_ref (pgm_peer_t*); -static bool on_general_poll (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict); -static bool on_dlr_poll (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict); - - -/* helpers for pgm_peer_t */ -static inline -pgm_time_t -next_ack_rb_expiry ( - const pgm_rxw_t* window - ) -{ - pgm_assert (NULL != window); - pgm_assert (NULL != window->ack_backoff_queue.tail); - - const struct pgm_peer_t* peer = (const struct pgm_peer_t*)window->ack_backoff_queue.tail; - return peer->ack_rb_expiry; -} - -static inline -pgm_time_t -next_nak_rb_expiry ( - const pgm_rxw_t* window - ) -{ - pgm_assert (NULL != window); - pgm_assert (NULL != window->nak_backoff_queue.tail); - - const struct pgm_sk_buff_t* skb = (const struct pgm_sk_buff_t*)window->nak_backoff_queue.tail; - const pgm_rxw_state_t* state = (const pgm_rxw_state_t*)&skb->cb; - return state->timer_expiry; -} - -static inline -pgm_time_t -next_nak_rpt_expiry ( - const pgm_rxw_t* window - ) -{ - pgm_assert (NULL != window); - pgm_assert (NULL != window->wait_ncf_queue.tail); - - const struct pgm_sk_buff_t* skb = (const struct pgm_sk_buff_t*)window->wait_ncf_queue.tail; - const pgm_rxw_state_t* state = (const pgm_rxw_state_t*)&skb->cb; - return state->timer_expiry; -} - -static inline -pgm_time_t -next_nak_rdata_expiry ( - const pgm_rxw_t* window - ) -{ - pgm_assert (NULL != window); - pgm_assert (NULL != window->wait_data_queue.tail); - - const struct pgm_sk_buff_t* skb = (const struct pgm_sk_buff_t*)window->wait_data_queue.tail; - const pgm_rxw_state_t* state = (const pgm_rxw_state_t*)&skb->cb; - return state->timer_expiry; -} - -/* calculate ACK_RB_IVL. - */ -static inline -uint32_t -ack_rb_ivl ( - pgm_sock_t* sock - ) /* not const as rand() updates the seed */ -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert_cmpuint (sock->ack_bo_ivl, >, 1); - - return pgm_rand_int_range (&sock->rand_, 1 /* us */, sock->ack_bo_ivl); -} - -/* calculate NAK_RB_IVL as random time interval 1 - NAK_BO_IVL. - */ -static inline -uint32_t -nak_rb_ivl ( - pgm_sock_t* sock - ) /* not const as rand() updates the seed */ -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert_cmpuint (sock->nak_bo_ivl, >, 1); - - return pgm_rand_int_range (&sock->rand_, 1 /* us */, sock->nak_bo_ivl); -} - -/* mark sequence as recovery failed. - */ - -static -void -cancel_skb ( - pgm_sock_t* restrict sock, - pgm_peer_t* restrict peer, - const struct pgm_sk_buff_t* restrict skb, - const pgm_time_t now - ) -{ - pgm_assert (NULL != sock); - pgm_assert (NULL != peer); - pgm_assert (NULL != skb); - pgm_assert_cmpuint (now, >=, skb->tstamp); - - pgm_trace (PGM_LOG_ROLE_RX_WINDOW, _("Lost data #%u due to cancellation."), skb->sequence); - - const uint32_t fail_time = now - skb->tstamp; - if (!peer->max_fail_time) - peer->max_fail_time = peer->min_fail_time = fail_time; - else if (fail_time > peer->max_fail_time) - peer->max_fail_time = fail_time; - else if (fail_time < peer->min_fail_time) - peer->min_fail_time = fail_time; - - pgm_rxw_lost (peer->window, skb->sequence); - PGM_HISTOGRAM_TIMES("Rx.FailTime", fail_time); - -/* mark receiver window for flushing on next recv() */ - pgm_peer_set_pending (sock, peer); -} - -/* check whether this receiver is the designated acker for the source - */ - -static inline -bool -_pgm_is_acker ( - const pgm_peer_t* restrict peer, - const struct pgm_sk_buff_t* restrict skb - ) -{ - struct sockaddr_storage acker_nla; - -/* pre-conditions */ - pgm_assert (NULL != peer); - pgm_assert (NULL != skb); - pgm_assert (NULL != skb->pgm_opt_pgmcc_data); - - pgm_nla_to_sockaddr (&skb->pgm_opt_pgmcc_data->opt_nla_afi, (struct sockaddr*)&acker_nla); - return (0 == pgm_sockaddr_cmp ((struct sockaddr*)&acker_nla, (struct sockaddr*)&peer->sock->send_addr)); -} - -/* is the source holding an acker election - */ - -static inline -bool -_pgm_is_acker_election ( - const struct pgm_sk_buff_t* restrict skb - ) -{ - pgm_assert (NULL != skb); - pgm_assert (NULL != skb->pgm_opt_pgmcc_data); - - const unsigned acker_afi = ntohs (skb->pgm_opt_pgmcc_data->opt_nla_afi); - switch (acker_afi) { - case AFI_IP: - if (INADDR_ANY == skb->pgm_opt_pgmcc_data->opt_nla.s_addr) - return TRUE; - break; - - case AFI_IP6: - if (0 == memcmp (&skb->pgm_opt_pgmcc_data->opt_nla, &in6addr_any, sizeof(in6addr_any))) - return TRUE; - break; - - default: break; - } - - return FALSE; -} - -/* add state for an ACK on a data packet. - */ - -static inline -void -_pgm_add_ack ( - pgm_peer_t* const restrict peer, - const pgm_time_t ack_rb_expiry - ) -{ - peer->ack_rb_expiry = ack_rb_expiry; - pgm_queue_push_head_link (&peer->window->ack_backoff_queue, &peer->ack_link); -} - -/* remove outstanding ACK - */ - -static inline -void -_pgm_remove_ack ( - pgm_peer_t* const restrict peer - ) -{ - pgm_assert (!pgm_queue_is_empty (&peer->window->ack_backoff_queue)); - pgm_queue_unlink (&peer->window->ack_backoff_queue, &peer->ack_link); - peer->ack_rb_expiry = 0; -} - -/* increase reference count for peer object - * - * on success, returns peer object. - */ - -static inline -pgm_peer_t* -_pgm_peer_ref ( - pgm_peer_t* peer - ) -{ -/* pre-conditions */ - pgm_assert (NULL != peer); - - pgm_atomic_inc32 (&peer->ref_count); - return peer; -} - -/* decrease reference count of peer object, destroying on last reference. - */ - -void -pgm_peer_unref ( - pgm_peer_t* peer - ) -{ -/* pre-conditions */ - pgm_assert (NULL != peer); - - if (pgm_atomic_exchange_and_add32 (&peer->ref_count, (uint32_t)-1) != 1) - return; - -/* receive window */ - pgm_rxw_destroy (peer->window); - peer->window = NULL; - -/* object */ - pgm_free (peer); - peer = NULL; -} - -/* find PGM options in received SKB. - * - * returns TRUE if opt_fragment is found, otherwise FALSE is returned. - */ - -static -bool -get_pgm_options ( - struct pgm_sk_buff_t* const skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - pgm_assert (NULL != skb->pgm_data); - - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(skb->pgm_data + 1); - bool found_opt = FALSE; - - pgm_assert (opt_header->opt_type == PGM_OPT_LENGTH); - pgm_assert (opt_header->opt_length == sizeof(struct pgm_opt_length)); - - pgm_debug ("get_pgm_options (skb:%p)", - (const void*)skb); - - skb->pgm_opt_fragment = NULL; - skb->pgm_opt_pgmcc_data = NULL; - -/* always at least two options, first is always opt_length */ - do { - opt_header = (struct pgm_opt_header*)((char*)opt_header + opt_header->opt_length); -/* option overflow */ - if (PGM_UNLIKELY((char*)opt_header > (char*)skb->data)) - break; - - switch (opt_header->opt_type & PGM_OPT_MASK) { - case PGM_OPT_FRAGMENT: - skb->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); - found_opt = TRUE; - break; - - case PGM_OPT_PGMCC_DATA: - skb->pgm_opt_pgmcc_data = (struct pgm_opt_pgmcc_data*)(opt_header + 1); - found_opt = TRUE; - break; - - default: break; - } - - } while (!(opt_header->opt_type & PGM_OPT_END)); - return found_opt; -} - -/* a peer in the context of the sock is another party on the network sending PGM - * packets. for each peer we need a receive window and network layer address (nla) to - * which nak requests can be forwarded to. - * - * on success, returns new peer object. - */ - -pgm_peer_t* -pgm_new_peer ( - pgm_sock_t* const restrict sock, - const pgm_tsi_t* const restrict tsi, - const struct sockaddr* const restrict src_addr, - const socklen_t src_addrlen, - const struct sockaddr* const restrict dst_addr, - const socklen_t dst_addrlen, - const pgm_time_t now - ) -{ - pgm_peer_t* peer; - -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != src_addr); - pgm_assert (src_addrlen > 0); - pgm_assert (NULL != dst_addr); - pgm_assert (dst_addrlen > 0); - -#ifdef PGM_DEBUG - char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop (src_addr, saddr, sizeof(saddr)); - pgm_sockaddr_ntop (dst_addr, daddr, sizeof(daddr)); - pgm_debug ("pgm_new_peer (sock:%p tsi:%s src-addr:%s src-addrlen:%u dst-addr:%s dst-addrlen:%u)", - (void*)sock, pgm_tsi_print (tsi), saddr, (unsigned)src_addrlen, daddr, (unsigned)dst_addrlen); -#endif - - peer = pgm_new0 (pgm_peer_t, 1); - peer->expiry = now + sock->peer_expiry; - peer->sock = sock; - memcpy (&peer->tsi, tsi, sizeof(pgm_tsi_t)); - memcpy (&peer->group_nla, dst_addr, dst_addrlen); - memcpy (&peer->local_nla, src_addr, src_addrlen); -/* port at same location for sin/sin6 */ - ((struct sockaddr_in*)&peer->local_nla)->sin_port = htons (sock->udp_encap_ucast_port); - ((struct sockaddr_in*)&peer->nla)->sin_port = htons (sock->udp_encap_ucast_port); - -/* lock on rx window */ - peer->window = pgm_rxw_create (&peer->tsi, - sock->max_tpdu, - sock->rxw_sqns, - sock->rxw_secs, - sock->rxw_max_rte, - sock->ack_c_p); - peer->spmr_expiry = now + sock->spmr_expiry; - -/* add peer to hash table and linked list */ - pgm_rwlock_writer_lock (&sock->peers_lock); - pgm_peer_t* entry = _pgm_peer_ref (peer); - pgm_hashtable_insert (sock->peers_hashtable, &peer->tsi, entry); - peer->peers_link.data = peer; - sock->peers_list = pgm_list_prepend_link (sock->peers_list, &peer->peers_link); - pgm_rwlock_writer_unlock (&sock->peers_lock); - - pgm_timer_lock (sock); - if (pgm_time_after( sock->next_poll, peer->spmr_expiry )) - sock->next_poll = peer->spmr_expiry; - pgm_timer_unlock (sock); - return peer; -} - -/* copy any contiguous buffers in the peer list to the provided - * message vector. - * returns -ENOBUFS if the vector is full, returns -ECONNRESET if - * data loss is detected, returns 0 when all peers flushed. - */ - -int -pgm_flush_peers_pending ( - pgm_sock_t* const restrict sock, - struct pgm_msgv_t** restrict pmsg, - const struct pgm_msgv_t* const msg_end, /* at least pmsg + 1, same object */ - size_t* const restrict bytes_read, /* added to, not set */ - unsigned* const restrict data_read - ) -{ - int retval = 0; - -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != pmsg); - pgm_assert (NULL != *pmsg); - pgm_assert (NULL != msg_end); - pgm_assert (NULL != bytes_read); - pgm_assert (NULL != data_read); - - pgm_debug ("pgm_flush_peers_pending (sock:%p pmsg:%p msg-end:%p bytes-read:%p data-read:%p)", - (const void*)sock, (const void*)pmsg, (const void*)msg_end, (const void*)bytes_read, (const void*)data_read); - - while (sock->peers_pending) - { - pgm_peer_t* peer = sock->peers_pending->data; - if (peer->last_commit && peer->last_commit < sock->last_commit) - pgm_rxw_remove_commit (peer->window); - const ssize_t peer_bytes = pgm_rxw_readv (peer->window, pmsg, msg_end - *pmsg + 1); - - if (peer->last_cumulative_losses != ((pgm_rxw_t*)peer->window)->cumulative_losses) - { - sock->is_reset = TRUE; - peer->lost_count = ((pgm_rxw_t*)peer->window)->cumulative_losses - peer->last_cumulative_losses; - peer->last_cumulative_losses = ((pgm_rxw_t*)peer->window)->cumulative_losses; - } - - if (peer_bytes >= 0) - { - (*bytes_read) += peer_bytes; - (*data_read) ++; - peer->last_commit = sock->last_commit; - if (*pmsg > msg_end) { /* commit full */ - retval = -ENOBUFS; - break; - } - } else - peer->last_commit = 0; - if (PGM_UNLIKELY(sock->is_reset)) { - retval = -ECONNRESET; - break; - } -/* clear this reference and move to next */ - sock->peers_pending = pgm_slist_remove_first (sock->peers_pending); - } - - return retval; -} - -/* edge trigerred has receiver pending events - */ - -bool -pgm_peer_has_pending ( - pgm_peer_t* const peer - ) -{ -/* pre-conditions */ - pgm_assert (NULL != peer); - - if (NULL == peer->pending_link.data && ((pgm_rxw_t*)peer->window)->has_event) { - ((pgm_rxw_t*)peer->window)->has_event = 0; - return TRUE; - } - return FALSE; -} - -/* set receiver in pending event queue - */ - -void -pgm_peer_set_pending ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict peer - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != peer); - - if (peer->pending_link.data) return; - peer->pending_link.data = peer; - sock->peers_pending = pgm_slist_prepend_link (sock->peers_pending, &peer->pending_link); -} - -/* Create a new error SKB detailing data loss. - */ - -void -pgm_set_reset_error ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict source, - struct pgm_msgv_t* const restrict msgv - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != source); - pgm_assert (NULL != msgv); - - struct pgm_sk_buff_t* error_skb = pgm_alloc_skb (0); - error_skb->sock = sock; - error_skb->tstamp = pgm_time_update_now (); - memcpy (&error_skb->tsi, &source->tsi, sizeof(pgm_tsi_t)); - error_skb->sequence = source->lost_count; - msgv->msgv_skb[0] = error_skb; - msgv->msgv_len = 1; -} - -/* SPM indicate start of a session, continued presence of a session, or flushing final packets - * of a session. - * - * returns TRUE on valid packet, FALSE on invalid packet or duplicate SPM sequence number. - */ - -bool -pgm_on_spm ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict source, - struct pgm_sk_buff_t* const restrict skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != source); - pgm_assert (NULL != skb); - - pgm_debug("pgm_on_spm (sock:%p source:%p skb:%p)", - (const void*)sock, (const void*)source, (const void*)skb); - - if (PGM_UNLIKELY(!pgm_verify_spm (skb))) { - pgm_trace(PGM_LOG_ROLE_NETWORK,_("Discarded invalid SPM.")); - source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]++; - return FALSE; - } - - const struct pgm_spm* spm = (struct pgm_spm*) skb->data; - const struct pgm_spm6* spm6 = (struct pgm_spm6*)skb->data; - const uint32_t spm_sqn = ntohl (spm->spm_sqn); - -/* check for advancing sequence number, or first SPM */ - if (PGM_LIKELY(pgm_uint32_gte (spm_sqn, source->spm_sqn))) - { -/* copy NLA for replies */ - pgm_nla_to_sockaddr (&spm->spm_nla_afi, (struct sockaddr*)&source->nla); - -/* save sequence number */ - source->spm_sqn = spm_sqn; - -/* update receive window */ - const pgm_time_t nak_rb_expiry = skb->tstamp + nak_rb_ivl (sock); - const unsigned naks = pgm_rxw_update (source->window, - ntohl (spm->spm_lead), - ntohl (spm->spm_trail), - skb->tstamp, - nak_rb_expiry); - if (naks) { - pgm_timer_lock (sock); - if (pgm_time_after (sock->next_poll, nak_rb_expiry)) - sock->next_poll = nak_rb_expiry; - pgm_timer_unlock (sock); - } - -/* mark receiver window for flushing on next recv() */ - const pgm_rxw_t* window = source->window; - if (window->cumulative_losses != source->last_cumulative_losses && - !source->pending_link.data) - { - sock->is_reset = TRUE; - source->lost_count = window->cumulative_losses - source->last_cumulative_losses; - source->last_cumulative_losses = window->cumulative_losses; - pgm_peer_set_pending (sock, source); - } - } - else - { /* does not advance SPM sequence number */ - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded duplicate SPM.")); - source->cumulative_stats[PGM_PC_RECEIVER_DUP_SPMS]++; - return FALSE; - } - -/* check whether peer can generate parity packets */ - if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) - { - const struct pgm_opt_length* opt_len = (AF_INET6 == source->nla.ss_family) ? - (const struct pgm_opt_length*)(spm6 + 1) : - (const struct pgm_opt_length*)(spm + 1); - if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed SPM.")); - source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]++; - return FALSE; - } - if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed SPM.")); - source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]++; - return FALSE; - } -/* TODO: check for > 16 options & past packet end */ - const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; - do { - opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); - if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_PARITY_PRM) - { - const struct pgm_opt_parity_prm* opt_parity_prm = (const struct pgm_opt_parity_prm*)(opt_header + 1); - if (PGM_UNLIKELY((opt_parity_prm->opt_reserved & PGM_PARITY_PRM_MASK) == 0)) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed SPM.")); - source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]++; - return FALSE; - } - - const uint32_t parity_prm_tgs = ntohl (opt_parity_prm->parity_prm_tgs); - if (PGM_UNLIKELY(parity_prm_tgs < 2 || parity_prm_tgs > 128)) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed SPM.")); - source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]++; - return FALSE; - } - - source->has_proactive_parity = opt_parity_prm->opt_reserved & PGM_PARITY_PRM_PRO; - source->has_ondemand_parity = opt_parity_prm->opt_reserved & PGM_PARITY_PRM_OND; - if (source->has_proactive_parity || source->has_ondemand_parity) { - source->is_fec_enabled = 1; - pgm_rxw_update_fec (source->window, parity_prm_tgs); - } - } - } while (!(opt_header->opt_type & PGM_OPT_END)); - } - -/* either way bump expiration timer */ - source->expiry = skb->tstamp + sock->peer_expiry; - source->spmr_expiry = 0; - if (source->spmr_tstamp > 0) { - PGM_HISTOGRAM_TIMES("Rx.SpmRequestResponseTime", skb->tstamp - source->spmr_tstamp); - source->spmr_tstamp = 0; - } - return TRUE; -} - -/* Multicast peer-to-peer NAK handling, pretty much the same as a NCF but different direction - * - * if NAK is valid, returns TRUE. on error, FALSE is returned. - */ - -bool -pgm_on_peer_nak ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict peer, - struct pgm_sk_buff_t* const restrict skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != peer); - pgm_assert (NULL != skb); - - pgm_debug ("pgm_on_peer_nak (sock:%p peer:%p skb:%p)", - (const void*)sock, (const void*)peer, (const void*)skb); - - if (PGM_UNLIKELY(!pgm_verify_nak (skb))) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded invalid multicast NAK.")); - peer->cumulative_stats[PGM_PC_RECEIVER_NAK_ERRORS]++; - return FALSE; - } - - const struct pgm_nak* nak = (struct pgm_nak*) skb->data; - const struct pgm_nak6* nak6 = (struct pgm_nak6*)skb->data; - -/* NAK_SRC_NLA must not contain our sock unicast NLA */ - struct sockaddr_storage nak_src_nla; - pgm_nla_to_sockaddr (&nak->nak_src_nla_afi, (struct sockaddr*)&nak_src_nla); - if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nak_src_nla, (struct sockaddr*)&sock->send_addr) == 0)) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded multicast NAK on NLA mismatch.")); - return FALSE; - } - -/* NAK_GRP_NLA contains one of our sock receive multicast groups: the sources send multicast group */ - struct sockaddr_storage nak_grp_nla; - pgm_nla_to_sockaddr ((AF_INET6 == nak_src_nla.ss_family) ? &nak6->nak6_grp_nla_afi : &nak->nak_grp_nla_afi, (struct sockaddr*)&nak_grp_nla); - bool found = FALSE; - for (unsigned i = 0; i < sock->recv_gsr_len; i++) - { - if (pgm_sockaddr_cmp ((struct sockaddr*)&nak_grp_nla, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0) - { - found = TRUE; - break; - } - } - - if (PGM_UNLIKELY(!found)) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded multicast NAK on multicast group mismatch.")); - return FALSE; - } - -/* handle as NCF */ - int status = pgm_rxw_confirm (peer->window, - ntohl (nak->nak_sqn), - skb->tstamp, - skb->tstamp + sock->nak_rdata_ivl, - skb->tstamp + nak_rb_ivl(sock)); - if (PGM_RXW_UPDATED == status || PGM_RXW_APPENDED == status) - peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]++; - -/* check NAK list */ - const uint32_t* nak_list = NULL; - unsigned nak_list_len = 0; - if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) - { - const struct pgm_opt_length* opt_len = (AF_INET6 == nak_src_nla.ss_family) ? - (const struct pgm_opt_length*)(nak6 + 1) : - (const struct pgm_opt_length*)(nak + 1); - if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed multicast NAK.")); - peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]++; - return FALSE; - } - if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed multicast NAK.")); - peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]++; - return FALSE; - } -/* TODO: check for > 16 options & past packet end */ - const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; - do { - opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); - if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_NAK_LIST) - { - nak_list = ((const struct pgm_opt_nak_list*)(opt_header + 1))->opt_sqn; - nak_list_len = ( opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(uint8_t) ) / sizeof(uint32_t); - break; - } - } while (!(opt_header->opt_type & PGM_OPT_END)); - } - - while (nak_list_len) { - status = pgm_rxw_confirm (peer->window, - ntohl (*nak_list), - skb->tstamp, - skb->tstamp + sock->nak_rdata_ivl, - skb->tstamp + nak_rb_ivl(sock)); - if (PGM_RXW_UPDATED == status || PGM_RXW_APPENDED == status) - peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]++; - nak_list++; - nak_list_len--; - } - -/* mark receiver window for flushing on next recv() */ - const pgm_rxw_t* window = peer->window; - if (window->cumulative_losses != peer->last_cumulative_losses && - !peer->pending_link.data) - { - sock->is_reset = TRUE; - peer->lost_count = window->cumulative_losses - peer->last_cumulative_losses; - peer->last_cumulative_losses = window->cumulative_losses; - pgm_peer_set_pending (sock, peer); - } - return TRUE; -} - -/* NCF confirming receipt of a NAK from this sock or another on the LAN segment. - * - * Packet contents will match exactly the sent NAK, although not really that helpful. - * - * if NCF is valid, returns TRUE. on error, FALSE is returned. - */ - -bool -pgm_on_ncf ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict source, - struct pgm_sk_buff_t* const restrict skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != source); - pgm_assert (NULL != skb); - - pgm_debug ("pgm_on_ncf (sock:%p source:%p skb:%p)", - (const void*)sock, (const void*)source, (const void*)skb); - - if (PGM_UNLIKELY(!pgm_verify_ncf (skb))) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded invalid NCF.")); - source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]++; - return FALSE; - } - - const struct pgm_nak* ncf = (struct pgm_nak*) skb->data; - const struct pgm_nak6* ncf6 = (struct pgm_nak6*)skb->data; - -/* NCF_SRC_NLA may contain our sock unicast NLA, we don't really care */ - struct sockaddr_storage ncf_src_nla; - pgm_nla_to_sockaddr (&ncf->nak_src_nla_afi, (struct sockaddr*)&ncf_src_nla); - -#if 0 - if (PGM(pgm_sockaddr_cmp ((struct sockaddr*)&ncf_src_nla, (struct sockaddr*)&sock->send_addr) != 0)) { - g_trace ("INFO", "Discarded NCF on NLA mismatch."); - peer->cumulative_stats[PGM_PC_RECEIVER_PACKETS_DISCARDED]++; - return FALSE; - } -#endif - -/* NCF_GRP_NLA contains our sock multicast group */ - struct sockaddr_storage ncf_grp_nla; - pgm_nla_to_sockaddr ((AF_INET6 == ncf_src_nla.ss_family) ? &ncf6->nak6_grp_nla_afi : &ncf->nak_grp_nla_afi, (struct sockaddr*)&ncf_grp_nla); - if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&ncf_grp_nla, (struct sockaddr*)&sock->send_gsr.gsr_group) != 0)) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded NCF on multicast group mismatch.")); - return FALSE; - } - - const pgm_time_t ncf_rdata_ivl = skb->tstamp + sock->nak_rdata_ivl; - const pgm_time_t ncf_rb_ivl = skb->tstamp + nak_rb_ivl(sock); - int status = pgm_rxw_confirm (source->window, - ntohl (ncf->nak_sqn), - skb->tstamp, - ncf_rdata_ivl, - ncf_rb_ivl); - if (PGM_RXW_UPDATED == status || PGM_RXW_APPENDED == status) - { - const pgm_time_t ncf_ivl = (PGM_RXW_APPENDED == status) ? ncf_rb_ivl : ncf_rdata_ivl; - pgm_timer_lock (sock); - if (pgm_time_after (sock->next_poll, ncf_ivl)) { - sock->next_poll = ncf_ivl; - } - pgm_timer_unlock (sock); - source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]++; - } - -/* check NCF list */ - const uint32_t* ncf_list = NULL; - unsigned ncf_list_len = 0; - if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) - { - const struct pgm_opt_length* opt_len = (AF_INET6 == ncf_src_nla.ss_family) ? - (const struct pgm_opt_length*)(ncf6 + 1) : - (const struct pgm_opt_length*)(ncf + 1); - if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed NCF.")); - source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]++; - return FALSE; - } - if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed NCF.")); - source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]++; - return FALSE; - } -/* TODO: check for > 16 options & past packet end */ - const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; - do { - opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); - if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_NAK_LIST) - { - ncf_list = ((const struct pgm_opt_nak_list*)(opt_header + 1))->opt_sqn; - ncf_list_len = ( opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(uint8_t) ) / sizeof(uint32_t); - break; - } - } while (!(opt_header->opt_type & PGM_OPT_END)); - } - - pgm_debug ("NCF contains 1+%d sequence numbers.", ncf_list_len); - while (ncf_list_len) - { - status = pgm_rxw_confirm (source->window, - ntohl (*ncf_list), - skb->tstamp, - ncf_rdata_ivl, - ncf_rb_ivl); - if (PGM_RXW_UPDATED == status || PGM_RXW_APPENDED == status) - source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]++; - ncf_list++; - ncf_list_len--; - } - -/* mark receiver window for flushing on next recv() */ - const pgm_rxw_t* window = source->window; - if (window->cumulative_losses != source->last_cumulative_losses && - !source->pending_link.data) - { - sock->is_reset = TRUE; - source->lost_count = window->cumulative_losses - source->last_cumulative_losses; - source->last_cumulative_losses = window->cumulative_losses; - pgm_peer_set_pending (sock, source); - } - return TRUE; -} - -/* send SPM-request to a new peer, this packet type has no contents - * - * on success, TRUE is returned, if operation would block FALSE is - * returned. - */ - -static -bool -send_spmr ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict source - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != source); - - pgm_debug ("send_spmr (sock:%p source:%p)", - (const void*)sock, (const void*)source); - - const size_t tpdu_length = sizeof(struct pgm_header); - char buf[ tpdu_length ]; - struct pgm_header* header = (struct pgm_header*)buf; - memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); -/* dport & sport reversed communicating upstream */ - header->pgm_sport = sock->dport; - header->pgm_dport = source->tsi.sport; - header->pgm_type = PGM_SPMR; - header->pgm_options = 0; - header->pgm_tsdu_length = 0; - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); - -/* send multicast SPMR TTL 1 */ - pgm_sockaddr_multicast_hops (sock->send_sock, sock->send_gsr.gsr_group.ss_family, 1); - ssize_t sent = pgm_sendto (sock, - FALSE, /* not rate limited */ - FALSE, /* regular socket */ - header, - tpdu_length, - (struct sockaddr*)&sock->send_gsr.gsr_group, - pgm_sockaddr_len ((struct sockaddr*)&sock->send_gsr.gsr_group)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) - return FALSE; - -/* send unicast SPMR with regular TTL */ - pgm_sockaddr_multicast_hops (sock->send_sock, sock->send_gsr.gsr_group.ss_family, sock->hops); - sent = pgm_sendto (sock, - FALSE, - FALSE, - header, - tpdu_length, - (struct sockaddr*)&source->local_nla, - pgm_sockaddr_len ((struct sockaddr*)&source->local_nla)); - if (sent < 0 && EAGAIN == errno) - return FALSE; - - sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT] += tpdu_length * 2; - return TRUE; -} - -/* send selective NAK for one sequence number. - * - * on success, TRUE is returned, returns FALSE if would block on operation. - */ - -static -bool -send_nak ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict source, - const uint32_t sequence - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != source); - - pgm_debug ("send_nak (sock:%p peer:%p sequence:%" PRIu32 ")", - (void*)sock, (void*)source, sequence); - - size_t tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); - if (AF_INET6 == source->nla.ss_family) - tpdu_length += sizeof(struct pgm_nak6) - sizeof(struct pgm_nak); - char buf[ tpdu_length ]; - struct pgm_header* header = (struct pgm_header*)buf; - struct pgm_nak* nak = (struct pgm_nak* )(header + 1); - struct pgm_nak6* nak6 = (struct pgm_nak6*)(header + 1); - memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); - -/* dport & sport swap over for a nak */ - header->pgm_sport = sock->dport; - header->pgm_dport = source->tsi.sport; - header->pgm_type = PGM_NAK; - header->pgm_options = 0; - header->pgm_tsdu_length = 0; - -/* NAK */ - nak->nak_sqn = htonl (sequence); - -/* source nla */ - pgm_sockaddr_to_nla ((struct sockaddr*)&source->nla, (char*)&nak->nak_src_nla_afi); - -/* group nla: we match the NAK NLA to the same as advertised by the source, we might - * be listening to multiple multicast groups - */ - pgm_sockaddr_to_nla ((struct sockaddr*)&source->group_nla, - (AF_INET6 == source->nla.ss_family) ? (char*)&nak6->nak6_grp_nla_afi : (char*)&nak->nak_grp_nla_afi); - - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); - - const ssize_t sent = pgm_sendto (sock, - FALSE, /* not rate limited */ - TRUE, /* with router alert */ - header, - tpdu_length, - (struct sockaddr*)&source->nla, - pgm_sockaddr_len((struct sockaddr*)&source->nla)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) - return FALSE; - - source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT]++; - source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT]++; - return TRUE; -} - -/* Send a parity NAK requesting on-demand parity packet generation. - * - * on success, TRUE is returned, returns FALSE if operation would block. - */ - -static -bool -send_parity_nak ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict source, - const uint32_t nak_tg_sqn, /* transmission group (shifted) */ - const uint32_t nak_pkt_cnt /* count of parity packets to request */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != source); - pgm_assert (nak_pkt_cnt > 0); - - pgm_debug ("send_parity_nak (sock:%p source:%p nak-tg-sqn:%" PRIu32 " nak-pkt-cnt:%" PRIu32 ")", - (void*)sock, (void*)source, nak_tg_sqn, nak_pkt_cnt); - - size_t tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); - if (AF_INET6 == source->nla.ss_family) - tpdu_length += sizeof(struct pgm_nak6) - sizeof(struct pgm_nak); - char buf[ tpdu_length ]; - struct pgm_header* header = (struct pgm_header*)buf; - struct pgm_nak* nak = (struct pgm_nak* )(header + 1); - struct pgm_nak6* nak6 = (struct pgm_nak6*)(header + 1); - memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); - -/* dport & sport swap over for a nak */ - header->pgm_sport = sock->dport; - header->pgm_dport = source->tsi.sport; - header->pgm_type = PGM_NAK; - header->pgm_options = PGM_OPT_PARITY; /* this is a parity packet */ - header->pgm_tsdu_length = 0; - -/* NAK */ - nak->nak_sqn = htonl (nak_tg_sqn | (nak_pkt_cnt - 1) ); - -/* source nla */ - pgm_sockaddr_to_nla ((struct sockaddr*)&source->nla, (char*)&nak->nak_src_nla_afi); - -/* group nla: we match the NAK NLA to the same as advertised by the source, we might - * be listening to multiple multicast groups - */ - pgm_sockaddr_to_nla ((struct sockaddr*)&source->group_nla, - (AF_INET6 == source->nla.ss_family) ? (char*)&nak6->nak6_grp_nla_afi : (char*)&nak->nak_grp_nla_afi ); - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); - - const ssize_t sent = pgm_sendto (sock, - FALSE, /* not rate limited */ - TRUE, /* with router alert */ - header, - tpdu_length, - (struct sockaddr*)&source->nla, - pgm_sockaddr_len((struct sockaddr*)&source->nla)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) - return FALSE; - - source->cumulative_stats[PGM_PC_RECEIVER_PARITY_NAK_PACKETS_SENT]++; - source->cumulative_stats[PGM_PC_RECEIVER_PARITY_NAKS_SENT]++; - return TRUE; -} - -/* A NAK packet with a OPT_NAK_LIST option extension - * - * on success, TRUE is returned. on error, FALSE is returned. - */ - -static -bool -send_nak_list ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict source, - const struct pgm_sqn_list_t* const restrict sqn_list - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != source); - pgm_assert (NULL != sqn_list); - pgm_assert_cmpuint (sqn_list->len, >, 1); - pgm_assert_cmpuint (sqn_list->len, <=, 63); - -#ifdef RECEIVER_DEBUG - char list[1024]; - sprintf (list, "%" PRIu32, sqn_list->sqn[0]); - for (unsigned i = 1; i < sqn_list->len; i++) { - char sequence[2 + strlen("4294967295")]; - sprintf (sequence, " %" PRIu32, sqn_list->sqn[i]); - strcat (list, sequence); - } - pgm_debug("send_nak_list (sock:%p source:%p sqn-list:[%s])", - (const void*)sock, (const void*)source, list); -#endif - - size_t tpdu_length = sizeof(struct pgm_header) + - sizeof(struct pgm_nak) + - sizeof(struct pgm_opt_length) + /* includes header */ - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_nak_list) + - ( (sqn_list->len-1) * sizeof(uint32_t) ); - if (AF_INET6 == source->nla.ss_family) - tpdu_length += sizeof(struct pgm_nak6) - sizeof(struct pgm_nak); - char buf[ tpdu_length ]; - if (PGM_UNLIKELY(pgm_mem_gc_friendly)) - memset (buf, 0, tpdu_length); - struct pgm_header* header = (struct pgm_header*)buf; - struct pgm_nak* nak = (struct pgm_nak* )(header + 1); - struct pgm_nak6* nak6 = (struct pgm_nak6*)(header + 1); - memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); - -/* dport & sport swap over for a nak */ - header->pgm_sport = sock->dport; - header->pgm_dport = source->tsi.sport; - header->pgm_type = PGM_NAK; - header->pgm_options = PGM_OPT_PRESENT | PGM_OPT_NETWORK; - header->pgm_tsdu_length = 0; - -/* NAK */ - nak->nak_sqn = htonl (sqn_list->sqn[0]); - -/* source nla */ - pgm_sockaddr_to_nla ((struct sockaddr*)&source->nla, (char*)&nak->nak_src_nla_afi); - -/* group nla */ - pgm_sockaddr_to_nla ((struct sockaddr*)&source->group_nla, - (AF_INET6 == source->nla.ss_family) ? (char*)&nak6->nak6_grp_nla_afi : (char*)&nak->nak_grp_nla_afi); - -/* OPT_NAK_LIST */ - struct pgm_opt_length* opt_len = (AF_INET6 == source->nla.ss_family) ? (struct pgm_opt_length*)(nak6 + 1) : (struct pgm_opt_length*)(nak + 1); - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_nak_list) + - ( (sqn_list->len-1) * sizeof(uint32_t) ) ); - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) - + ( (sqn_list->len-1) * sizeof(uint32_t) ); - struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); - opt_nak_list->opt_reserved = 0; - - for (unsigned i = 1; i < sqn_list->len; i++) - opt_nak_list->opt_sqn[i-1] = htonl (sqn_list->sqn[i]); - - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); - - const ssize_t sent = pgm_sendto (sock, - FALSE, /* not rate limited */ - FALSE, /* regular socket */ - header, - tpdu_length, - (struct sockaddr*)&source->nla, - pgm_sockaddr_len((struct sockaddr*)&source->nla)); - if ( sent != (ssize_t)tpdu_length ) - return FALSE; - - source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT]++; - source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT] += 1 + sqn_list->len; - return TRUE; -} - -/* send ACK upstream to source - * - * on success, TRUE is returned. on error, FALSE is returned. - */ - -static -bool -send_ack ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict source, - const pgm_time_t now - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != source); - - pgm_debug ("send_ack (sock:%p source:%p now:%" PGM_TIME_FORMAT ")", - (const void*)sock, (const void*)source, now); - - size_t tpdu_length = sizeof(struct pgm_header) + - sizeof(struct pgm_ack) + - sizeof(struct pgm_opt_length) + /* includes header */ - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_pgmcc_feedback); - if (AF_INET6 == sock->send_addr.ss_family) - tpdu_length += sizeof(struct pgm_opt6_pgmcc_feedback) - sizeof(struct pgm_opt_pgmcc_feedback); - char buf[ tpdu_length ]; - if (PGM_UNLIKELY(pgm_mem_gc_friendly)) - memset (buf, 0, tpdu_length); - struct pgm_header* header = (struct pgm_header*)buf; - struct pgm_ack* ack = (struct pgm_ack*)(header + 1); - memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); - -/* dport & sport swap over for an ack */ - header->pgm_sport = sock->dport; - header->pgm_dport = source->tsi.sport; - header->pgm_type = PGM_ACK; - header->pgm_options = PGM_OPT_PRESENT; - header->pgm_tsdu_length = 0; - -/* ACK */ - ack->ack_rx_max = htonl (pgm_rxw_lead (source->window)); - ack->ack_bitmap = htonl (source->window->bitmap); - -/* OPT_PGMCC_FEEDBACK */ - struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(ack + 1); - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - (AF_INET6 == sock->send_addr.ss_family) ? - sizeof(struct pgm_opt6_pgmcc_feedback) : - sizeof(struct pgm_opt_pgmcc_feedback) ); - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_PGMCC_FEEDBACK | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + - ( (AF_INET6 == sock->send_addr.ss_family) ? - sizeof(struct pgm_opt6_pgmcc_feedback) : - sizeof(struct pgm_opt_pgmcc_feedback) ); - struct pgm_opt_pgmcc_feedback* opt_pgmcc_feedback = (struct pgm_opt_pgmcc_feedback*)(opt_header + 1); - opt_pgmcc_feedback->opt_reserved = 0; - - const uint32_t t = source->ack_last_tstamp + pgm_to_msecs( now - source->last_data_tstamp ); - opt_pgmcc_feedback->opt_tstamp = htonl (t); - pgm_sockaddr_to_nla ((struct sockaddr*)&sock->send_addr, (char*)&opt_pgmcc_feedback->opt_nla_afi); - opt_pgmcc_feedback->opt_loss_rate = htonl (source->window->data_loss); - - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); - - const ssize_t sent = pgm_sendto (sock, - FALSE, /* not rate limited */ - FALSE, /* regular socket */ - header, - tpdu_length, - (struct sockaddr*)&source->nla, - pgm_sockaddr_len((struct sockaddr*)&source->nla)); - if ( sent != (ssize_t)tpdu_length ) - return FALSE; - - source->cumulative_stats[PGM_PC_RECEIVER_ACKS_SENT]++; - return TRUE; -} - -/* check all receiver windows for ACKer elections, on expiration send an ACK. - * - * returns TRUE on success, returns FALSE if operation would block. - */ - -static -bool -ack_rb_state ( - pgm_peer_t* peer, - const pgm_time_t now - ) -{ -/* pre-conditions */ - pgm_assert (NULL != peer); - - pgm_debug ("ack_rb_state (peer:%p now:%" PGM_TIME_FORMAT ")", - (const void*)peer, now); - - pgm_rxw_t* window = peer->window; - pgm_sock_t* sock = peer->sock; - pgm_list_t* list; - - list = window->ack_backoff_queue.tail; - if (!list) { - pgm_assert (window->ack_backoff_queue.head == NULL); - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Backoff queue is empty in ack_rb_state.")); - return TRUE; - } else { - pgm_assert (window->ack_backoff_queue.head != NULL); - } - -/* have not learned this peers NLA */ - const bool is_valid_nla = (0 != peer->nla.ss_family); - - while (list) - { - pgm_list_t* next_list_el = list->prev; - -/* check for ACK backoff expiration */ - if (pgm_time_after_eq(now, peer->ack_rb_expiry)) - { -/* unreliable delivery */ - _pgm_remove_ack (peer); - - if (PGM_UNLIKELY(!is_valid_nla)) { - pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Unable to send ACK due to unknown NLA.")); - list = next_list_el; - continue; - } - - pgm_assert (!pgm_sockaddr_is_addr_unspecified ((struct sockaddr*)&peer->nla)); - - if (!send_ack (sock, peer, now)) - return FALSE; - } - else - { /* packet expires some time later */ - break; - } - - list = next_list_el; - } - - if (window->ack_backoff_queue.length == 0) - { - pgm_assert ((struct rxw_packet*)window->ack_backoff_queue.head == NULL); - pgm_assert ((struct rxw_packet*)window->ack_backoff_queue.tail == NULL); - } - else - { - pgm_assert ((struct rxw_packet*)window->ack_backoff_queue.head != NULL); - pgm_assert ((struct rxw_packet*)window->ack_backoff_queue.tail != NULL); - } - - if (window->ack_backoff_queue.tail) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiry set in %f seconds."), - pgm_to_secsf(next_ack_rb_expiry(window) - now)); - } - else - { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("ACK backoff queue empty.")); - } - return TRUE; -} - -/* check all receiver windows for packets in BACK-OFF_STATE, on expiration send a NAK. - * update sock::next_nak_rb_timestamp for next expiration time. - * - * peer object is locked before entry. - * - * returns TRUE on success, returns FALSE if operation would block. - */ - -static -bool -nak_rb_state ( - pgm_peer_t* peer, - const pgm_time_t now - ) -{ -/* pre-conditions */ - pgm_assert (NULL != peer); - - pgm_debug ("nak_rb_state (peer:%p now:%" PGM_TIME_FORMAT ")", - (const void*)peer, now); - - pgm_rxw_t* window = peer->window; - pgm_sock_t* sock = peer->sock; - pgm_list_t* list; - struct pgm_sqn_list_t nak_list = { .len = 0 }; - -/* send all NAKs first, lack of data is blocking contiguous processing and its - * better to get the notification out a.s.a.p. even though it might be waiting - * in a kernel queue. - * - * alternative: after each packet check for incoming data and return to the - * event loop. bias for shorter loops as retry count increases. - */ - list = window->nak_backoff_queue.tail; - if (!list) { - pgm_assert (window->nak_backoff_queue.head == NULL); - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Backoff queue is empty in nak_rb_state.")); - return TRUE; - } else { - pgm_assert (window->nak_backoff_queue.head != NULL); - } - - unsigned dropped_invalid = 0; - -/* have not learned this peers NLA */ - const bool is_valid_nla = 0 != peer->nla.ss_family; - -/* TODO: process BOTH selective and parity NAKs? */ - -/* calculate current transmission group for parity enabled peers */ - if (peer->has_ondemand_parity) - { - const uint32_t tg_sqn_mask = 0xffffffff << window->tg_sqn_shift; - -/* NAKs only generated previous to current transmission group */ - const uint32_t current_tg_sqn = window->lead & tg_sqn_mask; - - uint32_t nak_tg_sqn = 0; - uint32_t nak_pkt_cnt = 0; - -/* parity NAK generation */ - - while (list) - { - pgm_list_t* next_list_el = list->prev; - struct pgm_sk_buff_t* skb = (struct pgm_sk_buff_t*)list; - pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; - -/* check this packet for state expiration */ - if (pgm_time_after_eq (now, state->timer_expiry)) - { - if (PGM_UNLIKELY(!is_valid_nla)) { - dropped_invalid++; - pgm_rxw_lost (window, skb->sequence); -/* mark receiver window for flushing on next recv() */ - pgm_peer_set_pending (sock, peer); - list = next_list_el; - continue; - } - -/* TODO: parity nak lists */ - const uint32_t tg_sqn = skb->sequence & tg_sqn_mask; - if ( ( nak_pkt_cnt && tg_sqn == nak_tg_sqn ) || - ( !nak_pkt_cnt && tg_sqn != current_tg_sqn ) ) - { - pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_NCF); - - if (!nak_pkt_cnt++) - nak_tg_sqn = tg_sqn; - state->nak_transmit_count++; - -#ifdef PGM_ABSOLUTE_EXPIRY - state->timer_expiry += sock->nak_rpt_ivl; - while (pgm_time_after_eq (now, state->timer_expiry)) { - state->timer_expiry += sock->nak_rpt_ivl; - state->ncf_retry_count++; - } -#else - state->timer_expiry = now + sock->nak_rpt_ivl; -#endif - pgm_timer_lock (sock); - if (pgm_time_after (sock->next_poll, state->timer_expiry)) - sock->next_poll = state->timer_expiry; - pgm_timer_unlock (sock); - } - else - { /* different transmission group */ - break; - } - } - else - { /* packet expires some time later */ - break; - } - - list = next_list_el; - } - - if (nak_pkt_cnt && !send_parity_nak (sock, peer, nak_tg_sqn, nak_pkt_cnt)) - return FALSE; - } - else - { - -/* select NAK generation */ - - while (list) - { - pgm_list_t* next_list_el = list->prev; - struct pgm_sk_buff_t* skb = (struct pgm_sk_buff_t*)list; - pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; - -/* check this packet for state expiration */ - if (pgm_time_after_eq(now, state->timer_expiry)) - { - if (PGM_UNLIKELY(!is_valid_nla)) { - dropped_invalid++; - pgm_rxw_lost (window, skb->sequence); -/* mark receiver window for flushing on next recv() */ - pgm_peer_set_pending (sock, peer); - list = next_list_el; - continue; - } - - pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_NCF); - nak_list.sqn[nak_list.len++] = skb->sequence; - state->nak_transmit_count++; - -/* we have two options here, calculate the expiry time in the new state relative to the current - * state execution time, skipping missed expirations due to delay in state processing, or base - * from the actual current time. - */ -#ifdef PGM_ABSOLUTE_EXPIRY - state->timer_expiry += sock->nak_rpt_ivl; - while (pgm_time_after_eq(now, state->timer_expiry)){ - state->timer_expiry += sock->nak_rpt_ivl; - state->ncf_retry_count++; - } -#else - state->timer_expiry = now + sock->nak_rpt_ivl; -pgm_trace(PGM_LOG_ROLE_NETWORK,_("nak_rpt_expiry in %f seconds."), - pgm_to_secsf( state->timer_expiry - now ) ); -#endif - pgm_timer_lock (sock); - if (pgm_time_after (sock->next_poll, state->timer_expiry)) - sock->next_poll = state->timer_expiry; - pgm_timer_unlock (sock); - - if (nak_list.len == PGM_N_ELEMENTS(nak_list.sqn)) { - if (sock->can_send_nak && !send_nak_list (sock, peer, &nak_list)) - return FALSE; - nak_list.len = 0; - } - } - else - { /* packet expires some time later */ - break; - } - - list = next_list_el; - } - - if (sock->can_send_nak && nak_list.len) - { - if (nak_list.len > 1 && !send_nak_list (sock, peer, &nak_list)) - return FALSE; - else if (!send_nak (sock, peer, nak_list.sqn[0])) - return FALSE; - } - - } - - if (PGM_UNLIKELY(dropped_invalid)) - { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Dropped %u messages due to invalid NLA."), dropped_invalid); - -/* mark receiver window for flushing on next recv() */ - if (window->cumulative_losses != peer->last_cumulative_losses && - !peer->pending_link.data) - { - sock->is_reset = TRUE; - peer->lost_count = window->cumulative_losses - peer->last_cumulative_losses; - peer->last_cumulative_losses = window->cumulative_losses; - pgm_peer_set_pending (sock, peer); - } - } - - if (window->nak_backoff_queue.length == 0) - { - pgm_assert ((struct rxw_packet*)window->nak_backoff_queue.head == NULL); - pgm_assert ((struct rxw_packet*)window->nak_backoff_queue.tail == NULL); - } - else - { - pgm_assert ((struct rxw_packet*)window->nak_backoff_queue.head != NULL); - pgm_assert ((struct rxw_packet*)window->nak_backoff_queue.tail != NULL); - } - - if (window->nak_backoff_queue.tail) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiry set in %f seconds."), - pgm_to_secsf(next_nak_rb_expiry(window) - now)); - } - else - { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("NAK backoff queue empty.")); - } - return TRUE; -} - -/* check this peer for NAK state timers, uses the tail of each queue for the nearest - * timer execution. - * - * returns TRUE on complete sweep, returns FALSE if operation would block. - */ - -bool -pgm_check_peer_state ( - pgm_sock_t* sock, - const pgm_time_t now - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - - pgm_debug ("pgm_check_peer_state (sock:%p now:%" PGM_TIME_FORMAT ")", - (const void*)sock, now); - - if (!sock->peers_list) - return TRUE; - - pgm_list_t* list = sock->peers_list; - do { - pgm_list_t* next = list->next; - pgm_peer_t* peer = list->data; - pgm_rxw_t* window = peer->window; - - if (peer->spmr_expiry) - { - if (pgm_time_after_eq (now, peer->spmr_expiry)) - { - if (sock->can_send_nak) { - if (!send_spmr (sock, peer)) { - return FALSE; - } - peer->spmr_tstamp = now; - } - peer->spmr_expiry = 0; - } - } - - if (window->ack_backoff_queue.tail) - { - if (pgm_time_after_eq (now, next_ack_rb_expiry (window))) - if (!ack_rb_state (peer, now)) { - return FALSE; - } - } - - if (window->nak_backoff_queue.tail) - { - if (pgm_time_after_eq (now, next_nak_rb_expiry (window))) - if (!nak_rb_state (peer, now)) { - return FALSE; - } - } - - if (window->wait_ncf_queue.tail) - { - if (pgm_time_after_eq (now, next_nak_rpt_expiry (window))) - nak_rpt_state (peer, now); - } - - if (window->wait_data_queue.tail) - { - if (pgm_time_after_eq (now, next_nak_rdata_expiry (window))) - nak_rdata_state (peer, now); - } - -/* expired, remove from hash table and linked list */ - if (pgm_time_after_eq (now, peer->expiry)) - { - if (peer->pending_link.data) - { - pgm_trace (PGM_LOG_ROLE_SESSION,_("Peer expiration postponed due to committing data, tsi %s"), pgm_tsi_print (&peer->tsi)); - peer->expiry += sock->peer_expiry; - } - else if (window->committed_count) - { - pgm_trace (PGM_LOG_ROLE_SESSION,_("Peer expiration postponed due to committed data, tsi %s"), pgm_tsi_print (&peer->tsi)); - peer->expiry += sock->peer_expiry; - } - else - { - pgm_trace (PGM_LOG_ROLE_SESSION,_("Peer expired, tsi %s"), pgm_tsi_print (&peer->tsi)); - pgm_hashtable_remove (sock->peers_hashtable, &peer->tsi); - sock->peers_list = pgm_list_remove_link (sock->peers_list, &peer->peers_link); - if (sock->last_hash_value == peer) - sock->last_hash_value = NULL; - pgm_peer_unref (peer); - } - } - - list = next; - } while (list); - -/* check for waiting contiguous packets */ - if (sock->peers_pending && !sock->is_pending_read) - { - pgm_debug ("prod rx thread"); - pgm_notify_send (&sock->pending_notify); - sock->is_pending_read = TRUE; - } - return TRUE; -} - -/* find the next state expiration time among the socks peers. - * - * on success, returns the earliest of the expiration parameter or next - * peer expiration time. - */ - -pgm_time_t -pgm_min_receiver_expiry ( - pgm_time_t expiration, /* absolute time */ - pgm_sock_t* sock - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - - pgm_debug ("pgm_min_receiver_expiry (expiration:%" PGM_TIME_FORMAT " sock:%p)", - expiration, (const void*)sock); - - if (!sock->peers_list) - return expiration; - - pgm_list_t* list = sock->peers_list; - do { - pgm_list_t* next = list->next; - pgm_peer_t* peer = (pgm_peer_t*)list->data; - pgm_rxw_t* window = peer->window; - - if (peer->spmr_expiry) - { - if (pgm_time_after_eq (expiration, peer->spmr_expiry)) - expiration = peer->spmr_expiry; - } - - if (window->ack_backoff_queue.tail) - { - if (pgm_time_after_eq (expiration, next_ack_rb_expiry (window))) - expiration = next_ack_rb_expiry (window); - } - - if (window->nak_backoff_queue.tail) - { - if (pgm_time_after_eq (expiration, next_nak_rb_expiry (window))) - expiration = next_nak_rb_expiry (window); - } - - if (window->wait_ncf_queue.tail) - { - if (pgm_time_after_eq (expiration, next_nak_rpt_expiry (window))) - expiration = next_nak_rpt_expiry (window); - } - - if (window->wait_data_queue.tail) - { - if (pgm_time_after_eq (expiration, next_nak_rdata_expiry (window))) - expiration = next_nak_rdata_expiry (window); - } - - list = next; - } while (list); - - return expiration; -} - -/* check WAIT_NCF_STATE, on expiration move back to BACK-OFF_STATE, on exceeding NAK_NCF_RETRIES - * cancel the sequence number. - */ -static -void -nak_rpt_state ( - pgm_peer_t* peer, - const pgm_time_t now - ) -{ -/* pre-conditions */ - pgm_assert (NULL != peer); - - pgm_debug ("nak_rpt_state (peer:%p now:%" PGM_TIME_FORMAT ")", - (void*)peer, now); - - pgm_rxw_t* window = peer->window; - pgm_sock_t* sock = peer->sock; - pgm_list_t* list = window->wait_ncf_queue.tail; - - unsigned dropped_invalid = 0; - unsigned dropped = 0; - -/* have not learned this peers NLA */ - const bool is_valid_nla = 0 != peer->nla.ss_family; - - while (list) - { - pgm_list_t* next_list_el = list->prev; - struct pgm_sk_buff_t* skb = (struct pgm_sk_buff_t*)list; - pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; - -/* check this packet for state expiration */ - if (pgm_time_after_eq (now, state->timer_expiry)) - { - if (PGM_UNLIKELY(!is_valid_nla)) { - dropped_invalid++; - pgm_rxw_lost (window, skb->sequence); -/* mark receiver window for flushing on next recv() */ - pgm_peer_set_pending (sock, peer); - list = next_list_el; - continue; - } - - if (++state->ncf_retry_count >= sock->nak_ncf_retries) - { - dropped++; - cancel_skb (sock, peer, skb, now); - peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_NCF_RETRIES_EXCEEDED]++; - } - else - { -/* retry */ -// state->timer_expiry += nak_rb_ivl(sock); - state->timer_expiry = now + nak_rb_ivl (sock); - pgm_rxw_state (window, skb, PGM_PKT_STATE_BACK_OFF); - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("NCF retry #%u attempt %u/%u."), skb->sequence, state->ncf_retry_count, sock->nak_ncf_retries); - } - } - else - { -/* packet expires some time later */ - pgm_trace(PGM_LOG_ROLE_RX_WINDOW,_("NCF retry #%u is delayed %f seconds."), - skb->sequence, pgm_to_secsf (state->timer_expiry - now)); - break; - } - - list = next_list_el; - } - - if (window->wait_ncf_queue.length == 0) - { - pgm_assert ((pgm_rxw_state_t*)window->wait_ncf_queue.head == NULL); - pgm_assert ((pgm_rxw_state_t*)window->wait_ncf_queue.tail == NULL); - } - else - { - pgm_assert ((pgm_rxw_state_t*)window->wait_ncf_queue.head != NULL); - pgm_assert ((pgm_rxw_state_t*)window->wait_ncf_queue.tail != NULL); - } - - if (PGM_UNLIKELY(dropped_invalid)) { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Dropped %u messages due to invalid NLA."), dropped_invalid); - } - - if (PGM_UNLIKELY(dropped)) { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Dropped %u messages due to ncf cancellation, " - "rxw_sqns %" PRIu32 - " bo %" PRIu32 - " ncf %" PRIu32 - " wd %" PRIu32 - " lost %" PRIu32 - " frag %" PRIu32), - dropped, - pgm_rxw_length (window), - window->nak_backoff_queue.length, - window->wait_ncf_queue.length, - window->wait_data_queue.length, - window->lost_count, - window->fragment_count); - } - -/* mark receiver window for flushing on next recv() */ - if (PGM_UNLIKELY(window->cumulative_losses != peer->last_cumulative_losses && - !peer->pending_link.data)) - { - sock->is_reset = TRUE; - peer->lost_count = window->cumulative_losses - peer->last_cumulative_losses; - peer->last_cumulative_losses = window->cumulative_losses; - pgm_peer_set_pending (sock, peer); - } - - if (window->wait_ncf_queue.tail) - { - if (next_nak_rpt_expiry (window) > now) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiry set in %f seconds."), pgm_to_secsf (next_nak_rpt_expiry (window) - now)); - } else { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiry set in -%f seconds."), pgm_to_secsf (now - next_nak_rpt_expiry (window))); - } - } - else - { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Wait ncf queue empty.")); - } -} - -/* check WAIT_DATA_STATE, on expiration move back to BACK-OFF_STATE, on exceeding NAK_DATA_RETRIES - * canel the sequence number. - */ -static -void -nak_rdata_state ( - pgm_peer_t* peer, - const pgm_time_t now - ) -{ -/* pre-conditions */ - pgm_assert (NULL != peer); - - pgm_debug ("nak_rdata_state (peer:%p now:%" PGM_TIME_FORMAT ")", - (const void*)peer, now); - - pgm_rxw_t* window = peer->window; - pgm_sock_t* sock = peer->sock; - pgm_list_t* list = window->wait_data_queue.tail; - - unsigned dropped_invalid = 0; - unsigned dropped = 0; - -/* have not learned this peers NLA */ - const bool is_valid_nla = 0 != peer->nla.ss_family; - - while (list) - { - pgm_list_t* next_list_el = list->prev; - struct pgm_sk_buff_t* rdata_skb = (struct pgm_sk_buff_t*)list; - pgm_assert (NULL != rdata_skb); - pgm_rxw_state_t* rdata_state = (pgm_rxw_state_t*)&rdata_skb->cb; - -/* check this packet for state expiration */ - if (pgm_time_after_eq (now, rdata_state->timer_expiry)) - { - if (PGM_UNLIKELY(!is_valid_nla)) { - dropped_invalid++; - pgm_rxw_lost (window, rdata_skb->sequence); -/* mark receiver window for flushing on next recv() */ - pgm_peer_set_pending (sock, peer); - list = next_list_el; - continue; - } - - if (++rdata_state->data_retry_count >= sock->nak_data_retries) - { - dropped++; - cancel_skb (sock, peer, rdata_skb, now); - peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_DATA_RETRIES_EXCEEDED]++; - list = next_list_el; - continue; - } - -// rdata_state->timer_expiry += nak_rb_ivl(sock); - rdata_state->timer_expiry = now + nak_rb_ivl (sock); - pgm_rxw_state (window, rdata_skb, PGM_PKT_STATE_BACK_OFF); - -/* retry back to back-off state */ - pgm_trace(PGM_LOG_ROLE_RX_WINDOW,_("Data retry #%u attempt %u/%u."), rdata_skb->sequence, rdata_state->data_retry_count, sock->nak_data_retries); - } - else - { /* packet expires some time later */ - break; - } - - - list = next_list_el; - } - - if (window->wait_data_queue.length == 0) - { - pgm_assert (NULL == (pgm_rxw_state_t*)window->wait_data_queue.head); - pgm_assert (NULL == (pgm_rxw_state_t*)window->wait_data_queue.tail); - } - else - { - pgm_assert (NULL != (pgm_rxw_state_t*)window->wait_data_queue.head); - pgm_assert (NULL != (pgm_rxw_state_t*)window->wait_data_queue.tail); - } - - if (PGM_UNLIKELY(dropped_invalid)) { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Dropped %u messages due to invalid NLA."), dropped_invalid); - } - - if (PGM_UNLIKELY(dropped)) { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Dropped %u messages due to data cancellation."), dropped); - } - -/* mark receiver window for flushing on next recv() */ - if (PGM_UNLIKELY(window->cumulative_losses != peer->last_cumulative_losses && - !peer->pending_link.data)) - { - sock->is_reset = TRUE; - peer->lost_count = window->cumulative_losses - peer->last_cumulative_losses; - peer->last_cumulative_losses = window->cumulative_losses; - pgm_peer_set_pending (sock, peer); - } - - if (window->wait_data_queue.tail) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiry set in %f seconds."), pgm_to_secsf (next_nak_rdata_expiry (window) - now)); - } else { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Wait data queue empty.")); - } -} - -/* ODATA or RDATA packet with any of the following options: - * - * OPT_FRAGMENT - this TPDU part of a larger APDU. - * - * Ownership of skb is taken and must be passed to the receive window or destroyed. - * - * returns TRUE is skb has been replaced, FALSE is remains unchanged and can be recycled. - */ - -bool -pgm_on_data ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict source, - struct pgm_sk_buff_t* const restrict skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != source); - pgm_assert (NULL != skb); - - pgm_debug ("pgm_on_data (sock:%p source:%p skb:%p)", - (void*)sock, (void*)source, (void*)skb); - - unsigned msg_count = 0; - const pgm_time_t nak_rb_expiry = skb->tstamp + nak_rb_ivl (sock); - pgm_time_t ack_rb_expiry = 0; - const unsigned tsdu_length = ntohs (skb->pgm_header->pgm_tsdu_length); - - skb->pgm_data = skb->data; - - const unsigned opt_total_length = (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) ? ntohs(*(uint16_t*)( (char*)( skb->pgm_data + 1 ) + sizeof(uint16_t))) : 0; - -/* advance data pointer to payload */ - pgm_skb_pull (skb, sizeof(struct pgm_data) + opt_total_length); - - if (opt_total_length > 0 && /* there are options */ - get_pgm_options (skb) && /* valid options */ - sock->use_pgmcc && /* PGMCC is enabled */ - NULL != skb->pgm_opt_pgmcc_data && /* PGMCC options */ - 0 == source->ack_rb_expiry) /* not partaking in a current election */ - { - ack_rb_expiry = skb->tstamp + ack_rb_ivl (sock); - } - - const int add_status = pgm_rxw_add (source->window, skb, skb->tstamp, nak_rb_expiry); - -/* skb reference is now invalid */ - bool flush_naks = FALSE; - - switch (add_status) { - case PGM_RXW_MISSING: - flush_naks = TRUE; -/* fall through */ - case PGM_RXW_INSERTED: - case PGM_RXW_APPENDED: - msg_count++; - break; - - case PGM_RXW_DUPLICATE: - source->cumulative_stats[PGM_PC_RECEIVER_DUP_DATAS]++; - goto discarded; - - case PGM_RXW_MALFORMED: - source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_ODATA]++; -/* fall through */ - case PGM_RXW_BOUNDS: -discarded: - return FALSE; - - default: pgm_assert_not_reached(); break; - } - -/* valid data */ - PGM_HISTOGRAM_COUNTS("Rx.DataBytesReceived", tsdu_length); - source->cumulative_stats[PGM_PC_RECEIVER_DATA_BYTES_RECEIVED] += tsdu_length; - source->cumulative_stats[PGM_PC_RECEIVER_DATA_MSGS_RECEIVED] += msg_count; - -/* congestion control */ - if (0 != ack_rb_expiry) - { -/* save source timestamp and local timestamp for RTT calculation */ - source->ack_last_tstamp = ntohl (skb->pgm_opt_pgmcc_data->opt_tstamp); - source->last_data_tstamp = skb->tstamp; - if (_pgm_is_acker (source, skb)) - { - if (PGM_UNLIKELY(pgm_sockaddr_is_addr_unspecified ((struct sockaddr*)&source->nla))) - { - pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Unable to send ACK due to unknown NLA.")); - } - else if (PGM_UNLIKELY(!send_ack (sock, source, skb->tstamp))) - { - pgm_debug ("send_ack failed"); - } - ack_rb_expiry = 0; - } - else if (_pgm_is_acker_election (skb)) - { - pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("ACKer election.")); - _pgm_add_ack (source, ack_rb_expiry); - } - else if (0 != source->window->ack_backoff_queue.length) - { -/* purge ACK backoff queue as host is not elected ACKer */ - _pgm_remove_ack (source); - ack_rb_expiry = 0; - } - else - { -/* no election, not the elected ACKer, no outstanding ACKs */ - ack_rb_expiry = 0; - } - } - - if (flush_naks || 0 != ack_rb_expiry) { -/* flush out 1st time nak packets */ - pgm_timer_lock (sock); - if (flush_naks && pgm_time_after (sock->next_poll, nak_rb_expiry)) - sock->next_poll = nak_rb_expiry; - if (0 != ack_rb_expiry && pgm_time_after (sock->next_poll, ack_rb_expiry)) - sock->next_poll = ack_rb_expiry; - pgm_timer_unlock (sock); - } - return TRUE; -} - -/* POLLs are generated by PGM Parents (Sources or Network Elements). - * - * returns TRUE on valid packet, FALSE on invalid packet. - */ - -bool -pgm_on_poll ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict source, - struct pgm_sk_buff_t* const restrict skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != source); - pgm_assert (NULL != skb); - - pgm_debug ("pgm_on_poll (sock:%p source:%p skb:%p)", - (void*)sock, (void*)source, (void*)skb); - - if (PGM_UNLIKELY(!pgm_verify_poll (skb))) { - pgm_trace(PGM_LOG_ROLE_NETWORK,_("Discarded invalid POLL.")); - return FALSE; - } - - struct pgm_poll* poll4 = (struct pgm_poll*) skb->data; - struct pgm_poll6* poll6 = (struct pgm_poll6*)skb->data; - uint32_t poll_rand; - memcpy (&poll_rand, (AFI_IP6 == ntohs (poll4->poll_nla_afi)) ? poll6->poll6_rand : poll4->poll_rand, sizeof(poll_rand)); - const uint32_t poll_mask = (AFI_IP6 == ntohs (poll4->poll_nla_afi)) ? ntohl (poll6->poll6_mask) : ntohl (poll4->poll_mask); - -/* Check for probability match */ - if (poll_mask && - (sock->rand_node_id & poll_mask) != poll_rand) - { -/* discard early */ - return FALSE; - } - -/* scoped per path nla - * TODO: manage list of pollers per peer - */ - const uint32_t poll_sqn = ntohl (poll4->poll_sqn); - const uint16_t poll_round = ntohs (poll4->poll_round); - -/* Check for new poll round */ - if (poll_round && - poll_sqn != source->last_poll_sqn) - { - return FALSE; - } - -/* save sequence and round of valid poll */ - source->last_poll_sqn = poll_sqn; - source->last_poll_round = poll_round; - - const uint16_t poll_s_type = ntohs (poll4->poll_s_type); - -/* Check poll type */ - switch (poll_s_type) { - case PGM_POLL_GENERAL: - return on_general_poll (sock, source, skb); - - case PGM_POLL_DLR: - return on_dlr_poll (sock, source, skb); - - default: -/* unknown sub-type, discard */ - break; - } - - return FALSE; -} - -/* Used to count PGM children */ - -static -bool -on_general_poll ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict source, - struct pgm_sk_buff_t* const restrict skb - ) -{ - struct pgm_poll* poll4 = (struct pgm_poll*) skb->data; - struct pgm_poll6* poll6 = (struct pgm_poll6*)skb->data; - -/* TODO: cancel any pending poll-response */ - -/* defer response based on provided back-off interval */ - const uint32_t poll_bo_ivl = (AFI_IP6 == ntohs (poll4->poll_nla_afi)) ? ntohl (poll6->poll6_bo_ivl) : ntohl (poll4->poll_bo_ivl); - source->polr_expiry = skb->tstamp + pgm_rand_int_range (&sock->rand_, 0, poll_bo_ivl); - pgm_nla_to_sockaddr (&poll4->poll_nla_afi, (struct sockaddr*)&source->poll_nla); -/* TODO: schedule poll-response */ - - return TRUE; -} - -/* Used to count off-tree DLRs */ - -static -bool -on_dlr_poll ( - PGM_GNUC_UNUSED pgm_sock_t* const restrict sock, - PGM_GNUC_UNUSED pgm_peer_t* const restrict source, - PGM_GNUC_UNUSED struct pgm_sk_buff_t* const restrict skb - ) -{ -/* we are not a DLR */ - return FALSE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/receiver_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/receiver_unittest.c deleted file mode 100644 index 5221a0b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/receiver_unittest.c +++ /dev/null @@ -1,857 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for PGM receiver transport. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include - - -/* mock state */ - -#define TEST_NETWORK "" -#define TEST_PORT 7500 -#define TEST_MAX_TPDU 1500 -#define TEST_TXW_SQNS 32 -#define TEST_RXW_SQNS 32 -#define TEST_HOPS 16 -#define TEST_SPM_AMBIENT ( pgm_secs(30) ) -#define TEST_SPM_HEARTBEAT_INIT { pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(1300), pgm_secs(7), pgm_secs(16), pgm_secs(25), pgm_secs(30) } -#define TEST_PEER_EXPIRY ( pgm_secs(300) ) -#define TEST_SPMR_EXPIRY ( pgm_msecs(250) ) -#define TEST_NAK_BO_IVL ( pgm_msecs(50) ) -#define TEST_NAK_RPT_IVL ( pgm_secs(2) ) -#define TEST_NAK_RDATA_IVL ( pgm_secs(2) ) -#define TEST_NAK_DATA_RETRIES 5 -#define TEST_NAK_NCF_RETRIES 2 - - -#define pgm_histogram_add mock_pgm_histogram_add -#define pgm_verify_spm mock_pgm_verify_spm -#define pgm_verify_nak mock_pgm_verify_nak -#define pgm_verify_ncf mock_pgm_verify_ncf -#define pgm_verify_poll mock_pgm_verify_poll -#define pgm_sendto mock_pgm_sendto -#define pgm_time_now mock_pgm_time_now -#define pgm_time_update_now mock_pgm_time_update_now -#define pgm_rxw_destroy mock_pgm_rxw_destroy -#define pgm_rxw_create mock_pgm_rxw_create -#define pgm_rxw_update mock_pgm_rxw_update -#define pgm_rxw_update_fec mock_pgm_rxw_update_fec -#define pgm_rxw_confirm mock_pgm_rxw_confirm -#define pgm_rxw_lost mock_pgm_rxw_lost -#define pgm_rxw_state mock_pgm_rxw_state -#define pgm_rxw_add mock_pgm_rxw_add -#define pgm_rxw_remove_commit mock_pgm_rxw_remove_commit -#define pgm_rxw_readv mock_pgm_rxw_readv -#define pgm_csum_fold mock_pgm_csum_fold -#define pgm_compat_csum_partial mock_pgm_compat_csum_partial -#define pgm_histogram_init mock_pgm_histogram_init - - -#define RECEIVER_DEBUG -#include "receiver.c" - - -static -void -mock_setup (void) -{ - if (!g_thread_supported ()) g_thread_init (NULL); -} - -static -struct pgm_sock_t* -generate_sock (void) -{ - struct pgm_sock_t* sock = g_malloc0 (sizeof(struct pgm_sock_t)); - return sock; -} - -static -pgm_peer_t* -generate_peer (void) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_peer_t* peer = g_malloc0 (sizeof(pgm_peer_t)); - peer->window = g_malloc0 (sizeof(pgm_rxw_t)); - pgm_atomic_inc32 (&peer->ref_count); - return peer; -} - -/** socket module */ -static -int -mock_pgm_poll_info ( - pgm_sock_t* const sock, - struct pollfd* fds, - int* n_fds, - int events - ) -{ -} - -static -gboolean -mock_pgm_on_nak ( - pgm_sock_t* const sock, - struct pgm_sk_buff_t* const skb - ) -{ - return TRUE; -} - -static -gboolean -mock_pgm_on_nnak ( - pgm_sock_t* const sock, - struct pgm_sk_buff_t* const skb - ) -{ - return TRUE; -} - -static -gboolean -mock_pgm_on_spmr ( - pgm_sock_t* const sock, - pgm_peer_t* const peer, - struct pgm_sk_buff_t* const skb - ) -{ - return TRUE; -} - -/** net module */ -PGM_GNUC_INTERNAL -ssize_t -mock_pgm_sendto ( - pgm_sock_t* sock, - bool use_rate_limit, - bool use_router_alert, - const void* buf, - size_t len, - const struct sockaddr* to, - socklen_t tolen - ) -{ - return len; -} - -/** time module */ -static pgm_time_t mock_pgm_time_now = 0x1; -static pgm_time_t _mock_pgm_time_update_now (void); -pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; - -pgm_time_t -_mock_pgm_time_update_now (void) -{ - return mock_pgm_time_now; -} - -/* packet module */ -bool -mock_pgm_verify_spm ( - const struct pgm_sk_buff_t* const skb - ) -{ - return TRUE; -} - -bool -mock_pgm_verify_nak ( - const struct pgm_sk_buff_t* const skb - ) -{ - return TRUE; -} - -bool -mock_pgm_verify_ncf ( - const struct pgm_sk_buff_t* const skb - ) -{ - return TRUE; -} - -bool -mock_pgm_verify_poll ( - const struct pgm_sk_buff_t* const skb - ) -{ - return TRUE; -} - -/* receive window module */ -pgm_rxw_t* -mock_pgm_rxw_create ( - const pgm_tsi_t* tsi, - const uint16_t tpdu_size, - const unsigned sqns, - const unsigned secs, - const ssize_t max_rte, - const uint32_t ack_c_p - ) -{ - return g_malloc0 (sizeof(pgm_rxw_t)); -} - -void -mock_pgm_rxw_destroy ( - pgm_rxw_t* const window - ) -{ - g_assert (NULL != window); - g_free (window); -} - -int -mock_pgm_rxw_confirm ( - pgm_rxw_t* const window, - const uint32_t sequence, - const pgm_time_t now, - const pgm_time_t nak_rdata_expiry, - const pgm_time_t nak_rb_expiry - ) -{ - return PGM_RXW_DUPLICATE; -} - -void -mock_pgm_rxw_lost ( - pgm_rxw_t* const window, - const uint32_t sequence - ) -{ -} - -void -mock_pgm_rxw_state ( - pgm_rxw_t* const window, - struct pgm_sk_buff_t* const skb, - const int new_state - ) -{ -} - -unsigned -mock_pgm_rxw_update ( - pgm_rxw_t* const window, - const uint32_t txw_lead, - const uint32_t txw_trail, - const pgm_time_t now, - const pgm_time_t nak_rb_expiry - ) -{ - return 0; -} - -void -mock_pgm_rxw_update_fec ( - pgm_rxw_t* const window, - const uint8_t rs_k - ) -{ -} - -int -mock_pgm_rxw_add ( - pgm_rxw_t* const window, - struct pgm_sk_buff_t* const skb, - const pgm_time_t now, - const pgm_time_t nak_rb_expiry - ) -{ - return PGM_RXW_APPENDED; -} - -void -mock_pgm_rxw_remove_commit ( - pgm_rxw_t* const window - ) -{ -} - -ssize_t -mock_pgm_rxw_readv ( - pgm_rxw_t* const window, - struct pgm_msgv_t** pmsg, - const unsigned pmsglen - ) -{ - return 0; -} - -/* checksum module */ -uint16_t -mock_pgm_csum_fold ( - uint32_t csum - ) -{ - return 0x0; -} - -uint32_t -mock_pgm_compat_csum_partial ( - const void* addr, - uint16_t len, - uint32_t csum - ) -{ - return 0x0; -} - -void -mock_pgm_histogram_init ( - pgm_histogram_t* histogram - ) -{ -} - -void -mock_pgm_histogram_add ( - pgm_histogram_t* histogram, - int value - ) -{ -} - -/* mock functions for external references */ - -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return 0; -} - - -/* target: - * void - * pgm_peer_unref ( - * pgm_peer_t* peer - * ) - */ - -/* last ref */ -START_TEST (test_peer_unref_pass_001) -{ - pgm_peer_t* peer = generate_peer(); - pgm_peer_unref (peer); -} -END_TEST - -/* non-last ref */ -START_TEST (test_peer_unref_pass_002) -{ - pgm_peer_t* peer = _pgm_peer_ref (generate_peer()); - pgm_peer_unref (peer); -} -END_TEST - - -START_TEST (test_peer_unref_fail_001) -{ - pgm_peer_unref (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_check_peer_state ( - * pgm_sock_t* sock, - * const pgm_time_t now - * ) - */ - -START_TEST (test_check_peer_state_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - sock->is_bound = TRUE; - pgm_check_peer_state (sock, mock_pgm_time_now); -} -END_TEST - -START_TEST (test_check_peer_state_fail_001) -{ - pgm_check_peer_state (NULL, mock_pgm_time_now); - fail ("reached"); -} -END_TEST - -/* target: - * pgm_time_t - * pgm_min_receiver_expiry ( - * pgm_time_t expiration, - * pgm_sock_t* sock - * ) - */ - -START_TEST (test_min_receiver_expiry_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - sock->is_bound = TRUE; - const pgm_time_t expiration = pgm_secs(1); - pgm_time_t next_expiration = pgm_min_receiver_expiry (expiration, sock); -} -END_TEST - -START_TEST (test_min_receiver_expiry_fail_001) -{ - const pgm_time_t expiration = pgm_secs(1); - pgm_min_receiver_expiry (expiration, NULL); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_RXW_SQNS - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_rxw_sqns_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - const int optname = PGM_RXW_SQNS; - const int rxw_sqns = 100; - const void* optval = &rxw_sqns; - const socklen_t optlen = sizeof(int); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_rxw_sqns failed"); -} -END_TEST - -START_TEST (test_set_rxw_sqns_fail_001) -{ - const int optname = PGM_RXW_SQNS; - const int rxw_sqns = 100; - const void* optval = &rxw_sqns; - const socklen_t optlen = sizeof(int); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_rxw_sqns failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_RXW_SECS, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_rxw_secs_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - const int optname = PGM_RXW_SECS; - const int rxw_secs = 10; - const void* optval = &rxw_secs; - const socklen_t optlen = sizeof(int); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_rxw_secs failed"); -} -END_TEST - -START_TEST (test_set_rxw_secs_fail_001) -{ - const int optname = PGM_RXW_SECS; - const int rxw_secs = 10; - const void* optval = &rxw_secs; - const socklen_t optlen = sizeof(int); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_rxw_secs failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_RXW_MAX_RTE, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_rxw_max_rte_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - const int optname = PGM_RXW_MAX_RTE; - const int rxw_max_rte = 100*1000; - const void* optval = &rxw_max_rte; - const socklen_t optlen = sizeof(int); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_rxw_max_rte failed"); -} -END_TEST - -START_TEST (test_set_rxw_max_rte_fail_001) -{ - const int optname = PGM_RXW_MAX_RTE; - const int rxw_max_rte = 100*1000; - const void* optval = &rxw_max_rte; - const socklen_t optlen = sizeof(int); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_rxw_max_rte failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_PEER_EXPIRY, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_peer_expiry_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - const int optname = PGM_PEER_EXPIRY; - const int peer_expiry = pgm_secs(100); - const void* optval = &peer_expiry; - const socklen_t optlen = sizeof(int); -/* pre-checking should verify value to spm ambient interval - sock->spm_ambient_interval = pgm_secs(30); - */ - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_peer_expiry failed"); -} -END_TEST - -START_TEST (test_set_peer_expiry_fail_001) -{ - const int optname = PGM_PEER_EXPIRY; - const int peer_expiry = pgm_secs(100); - const void* optval = &peer_expiry; - const socklen_t optlen = sizeof(int); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_peer_expiry failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_SPMR_EXPIRY, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_spmr_expiry_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - const int optname = PGM_SPMR_EXPIRY; - const int spmr_expiry = pgm_secs(10); - const void* optval = &spmr_expiry; - const socklen_t optlen = sizeof(int); -/* pre-checking should verify value to spm ambient interval - sock->spm_ambient_interval = pgm_secs(30); - */ - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_spmr_expiry failed"); -} -END_TEST - -START_TEST (test_set_spmr_expiry_fail_001) -{ - const int optname = PGM_SPMR_EXPIRY; - const int spmr_expiry = pgm_secs(10); - const void* optval = &spmr_expiry; - const socklen_t optlen = sizeof(int); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_spmr_expiry failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_NAK_BO_IVL, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_nak_bo_ivl_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - const int optname = PGM_NAK_BO_IVL; - const int nak_bo_ivl = pgm_msecs(1000); - const void* optval = &nak_bo_ivl; - const socklen_t optlen = sizeof(int); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_nak_bo_ivl failed"); -} -END_TEST - -START_TEST (test_set_nak_bo_ivl_fail_001) -{ - const int optname = PGM_NAK_BO_IVL; - const int nak_bo_ivl = pgm_msecs(1000); - const void* optval = &nak_bo_ivl; - const socklen_t optlen = sizeof(int); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_nak_bo_ivl failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_NAK_RPT_IVL, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_nak_rpt_ivl_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - const int optname = PGM_NAK_RPT_IVL; - const int nak_rpt_ivl = pgm_msecs(1000); - const void* optval = &nak_rpt_ivl; - const socklen_t optlen = sizeof(int); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_nak_rpt_ivl failed"); -} -END_TEST - -START_TEST (test_set_nak_rpt_ivl_fail_001) -{ - const int optname = PGM_NAK_RPT_IVL; - const int nak_rpt_ivl = pgm_msecs(1000); - const void* optval = &nak_rpt_ivl; - const socklen_t optlen = sizeof(int); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_nak_rpt_ivl failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_NAK_RDATA_IVL, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_nak_rdata_ivl_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - const int optname = PGM_NAK_RDATA_IVL; - const int nak_rdata_ivl = pgm_msecs(1000); - const void* optval = &nak_rdata_ivl; - const socklen_t optlen = sizeof(int); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_nak_rdata_ivl failed"); -} -END_TEST - -START_TEST (test_set_nak_rdata_ivl_fail_001) -{ - const int optname = PGM_NAK_RDATA_IVL; - const int nak_rdata_ivl = pgm_msecs(1000); - const void* optval = &nak_rdata_ivl; - const socklen_t optlen = sizeof(int); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_nak_rdata_ivl failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_NAK_DATA_RETRIES, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_nak_data_retries_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - const int optname = PGM_NAK_DATA_RETRIES; - const int retries = 1000; - const void* optval = &retries; - const socklen_t optlen = sizeof(int); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_nak_data_retries failed"); -} -END_TEST - -START_TEST (test_set_nak_data_retries_fail_001) -{ - const int optname = PGM_NAK_DATA_RETRIES; - const int retries = 1000; - const void* optval = &retries; - const socklen_t optlen = sizeof(int); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_nak_data_retries failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_NAK_NCF_RETRIES, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_nak_ncf_retries_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - const int optname = PGM_NAK_NCF_RETRIES; - const int retries = 1000; - const void* optval = &retries; - const socklen_t optlen = sizeof(int); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_ncf_data_retries failed"); -} -END_TEST - -START_TEST (test_set_nak_ncf_retries_fail_001) -{ - const int optname = PGM_NAK_NCF_RETRIES; - const int retries = 1000; - const void* optval = &retries; - const socklen_t optlen = sizeof(int); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_ncf_data_retries failed"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_peer_unref = tcase_create ("peer_unref"); - suite_add_tcase (s, tc_peer_unref); - tcase_add_checked_fixture (tc_peer_unref, mock_setup, NULL); - tcase_add_test (tc_peer_unref, test_peer_unref_pass_001); - tcase_add_test_raise_signal (tc_peer_unref, test_peer_unref_fail_001, SIGABRT); - -/* formally check-peer-nak-state */ - TCase* tc_check_peer_state = tcase_create ("check-peer-state"); - suite_add_tcase (s, tc_check_peer_state); - tcase_add_checked_fixture (tc_check_peer_state, mock_setup, NULL); - tcase_add_test (tc_check_peer_state, test_check_peer_state_pass_001); - tcase_add_test_raise_signal (tc_check_peer_state, test_check_peer_state_fail_001, SIGABRT); - -/* formally min-nak-expiry */ - TCase* tc_min_receiver_expiry = tcase_create ("min-receiver-expiry"); - suite_add_tcase (s, tc_min_receiver_expiry); - tcase_add_checked_fixture (tc_min_receiver_expiry, mock_setup, NULL); - tcase_add_test (tc_min_receiver_expiry, test_min_receiver_expiry_pass_001); - tcase_add_test_raise_signal (tc_min_receiver_expiry, test_min_receiver_expiry_fail_001, SIGABRT); - - TCase* tc_set_rxw_sqns = tcase_create ("set-rxw_sqns"); - suite_add_tcase (s, tc_set_rxw_sqns); - tcase_add_checked_fixture (tc_set_rxw_sqns, mock_setup, NULL); - tcase_add_test (tc_set_rxw_sqns, test_set_rxw_sqns_pass_001); - tcase_add_test (tc_set_rxw_sqns, test_set_rxw_sqns_fail_001); - - TCase* tc_set_rxw_secs = tcase_create ("set-rxw-secs"); - suite_add_tcase (s, tc_set_rxw_secs); - tcase_add_checked_fixture (tc_set_rxw_secs, mock_setup, NULL); - tcase_add_test (tc_set_rxw_secs, test_set_rxw_secs_pass_001); - tcase_add_test (tc_set_rxw_secs, test_set_rxw_secs_fail_001); - - TCase* tc_set_rxw_max_rte = tcase_create ("set-rxw-max-rte"); - suite_add_tcase (s, tc_set_rxw_max_rte); - tcase_add_checked_fixture (tc_set_rxw_max_rte, mock_setup, NULL); - tcase_add_test (tc_set_rxw_max_rte, test_set_rxw_max_rte_pass_001); - tcase_add_test (tc_set_rxw_max_rte, test_set_rxw_max_rte_fail_001); - - TCase* tc_set_peer_expiry = tcase_create ("set-peer-expiry"); - suite_add_tcase (s, tc_set_peer_expiry); - tcase_add_checked_fixture (tc_set_peer_expiry, mock_setup, NULL); - tcase_add_test (tc_set_peer_expiry, test_set_peer_expiry_pass_001); - tcase_add_test (tc_set_peer_expiry, test_set_peer_expiry_fail_001); - - TCase* tc_set_spmr_expiry = tcase_create ("set-spmr-expiry"); - suite_add_tcase (s, tc_set_spmr_expiry); - tcase_add_checked_fixture (tc_set_spmr_expiry, mock_setup, NULL); - tcase_add_test (tc_set_spmr_expiry, test_set_spmr_expiry_pass_001); - tcase_add_test (tc_set_spmr_expiry, test_set_spmr_expiry_fail_001); - - TCase* tc_set_nak_bo_ivl = tcase_create ("set-nak-bo-ivl"); - suite_add_tcase (s, tc_set_nak_bo_ivl); - tcase_add_checked_fixture (tc_set_nak_bo_ivl, mock_setup, NULL); - tcase_add_test (tc_set_nak_bo_ivl, test_set_nak_bo_ivl_pass_001); - tcase_add_test (tc_set_nak_bo_ivl, test_set_nak_bo_ivl_fail_001); - - TCase* tc_set_nak_rpt_ivl = tcase_create ("set-nak-rpt-ivl"); - suite_add_tcase (s, tc_set_nak_rpt_ivl); - tcase_add_checked_fixture (tc_set_nak_rpt_ivl, mock_setup, NULL); - tcase_add_test (tc_set_nak_rpt_ivl, test_set_nak_rpt_ivl_pass_001); - tcase_add_test (tc_set_nak_rpt_ivl, test_set_nak_rpt_ivl_fail_001); - - TCase* tc_set_nak_rdata_ivl = tcase_create ("set-nak-rdata-ivl"); - suite_add_tcase (s, tc_set_nak_rdata_ivl); - tcase_add_checked_fixture (tc_set_nak_rdata_ivl, mock_setup, NULL); - tcase_add_test (tc_set_nak_rdata_ivl, test_set_nak_rdata_ivl_pass_001); - tcase_add_test (tc_set_nak_rdata_ivl, test_set_nak_rdata_ivl_fail_001); - - TCase* tc_set_nak_data_retries = tcase_create ("set-nak-data-retries"); - suite_add_tcase (s, tc_set_nak_data_retries); - tcase_add_checked_fixture (tc_set_nak_data_retries, mock_setup, NULL); - tcase_add_test (tc_set_nak_data_retries, test_set_nak_data_retries_pass_001); - tcase_add_test (tc_set_nak_data_retries, test_set_nak_data_retries_fail_001); - - TCase* tc_set_nak_ncf_retries = tcase_create ("set-nak-ncf-retries"); - suite_add_tcase (s, tc_set_nak_ncf_retries); - tcase_add_checked_fixture (tc_set_nak_ncf_retries, mock_setup, NULL); - tcase_add_test (tc_set_nak_ncf_retries, test_set_nak_ncf_retries_pass_001); - tcase_add_test (tc_set_nak_ncf_retries, test_set_nak_ncf_retries_fail_001); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/recv.c b/3rdparty/openpgm-svn-r1085/pgm/recv.c deleted file mode 100644 index 63cbce5..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/recv.c +++ /dev/null @@ -1,1059 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Transport recv API. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define _GNU_SOURCE -#include -#ifndef _WIN32 -# include -# include -# include /* _GNU_SOURCE for in6_pktinfo */ -#else -# include -# include -#endif -#include -#include -#include -#include -#include -#include - - -//#define RECV_DEBUG - -#ifndef RECV_DEBUG -# define PGM_DISABLE_ASSERT -#endif - -#ifdef _WIN32 -# define cmsghdr wsacmsghdr -# define CMSG_FIRSTHDR(msg) WSA_CMSG_FIRSTHDR(msg) -# define CMSG_NXTHDR(msg, cmsg) WSA_CMSG_NXTHDR(msg, cmsg) -# define CMSG_DATA(cmsg) WSA_CMSG_DATA(cmsg) -# define CMSG_SPACE(len) WSA_CMSG_SPACE(len) -# define CMSG_LEN(len) WSA_CMSG_LEN(len) -#endif - - -/* read a packet into a PGM skbuff - * on success returns packet length, on closed socket returns 0, - * on error returns -1. - */ - -static -ssize_t -recvskb ( - pgm_sock_t* const restrict sock, - struct pgm_sk_buff_t* const restrict skb, - const int flags, - struct sockaddr* const restrict src_addr, - const socklen_t src_addrlen, - struct sockaddr* const restrict dst_addr, - const socklen_t dst_addrlen - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - pgm_assert (NULL != src_addr); - pgm_assert (src_addrlen > 0); - pgm_assert (NULL != dst_addr); - pgm_assert (dst_addrlen > 0); - - pgm_debug ("recvskb (sock:%p skb:%p flags:%d src-addr:%p src-addrlen:%d dst-addr:%p dst-addrlen:%d)", - (void*)sock, (void*)skb, flags, (void*)src_addr, (int)src_addrlen, (void*)dst_addr, (int)dst_addrlen); - - if (PGM_UNLIKELY(sock->is_destroyed)) - return 0; - -#ifdef CONFIG_TARGET_WINE - socklen_t fromlen = src_addrlen; - const ssize_t len = recvfrom (sock->recv_sock, skb->head, sock->max_tpdu, 0, src_addr, &fromlen); - if (len <= 0) - return len; -#else - struct pgm_iovec iov = { - .iov_base = skb->head, - .iov_len = sock->max_tpdu - }; - char aux[ 1024 ]; -# ifndef _WIN32 - struct msghdr msg = { - .msg_name = src_addr, - .msg_namelen = src_addrlen, - .msg_iov = (void*)&iov, - .msg_iovlen = 1, - .msg_control = aux, - .msg_controllen = sizeof(aux), - .msg_flags = 0 - }; - - ssize_t len = recvmsg (sock->recv_sock, &msg, flags); - if (len <= 0) - return len; -# else /* !_WIN32 */ - WSAMSG msg = { - .name = (LPSOCKADDR)src_addr, - .namelen = src_addrlen, - .lpBuffers = (LPWSABUF)&iov, - .dwBufferCount = 1, - .dwFlags = 0 - }; - msg.Control.buf = aux; - msg.Control.len = sizeof(aux); - DWORD len; - if (SOCKET_ERROR == pgm_WSARecvMsg (sock->recv_sock, &msg, &len, NULL, NULL)) { - return -1; - } -# endif /* !_WIN32 */ -#endif /* !CONFIG_TARGET_WINE */ - -#ifdef PGM_DEBUG - if (PGM_UNLIKELY(pgm_loss_rate > 0)) { - const unsigned percent = pgm_rand_int_range (&sock->rand_, 0, 100); - if (percent <= pgm_loss_rate) { - pgm_debug ("Simulated packet loss"); -# ifndef _WIN32 - errno = EAGAIN; -# else - WSASetLastError (WSAEWOULDBLOCK); -# endif - return -1; - } - } -#endif - - skb->sock = sock; - skb->tstamp = pgm_time_update_now(); - skb->data = skb->head; - skb->len = len; - skb->zero_padded = 0; - skb->tail = (char*)skb->data + len; - -#ifdef CONFIG_TARGET_WINE - pgm_assert (pgm_sockaddr_len (&sock->recv_gsr[0].gsr_group) <= dst_addrlen); - memcpy (dst_addr, &sock->recv_gsr[0].gsr_group, pgm_sockaddr_len (&sock->recv_gsr[0].gsr_group)); -#else - if (sock->udp_encap_ucast_port || - AF_INET6 == pgm_sockaddr_family (src_addr)) - { -#ifdef CONFIG_HAVE_WSACMSGHDR - WSACMSGHDR* cmsg; -#else - struct cmsghdr* cmsg; -#endif - for (cmsg = CMSG_FIRSTHDR(&msg); - cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) - { -/* both IP_PKTINFO and IP_RECVDSTADDR exist on OpenSolaris, so capture - * each type if defined. - */ -#ifdef IP_PKTINFO - if (IPPROTO_IP == cmsg->cmsg_level && - IP_PKTINFO == cmsg->cmsg_type) - { - const void* pktinfo = CMSG_DATA(cmsg); -/* discard on invalid address */ - if (PGM_UNLIKELY(NULL == pktinfo)) { - pgm_debug ("in_pktinfo is NULL"); - return -1; - } - const struct in_pktinfo* in = pktinfo; - struct sockaddr_in s4; - memset (&s4, 0, sizeof(s4)); - s4.sin_family = AF_INET; - s4.sin_addr.s_addr = in->ipi_addr.s_addr; - memcpy (dst_addr, &s4, sizeof(s4)); - break; - } -#endif -#ifdef IP_RECVDSTADDR - if (IPPROTO_IP == cmsg->cmsg_level && - IP_RECVDSTADDR == cmsg->cmsg_type) - { - const void* recvdstaddr = CMSG_DATA(cmsg); -/* discard on invalid address */ - if (PGM_UNLIKELY(NULL == recvdstaddr)) { - pgm_debug ("in_recvdstaddr is NULL"); - return -1; - } - const struct in_addr* in = recvdstaddr; - struct sockaddr_in s4; - memset (&s4, 0, sizeof(s4)); - s4.sin_family = AF_INET; - s4.sin_addr.s_addr = in->s_addr; - memcpy (dst_addr, &s4, sizeof(s4)); - break; - } -#endif -#if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR) -# error "No defined CMSG type for IPv4 destination address." -#endif - - if (IPPROTO_IPV6 == cmsg->cmsg_level && - IPV6_PKTINFO == cmsg->cmsg_type) - { - const void* pktinfo = CMSG_DATA(cmsg); -/* discard on invalid address */ - if (PGM_UNLIKELY(NULL == pktinfo)) { - pgm_debug ("in6_pktinfo is NULL"); - return -1; - } - const struct in6_pktinfo* in6 = pktinfo; - struct sockaddr_in6 s6; - memset (&s6, 0, sizeof(s6)); - s6.sin6_family = AF_INET6; - s6.sin6_addr = in6->ipi6_addr; - s6.sin6_scope_id = in6->ipi6_ifindex; - memcpy (dst_addr, &s6, sizeof(s6)); -/* does not set flow id */ - break; - } - } - } -#endif - return len; -} - -/* upstream = receiver to source, peer-to-peer = receive to receiver - * - * NB: SPMRs can be upstream or peer-to-peer, if the packet is multicast then its - * a peer-to-peer message, if its unicast its an upstream message. - * - * returns TRUE on valid processed packet, returns FALSE on discarded packet. - */ - -static -bool -on_upstream ( - pgm_sock_t* const restrict sock, - struct pgm_sk_buff_t* const restrict skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - pgm_assert_cmpuint (skb->pgm_header->pgm_dport, ==, sock->tsi.sport); - - pgm_debug ("on_upstream (sock:%p skb:%p)", - (const void*)sock, (const void*)skb); - - if (PGM_UNLIKELY(!sock->can_send_data)) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet for muted source.")); - goto out_discarded; - } - -/* unicast upstream message, note that dport & sport are reversed */ - if (PGM_UNLIKELY(skb->pgm_header->pgm_sport != sock->dport)) { -/* its upstream/peer-to-peer for another session */ - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet on data-destination port mismatch.")); - goto out_discarded; - } - - if (PGM_UNLIKELY(!pgm_gsi_equal (&skb->tsi.gsi, &sock->tsi.gsi))) { -/* its upstream/peer-to-peer for another session */ - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet on data-destination port mismatch.")); - goto out_discarded; - } - -/* advance SKB pointer to PGM type header */ - skb->data = (char*)skb->data + sizeof(struct pgm_header); - skb->len -= sizeof(struct pgm_header); - - switch (skb->pgm_header->pgm_type) { - case PGM_NAK: - if (PGM_UNLIKELY(!pgm_on_nak (sock, skb))) - goto out_discarded; - break; - - case PGM_NNAK: - if (PGM_UNLIKELY(!pgm_on_nnak (sock, skb))) - goto out_discarded; - break; - - case PGM_SPMR: - if (PGM_UNLIKELY(!pgm_on_spmr (sock, NULL, skb))) - goto out_discarded; - break; - - case PGM_ACK: - if (PGM_UNLIKELY(!pgm_on_ack (sock, skb))) - goto out_discarded; - break; - - case PGM_POLR: - default: - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded unsupported PGM type packet.")); - goto out_discarded; - } - - return TRUE; -out_discarded: - sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]++; - return FALSE; -} - -/* peer to peer message, either multicast NAK or multicast SPMR. - * - * returns TRUE on valid processed packet, returns FALSE on discarded packet. - */ - -static -bool -on_peer ( - pgm_sock_t* const restrict sock, - struct pgm_sk_buff_t* const restrict skb, - pgm_peer_t** restrict source - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - pgm_assert_cmpuint (skb->pgm_header->pgm_dport, !=, sock->tsi.sport); - pgm_assert (NULL != source); - - pgm_debug ("on_peer (sock:%p skb:%p source:%p)", - (const void*)sock, (const void*)skb, (const void*)source); - -/* we are not the source */ - if (PGM_UNLIKELY(!sock->can_recv_data)) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet for muted receiver.")); - goto out_discarded; - } - -/* unicast upstream message, note that dport & sport are reversed */ - if (PGM_UNLIKELY(skb->pgm_header->pgm_sport != sock->dport)) { -/* its upstream/peer-to-peer for another session */ - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet on data-destination port mismatch.")); - goto out_discarded; - } - -/* check to see the source this peer-to-peer message is about is in our peer list */ - pgm_tsi_t upstream_tsi; - memcpy (&upstream_tsi.gsi, &skb->tsi.gsi, sizeof(pgm_gsi_t)); - upstream_tsi.sport = skb->pgm_header->pgm_dport; - - pgm_rwlock_reader_lock (&sock->peers_lock); - *source = pgm_hashtable_lookup (sock->peers_hashtable, &upstream_tsi); - pgm_rwlock_reader_unlock (&sock->peers_lock); - if (PGM_UNLIKELY(NULL == *source)) { -/* this source is unknown, we don't care about messages about it */ - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded peer packet about new source.")); - goto out_discarded; - } - -/* advance SKB pointer to PGM type header */ - skb->data = (char*)skb->data + sizeof(struct pgm_header); - skb->len -= sizeof(struct pgm_header); - - switch (skb->pgm_header->pgm_type) { - case PGM_NAK: - if (PGM_UNLIKELY(!pgm_on_peer_nak (sock, *source, skb))) - goto out_discarded; - break; - - case PGM_SPMR: - if (PGM_UNLIKELY(!pgm_on_spmr (sock, *source, skb))) - goto out_discarded; - break; - - case PGM_NNAK: - case PGM_POLR: - default: - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded unsupported PGM type packet.")); - goto out_discarded; - } - - return TRUE; -out_discarded: - if (*source) - (*source)->cumulative_stats[PGM_PC_RECEIVER_PACKETS_DISCARDED]++; - else if (sock->can_send_data) - sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]++; - return FALSE; -} - -/* source to receiver message - * - * returns TRUE on valid processed packet, returns FALSE on discarded packet. - */ - -static -bool -on_downstream ( - pgm_sock_t* const restrict sock, - struct pgm_sk_buff_t* const restrict skb, - struct sockaddr* const restrict src_addr, - struct sockaddr* const restrict dst_addr, - pgm_peer_t** restrict source - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - pgm_assert (NULL != src_addr); - pgm_assert (NULL != dst_addr); - pgm_assert (NULL != source); - -#ifdef RECV_DEBUG - char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop (src_addr, saddr, sizeof(saddr)); - pgm_sockaddr_ntop (dst_addr, daddr, sizeof(daddr)); - pgm_debug ("on_downstream (sock:%p skb:%p src-addr:%s dst-addr:%s source:%p)", - (const void*)sock, (const void*)skb, saddr, daddr, (const void*)source); -#endif - - if (PGM_UNLIKELY(!sock->can_recv_data)) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet for muted receiver.")); - goto out_discarded; - } - -/* pgm packet DPORT contains our sock DPORT */ - if (PGM_UNLIKELY(skb->pgm_header->pgm_dport != sock->dport)) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet on data-destination port mismatch.")); - goto out_discarded; - } - -/* search for TSI peer context or create a new one */ - if (PGM_LIKELY(pgm_tsi_hash (&skb->tsi) == sock->last_hash_key && - NULL != sock->last_hash_value)) - { - *source = sock->last_hash_value; - } - else - { - pgm_rwlock_reader_lock (&sock->peers_lock); - *source = pgm_hashtable_lookup_extended (sock->peers_hashtable, &skb->tsi, &sock->last_hash_key); - pgm_rwlock_reader_unlock (&sock->peers_lock); - if (PGM_UNLIKELY(NULL == *source)) { - *source = pgm_new_peer (sock, - &skb->tsi, - (struct sockaddr*)src_addr, pgm_sockaddr_len(src_addr), - (struct sockaddr*)dst_addr, pgm_sockaddr_len(dst_addr), - skb->tstamp); - } - sock->last_hash_value = *source; - } - - (*source)->cumulative_stats[PGM_PC_RECEIVER_BYTES_RECEIVED] += skb->len; - (*source)->last_packet = skb->tstamp; - - skb->data = (void*)( skb->pgm_header + 1 ); - skb->len -= sizeof(struct pgm_header); - -/* handle PGM packet type */ - switch (skb->pgm_header->pgm_type) { - case PGM_ODATA: - case PGM_RDATA: - if (PGM_UNLIKELY(!pgm_on_data (sock, *source, skb))) - goto out_discarded; - sock->rx_buffer = pgm_alloc_skb (sock->max_tpdu); - break; - - case PGM_NCF: - if (PGM_UNLIKELY(!pgm_on_ncf (sock, *source, skb))) - goto out_discarded; - break; - - case PGM_SPM: - if (PGM_UNLIKELY(!pgm_on_spm (sock, *source, skb))) - goto out_discarded; - -/* update group NLA if appropriate */ - if (PGM_LIKELY(pgm_sockaddr_is_addr_multicast ((struct sockaddr*)dst_addr))) - memcpy (&(*source)->group_nla, dst_addr, pgm_sockaddr_len(dst_addr)); - break; - -#ifdef CONFIG_PGM_POLLING - case PGM_POLL: - if (PGM_UNLIKELY(!pgm_on_poll (sock, *source, skb))) - goto out_discarded; - break; -#endif - - default: - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded unsupported PGM type packet.")); - goto out_discarded; - } - - return TRUE; -out_discarded: - if (*source) - (*source)->cumulative_stats[PGM_PC_RECEIVER_PACKETS_DISCARDED]++; - else if (sock->can_send_data) - sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]++; - return FALSE; -} - -/* process a pgm packet - * - * returns TRUE on valid processed packet, returns FALSE on discarded packet. - */ -static -bool -on_pgm ( - pgm_sock_t* const restrict sock, - struct pgm_sk_buff_t* const restrict skb, - struct sockaddr* const restrict src_addr, - struct sockaddr* const restrict dst_addr, - pgm_peer_t** restrict source - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - pgm_assert (NULL != src_addr); - pgm_assert (NULL != dst_addr); - pgm_assert (NULL != source); - -#ifdef RECV_DEBUG - char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop (src_addr, saddr, sizeof(saddr)); - pgm_sockaddr_ntop (dst_addr, daddr, sizeof(daddr)); - pgm_debug ("on_pgm (sock:%p skb:%p src-addr:%s dst-addr:%s source:%p)", - (const void*)sock, (const void*)skb, saddr, daddr, (const void*)source); -#endif - - if (PGM_IS_DOWNSTREAM (skb->pgm_header->pgm_type)) - return on_downstream (sock, skb, src_addr, dst_addr, source); - if (skb->pgm_header->pgm_dport == sock->tsi.sport) - { - if (PGM_IS_UPSTREAM (skb->pgm_header->pgm_type) || - PGM_IS_PEER (skb->pgm_header->pgm_type)) - { - return on_upstream (sock, skb); - } - } - else if (PGM_IS_PEER (skb->pgm_header->pgm_type)) - return on_peer (sock, skb, source); - - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded unknown PGM packet.")); - if (sock->can_send_data) - sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]++; - return FALSE; -} - -/* block on receiving socket whilst holding sock::waiting-mutex - * returns EAGAIN for waiting data, returns EINTR for waiting timer event, - * returns ENOENT on closed sock, and returns EFAULT for libc error. - */ - -static -int -wait_for_event ( - pgm_sock_t* const sock - ) -{ - int n_fds = 3; - -/* pre-conditions */ - pgm_assert (NULL != sock); - - pgm_debug ("wait_for_event (sock:%p)", (const void*)sock); - - do { - if (PGM_UNLIKELY(sock->is_destroyed)) - return ENOENT; - - if (sock->can_send_data && !pgm_txw_retransmit_is_empty (sock->window)) -/* tight loop on blocked send */ - pgm_on_deferred_nak (sock); - -#ifdef CONFIG_HAVE_POLL - struct pollfd fds[ n_fds ]; - memset (fds, 0, sizeof(fds)); - const int status = pgm_poll_info (sock, fds, &n_fds, POLLIN); - pgm_assert (-1 != status); -#else - fd_set readfds; - FD_ZERO(&readfds); - const int status = pgm_select_info (sock, &readfds, NULL, &n_fds); - pgm_assert (-1 != status); -#endif /* CONFIG_HAVE_POLL */ - -/* flush any waiting notifications */ - if (sock->is_pending_read) { - pgm_notify_clear (&sock->pending_notify); - sock->is_pending_read = FALSE; - } - - int timeout; - if (sock->can_send_data && !pgm_txw_retransmit_is_empty (sock->window)) - timeout = 0; - else - timeout = pgm_timer_expiration (sock); - -#ifdef CONFIG_HAVE_POLL - const int ready = poll (fds, n_fds, timeout /* μs */ / 1000 /* to ms */); -#else - struct timeval tv_timeout = { - .tv_sec = timeout > 1000000L ? timeout / 1000000UL : 0, - .tv_usec = timeout > 1000000L ? timeout % 1000000UL : timeout - }; - const int ready = select (n_fds, &readfds, NULL, NULL, &tv_timeout); -#endif - if (PGM_UNLIKELY(-1 == ready)) { - pgm_debug ("block returned errno=%i",errno); - return EFAULT; - } else if (ready > 0) { - pgm_debug ("recv again on empty"); - return EAGAIN; - } - } while (pgm_timer_check (sock)); - pgm_debug ("state generated event"); - return EINTR; -} - -/* data incoming on receive sockets, can be from a sender or receiver, or simply bogus. - * for IPv4 we receive the IP header to handle fragmentation, for IPv6 we cannot, but the - * underlying stack handles this for us. - * - * recvmsgv reads a vector of apdus each contained in a IO scatter/gather array. - * - * can be called due to event from incoming socket(s) or timer induced data loss. - * - * On success, returns PGM_IO_STATUS_NORMAL and saves the count of bytes read - * into _bytes_read. With non-blocking sockets a block returns - * PGM_IO_STATUS_WOULD_BLOCK. When rate limited sending repair data, returns - * PGM_IO_STATUS_RATE_LIMITED and caller should wait. During recovery state, - * returns PGM_IO_STATUS_TIMER_PENDING and caller should also wait. On - * unrecoverable dataloss, returns PGM_IO_STATUS_CONN_RESET. If connection is - * closed, returns PGM_IO_STATUS_EOF. On error, returns PGM_IO_STATUS_ERROR. - */ - -int -pgm_recvmsgv ( - pgm_sock_t* const restrict sock, - struct pgm_msgv_t* const restrict msg_start, - const size_t msg_len, - const int flags, /* MSG_DONTWAIT for non-blocking */ - size_t* restrict _bytes_read, /* may be NULL */ - pgm_error_t** restrict error - ) -{ - int status = PGM_IO_STATUS_WOULD_BLOCK; - - pgm_debug ("pgm_recvmsgv (sock:%p msg-start:%p msg-len:%zu flags:%d bytes-read:%p error:%p)", - (void*)sock, (void*)msg_start, msg_len, flags, (void*)_bytes_read, (void*)error); - -/* parameters */ - pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); - if (PGM_LIKELY(msg_len)) pgm_return_val_if_fail (NULL != msg_start, PGM_IO_STATUS_ERROR); - -/* shutdown */ - if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) - pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); - -/* state */ - if (PGM_UNLIKELY(!sock->is_bound || sock->is_destroyed)) - { - pgm_rwlock_reader_unlock (&sock->lock); - pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); - } - -/* pre-conditions */ - pgm_assert (NULL != sock->rx_buffer); - pgm_assert (sock->max_tpdu > 0); - if (sock->can_recv_data) { - pgm_assert (NULL != sock->peers_hashtable); - pgm_assert_cmpuint (sock->nak_bo_ivl, >, 1); - pgm_assert (pgm_notify_is_valid (&sock->pending_notify)); - } - -/* receiver */ - pgm_mutex_lock (&sock->receiver_mutex); - - if (PGM_UNLIKELY(sock->is_reset)) { - pgm_assert (NULL != sock->peers_pending); - pgm_assert (NULL != sock->peers_pending->data); - pgm_peer_t* peer = sock->peers_pending->data; - if (flags & MSG_ERRQUEUE) - pgm_set_reset_error (sock, peer, msg_start); - else if (error) { - char tsi[PGM_TSISTRLEN]; - pgm_tsi_print_r (&peer->tsi, tsi, sizeof(tsi)); - pgm_set_error (error, - PGM_ERROR_DOMAIN_RECV, - PGM_ERROR_CONNRESET, - _("Transport has been reset on unrecoverable loss from %s."), - tsi); - } - if (!sock->is_abort_on_reset) - sock->is_reset = !sock->is_reset; - pgm_mutex_unlock (&sock->receiver_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_RESET; - } - -/* timer status */ - if (pgm_timer_check (sock) && - !pgm_timer_dispatch (sock)) - { -/* block on send-in-recv */ - status = PGM_IO_STATUS_RATE_LIMITED; - } -/* NAK status */ - else if (sock->can_send_data) - { - if (!pgm_txw_retransmit_is_empty (sock->window)) - { - if (!pgm_on_deferred_nak (sock)) - status = PGM_IO_STATUS_RATE_LIMITED; - } - else - pgm_notify_clear (&sock->rdata_notify); - } - - size_t bytes_read = 0; - unsigned data_read = 0; - struct pgm_msgv_t* pmsg = msg_start; - const struct pgm_msgv_t* msg_end = msg_start + msg_len - 1; - - if (PGM_UNLIKELY(0 == ++(sock->last_commit))) - ++(sock->last_commit); - - /* second, flush any remaining contiguous messages from previous call(s) */ - if (sock->peers_pending) { - if (0 != pgm_flush_peers_pending (sock, &pmsg, msg_end, &bytes_read, &data_read)) - goto out; -/* returns on: reset or full buffer */ - } - -/* read the data: - * - * We cannot actually block here as packets pushed by the timers need to be addressed too. - */ - struct sockaddr_storage src, dst; - ssize_t len; - size_t bytes_received = 0; - -recv_again: - - len = recvskb (sock, - sock->rx_buffer, /* PGM skbuff */ - 0, - (struct sockaddr*)&src, - sizeof(src), - (struct sockaddr*)&dst, - sizeof(dst)); - if (len < 0) - { -#ifndef _WIN32 - const int save_errno = errno; - if (PGM_LIKELY(EAGAIN == save_errno)) { - goto check_for_repeat; - } - status = PGM_IO_STATUS_ERROR; - pgm_set_error (error, - PGM_ERROR_DOMAIN_RECV, - pgm_error_from_errno (save_errno), - _("Transport socket error: %s"), - strerror (save_errno)); -#else - const int save_wsa_errno = WSAGetLastError (); - if (PGM_LIKELY(WSAEWOULDBLOCK == save_wsa_errno)) { - goto check_for_repeat; - } - status = PGM_IO_STATUS_ERROR; - pgm_set_error (error, - PGM_ERROR_DOMAIN_RECV, - pgm_error_from_wsa_errno (save_wsa_errno), - _("Transport socket error: %s"), - pgm_wsastrerror (save_wsa_errno)); -#endif /* !_WIN32 */ - goto out; - } - else if (0 == len) - { -/* cannot return NORMAL/0 as that is valid payload with SKB */ - status = PGM_IO_STATUS_EOF; - goto out; - } - else - { - bytes_received += len; - } - - pgm_error_t* err = NULL; - const bool is_valid = (sock->udp_encap_ucast_port || AF_INET6 == src.ss_family) ? - pgm_parse_udp_encap (sock->rx_buffer, &err) : - pgm_parse_raw (sock->rx_buffer, (struct sockaddr*)&dst, &err); - if (PGM_UNLIKELY(!is_valid)) - { -/* inherently cannot determine PGM_PC_RECEIVER_CKSUM_ERRORS unless only one receiver */ - pgm_trace (PGM_LOG_ROLE_NETWORK, - _("Discarded invalid packet: %s"), - (err && err->message) ? err->message : "(null)"); - pgm_error_free (err); - if (sock->can_send_data) { - if (err && PGM_ERROR_CKSUM == err->code) - sock->cumulative_stats[PGM_PC_SOURCE_CKSUM_ERRORS]++; - sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]++; - } - goto recv_again; - } - - pgm_peer_t* source = NULL; - if (PGM_UNLIKELY(!on_pgm (sock, sock->rx_buffer, (struct sockaddr*)&src, (struct sockaddr*)&dst, &source))) - goto recv_again; - -/* check whether this source has waiting data */ - if (source && pgm_peer_has_pending (source)) { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("New pending data.")); - pgm_peer_set_pending (sock, source); - } - -flush_pending: -/* flush any congtiguous packets generated by the receipt of this packet */ - if (sock->peers_pending) - { - if (0 != pgm_flush_peers_pending (sock, &pmsg, msg_end, &bytes_read, &data_read)) - { -/* recv vector is now full */ - goto out; - } - } - -check_for_repeat: -/* repeat if non-blocking and not full */ - if (sock->is_nonblocking || - flags & MSG_DONTWAIT) - { - if (len > 0 && pmsg <= msg_end) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Recv again on not-full")); - goto recv_again; /* \:D/ */ - } - } - else - { -/* repeat if blocking and empty, i.e. received non data packet. - */ - if (0 == data_read) { - const int wait_status = wait_for_event (sock); - switch (wait_status) { - case EAGAIN: - goto recv_again; - case EINTR: - if (!pgm_timer_dispatch (sock)) - goto check_for_repeat; - goto flush_pending; - case ENOENT: - pgm_mutex_unlock (&sock->receiver_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_EOF; - case EFAULT: - pgm_set_error (error, - PGM_ERROR_DOMAIN_RECV, - pgm_error_from_errno (errno), - _("Waiting for event: %s"), -#ifndef _WIN32 - strerror (errno) -#else - pgm_wsastrerror (WSAGetLastError()) /* from select() */ -#endif - ); - pgm_mutex_unlock (&sock->receiver_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_ERROR; - default: - pgm_assert_not_reached(); - } - } - } - -out: - if (0 == data_read) - { -/* clear event notification */ - if (sock->is_pending_read) { - pgm_notify_clear (&sock->pending_notify); - sock->is_pending_read = FALSE; - } -/* report data loss */ - if (PGM_UNLIKELY(sock->is_reset)) { - pgm_assert (NULL != sock->peers_pending); - pgm_assert (NULL != sock->peers_pending->data); - pgm_peer_t* peer = sock->peers_pending->data; - if (flags & MSG_ERRQUEUE) - pgm_set_reset_error (sock, peer, msg_start); - else if (error) { - char tsi[PGM_TSISTRLEN]; - pgm_tsi_print_r (&peer->tsi, tsi, sizeof(tsi)); - pgm_set_error (error, - PGM_ERROR_DOMAIN_RECV, - PGM_ERROR_CONNRESET, - _("Transport has been reset on unrecoverable loss from %s."), - tsi); - } - if (!sock->is_abort_on_reset) - sock->is_reset = !sock->is_reset; - pgm_mutex_unlock (&sock->receiver_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_RESET; - } - pgm_mutex_unlock (&sock->receiver_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - if (PGM_IO_STATUS_WOULD_BLOCK == status && - ( sock->can_send_data || - ( sock->can_recv_data && NULL != sock->peers_list ))) - { - status = PGM_IO_STATUS_TIMER_PENDING; - } - return status; - } - - if (sock->peers_pending) - { -/* set event notification for additional available data */ - if (sock->is_pending_read && sock->is_edge_triggered_recv) - { -/* empty pending-pipe */ - pgm_notify_clear (&sock->pending_notify); - sock->is_pending_read = FALSE; - } - else if (!sock->is_pending_read && !sock->is_edge_triggered_recv) - { -/* fill pending-pipe */ - pgm_notify_send (&sock->pending_notify); - sock->is_pending_read = TRUE; - } - } - - if (NULL != _bytes_read) - *_bytes_read = bytes_read; - pgm_mutex_unlock (&sock->receiver_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_NORMAL; -} - -/* read one contiguous apdu and return as a IO scatter/gather array. msgv is owned by - * the caller, tpdu contents are owned by the receive window. - * - * on success, returns PGM_IO_STATUS_NORMAL. - */ - -int -pgm_recvmsg ( - pgm_sock_t* const restrict sock, - struct pgm_msgv_t* const restrict msgv, - const int flags, /* MSG_DONTWAIT for non-blocking */ - size_t* restrict bytes_read, /* may be NULL */ - pgm_error_t** restrict error - ) -{ - pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); - pgm_return_val_if_fail (NULL != msgv, PGM_IO_STATUS_ERROR); - - pgm_debug ("pgm_recvmsg (sock:%p msgv:%p flags:%d bytes_read:%p error:%p)", - (const void*)sock, (const void*)msgv, flags, (const void*)bytes_read, (const void*)error); - - return pgm_recvmsgv (sock, msgv, 1, flags, bytes_read, error); -} - -/* vanilla read function. copies from the receive window to the provided buffer - * location. the caller must provide an adequately sized buffer to store the largest - * expected apdu or else it will be truncated. - * - * on success, returns PGM_IO_STATUS_NORMAL. - */ - -int -pgm_recvfrom ( - pgm_sock_t* const restrict sock, - void* restrict buf, - const size_t buflen, - const int flags, /* MSG_DONTWAIT for non-blocking */ - size_t* restrict _bytes_read, /* may be NULL */ - struct pgm_sockaddr_t* restrict from, /* may be NULL */ - socklen_t* restrict fromlen, - pgm_error_t** restrict error - ) -{ - struct pgm_msgv_t msgv; - size_t bytes_read = 0; - - pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); - if (PGM_LIKELY(buflen)) pgm_return_val_if_fail (NULL != buf, PGM_IO_STATUS_ERROR); - if (fromlen) { - pgm_return_val_if_fail (NULL != from, PGM_IO_STATUS_ERROR); - pgm_return_val_if_fail (sizeof (struct pgm_sockaddr_t) == *fromlen, PGM_IO_STATUS_ERROR); - } - - pgm_debug ("pgm_recvfrom (sock:%p buf:%p buflen:%zu flags:%d bytes-read:%p from:%p from:%p error:%p)", - (const void*)sock, buf, buflen, flags, (const void*)_bytes_read, (const void*)from, (const void*)fromlen, (const void*)error); - - const int status = pgm_recvmsg (sock, &msgv, flags & ~(MSG_ERRQUEUE), &bytes_read, error); - if (PGM_IO_STATUS_NORMAL != status) - return status; - - size_t bytes_copied = 0; - struct pgm_sk_buff_t** skb = msgv.msgv_skb; - struct pgm_sk_buff_t* pskb = *skb; - - if (from) { - from->sa_port = ntohs (sock->dport); - from->sa_addr.sport = ntohs (pskb->tsi.sport); - memcpy (&from->sa_addr.gsi, &pskb->tsi.gsi, sizeof(pgm_gsi_t)); - } - - while (bytes_copied < bytes_read) { - size_t copy_len = pskb->len; - if (bytes_copied + copy_len > buflen) { - pgm_warn (_("APDU truncated, original length %zu bytes."), - bytes_read); - copy_len = buflen - bytes_copied; - bytes_read = buflen; - } - memcpy ((char*)buf + bytes_copied, pskb->data, copy_len); - bytes_copied += copy_len; - pskb = *(++skb); - } - if (_bytes_read) - *_bytes_read = bytes_copied; - return PGM_IO_STATUS_NORMAL; -} - -/* Basic recv operation, copying data from window to application. - * - * on success, returns PGM_IO_STATUS_NORMAL. - */ - -int -pgm_recv ( - pgm_sock_t* const restrict sock, - void* restrict buf, - const size_t buflen, - const int flags, /* MSG_DONTWAIT for non-blocking */ - size_t* const restrict bytes_read, /* may be NULL */ - pgm_error_t** restrict error - ) -{ - pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); - if (PGM_LIKELY(buflen)) pgm_return_val_if_fail (NULL != buf, PGM_IO_STATUS_ERROR); - - pgm_debug ("pgm_recv (sock:%p buf:%p buflen:%zu flags:%d bytes-read:%p error:%p)", - (const void*)sock, buf, buflen, flags, (const void*)bytes_read, (const void*)error); - - return pgm_recvfrom (sock, buf, buflen, flags, bytes_read, NULL, NULL, error); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/recv_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/recv_unittest.c deleted file mode 100644 index 2719897..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/recv_unittest.c +++ /dev/null @@ -1,1600 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for transport recv api - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include /* _GNU_SOURCE for in6_pktinfo */ -#include -#include -#include - - -/* mock state */ - -#define TEST_NETWORK "" -#define TEST_DPORT 7500 -#define TEST_SPORT 1000 -#define TEST_SRC_ADDR "127.0.0.1" -#define TEST_END_ADDR "127.0.0.2" -#define TEST_GROUP_ADDR "239.192.0.1" -#define TEST_PEER_ADDR "127.0.0.6" -#define TEST_DLR_ADDR "127.0.0.9" -#define TEST_MAX_TPDU 1500 -#define TEST_TXW_SQNS 32 -#define TEST_RXW_SQNS 32 -#define TEST_HOPS 16 -#define TEST_SPM_AMBIENT ( pgm_secs(30) ) -#define TEST_SPM_HEARTBEAT_INIT { pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(1300), pgm_secs(7), pgm_secs(16), pgm_secs(25), pgm_secs(30) } -#define TEST_PEER_EXPIRY ( pgm_secs(300) ) -#define TEST_SPMR_EXPIRY ( pgm_msecs(250) ) -#define TEST_NAK_BO_IVL ( pgm_msecs(50) ) -#define TEST_NAK_RPT_IVL ( pgm_secs(2) ) -#define TEST_NAK_RDATA_IVL ( pgm_secs(2) ) -#define TEST_NAK_DATA_RETRIES 5 -#define TEST_NAK_NCF_RETRIES 2 - -struct mock_recvmsg_t { - struct msghdr* mr_msg; - ssize_t mr_retval; - int mr_errno; -}; - -struct pgm_peer_t; - -GList* mock_recvmsg_list = NULL; -static int mock_pgm_type = -1; -static gboolean mock_reset_on_spmr = FALSE; -static gboolean mock_data_on_spmr = FALSE; -static struct pgm_peer_t* mock_peer = NULL; -GList* mock_data_list = NULL; -unsigned mock_pgm_loss_rate = 0; - - -static ssize_t mock_recvmsg (int, struct msghdr*, int); - -#define pgm_parse_raw mock_pgm_parse_raw -#define pgm_parse_udp_encap mock_pgm_parse_udp_encap -#define pgm_verify_spm mock_pgm_verify_spm -#define pgm_verify_nak mock_pgm_verify_nak -#define pgm_verify_ncf mock_pgm_verify_ncf -#define pgm_poll_info mock_pgm_poll_info -#define pgm_set_reset_error mock_pgm_set_reset_error -#define pgm_flush_peers_pending mock_pgm_flush_peers_pending -#define pgm_peer_has_pending mock_pgm_peer_has_pending -#define pgm_peer_set_pending mock_pgm_peer_set_pending -#define pgm_txw_retransmit_is_empty mock_pgm_txw_retransmit_is_empty -#define pgm_rxw_create mock_pgm_rxw_create -#define pgm_rxw_readv mock_pgm_rxw_readv -#define pgm_new_peer mock_pgm_new_peer -#define pgm_on_data mock_pgm_on_data -#define pgm_on_spm mock_pgm_on_spm -#define pgm_on_ack mock_pgm_on_ack -#define pgm_on_nak mock_pgm_on_nak -#define pgm_on_deferred_nak mock_pgm_on_deferred_nak -#define pgm_on_peer_nak mock_pgm_on_peer_nak -#define pgm_on_nnak mock_pgm_on_nnak -#define pgm_on_ncf mock_pgm_on_ncf -#define pgm_on_spmr mock_pgm_on_spmr -#define pgm_sendto mock_pgm_sendto -#define pgm_timer_prepare mock_pgm_timer_prepare -#define pgm_timer_check mock_pgm_timer_check -#define pgm_timer_expiration mock_pgm_timer_expiration -#define pgm_timer_dispatch mock_pgm_timer_dispatch -#define pgm_time_now mock_pgm_time_now -#define pgm_time_update_now mock_pgm_time_update_now -#define recvmsg mock_recvmsg -#define pgm_loss_rate mock_pgm_loss_rate - -#define RECV_DEBUG -#include "recv.c" - - -pgm_rxw_t* mock_pgm_rxw_create (const pgm_tsi_t*, const uint16_t, const unsigned, const unsigned, const ssize_t, const uint32_t); -static pgm_time_t _mock_pgm_time_update_now (void); -pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; - - -static -void -mock_setup (void) -{ - if (!g_thread_supported ()) g_thread_init (NULL); -} - -static -struct pgm_sock_t* -generate_sock (void) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, g_htons(TEST_SPORT) }; - struct pgm_sock_t* sock = g_new0 (struct pgm_sock_t, 1); - sock->window = g_new0 (pgm_txw_t, 1); - memcpy (&sock->tsi, &tsi, sizeof(pgm_tsi_t)); - sock->is_bound = TRUE; - sock->rx_buffer = pgm_alloc_skb (TEST_MAX_TPDU); - sock->max_tpdu = TEST_MAX_TPDU; - sock->rxw_sqns = TEST_RXW_SQNS; - sock->dport = g_htons(TEST_DPORT); - sock->can_send_data = TRUE; - sock->can_send_nak = TRUE; - sock->can_recv_data = TRUE; - sock->peers_hashtable = pgm_hashtable_new (pgm_tsi_hash, pgm_tsi_equal); - pgm_rand_create (&sock->rand_); - sock->nak_bo_ivl = 100*1000; - pgm_notify_init (&sock->pending_notify); - pgm_notify_init (&sock->rdata_notify); - return sock; -} - -static -struct pgm_sk_buff_t* -generate_packet (void) -{ - struct pgm_sk_buff_t* skb; - - skb = pgm_alloc_skb (TEST_MAX_TPDU); - skb->data = skb->head; - skb->len = sizeof(struct pgm_ip) + sizeof(struct pgm_header); - skb->tail = (guint8*)skb->data + skb->len; - -/* add IP header */ - struct pgm_ip* iphdr = skb->data; - iphdr->ip_hl = sizeof(struct pgm_ip) / 4; - iphdr->ip_v = 4; - iphdr->ip_tos = 0; - iphdr->ip_id = 0; - iphdr->ip_off = 0; - iphdr->ip_ttl = 16; - iphdr->ip_p = IPPROTO_PGM; - iphdr->ip_sum = 0; - iphdr->ip_src.s_addr = inet_addr (TEST_SRC_ADDR); - iphdr->ip_dst.s_addr = inet_addr (TEST_GROUP_ADDR); - -/* add PGM header */ - struct pgm_header* pgmhdr = (gpointer)(iphdr + 1); - pgmhdr->pgm_sport = g_htons ((guint16)TEST_SPORT); - pgmhdr->pgm_dport = g_htons ((guint16)TEST_DPORT); - pgmhdr->pgm_options = 0; - pgmhdr->pgm_gsi[0] = 1; - pgmhdr->pgm_gsi[1] = 2; - pgmhdr->pgm_gsi[2] = 3; - pgmhdr->pgm_gsi[3] = 4; - pgmhdr->pgm_gsi[4] = 5; - pgmhdr->pgm_gsi[5] = 6; - pgmhdr->pgm_tsdu_length = 0; - pgmhdr->pgm_checksum = 0; - - skb->pgm_header = pgmhdr; - return skb; -} - -static -void -generate_odata ( - const char* source, - const guint source_len, - const guint32 data_sqn, - const guint32 data_trail, - gpointer* packet, - gsize* len - ) -{ - struct pgm_sk_buff_t* skb = generate_packet (); - pgm_skb_put (skb, sizeof(struct pgm_data) + source_len); - -/* add ODATA header */ - struct pgm_data* datahdr = (gpointer)(skb->pgm_header + 1); - datahdr->data_sqn = g_htonl (data_sqn); - datahdr->data_trail = g_htonl (data_trail); - -/* add payload */ - gpointer data = (gpointer)(datahdr + 1); - memcpy (data, source, source_len); - -/* finalize PGM header */ - struct pgm_header* pgmhdr = skb->pgm_header; - pgmhdr->pgm_type = PGM_ODATA; - pgmhdr->pgm_tsdu_length = g_htons (source_len); - -/* finalize IP header */ - struct pgm_ip* iphdr = skb->data; - iphdr->ip_len = g_htons (skb->len); - - *packet = skb->head; - *len = skb->len; -} - -static -void -generate_spm ( - const guint32 spm_sqn, - const guint32 spm_trail, - const guint32 spm_lead, - gpointer* packet, - gsize* len - ) -{ - struct pgm_sk_buff_t* skb = generate_packet (); - pgm_skb_put (skb, sizeof(struct pgm_spm)); - -/* add SPM header */ - struct pgm_spm* spm = (gpointer)(skb->pgm_header + 1); - spm->spm_sqn = g_htonl (spm_sqn); - spm->spm_trail = g_htonl (spm_trail); - spm->spm_lead = g_htonl (spm_lead); - -/* finalize PGM header */ - struct pgm_header* pgmhdr = skb->pgm_header; - pgmhdr->pgm_type = PGM_SPM; - -/* finalize IP header */ - struct pgm_ip* iphdr = skb->data; - iphdr->ip_len = g_htons (skb->len); - - *packet = skb->head; - *len = skb->len; -} - -static -void -generate_nak ( - const guint32 nak_sqn, - gpointer* packet, - gsize* len - ) -{ - struct pgm_sk_buff_t* skb = generate_packet (); - pgm_skb_put (skb, sizeof(struct pgm_spm)); - -/* update IP header */ - struct pgm_ip* iphdr = skb->data; - iphdr->ip_src.s_addr = inet_addr (TEST_END_ADDR); - iphdr->ip_dst.s_addr = inet_addr (TEST_SRC_ADDR); - -/* update PGM header */ - struct pgm_header* pgmhdr = skb->pgm_header; - pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); - pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); - -/* add NAK header */ - struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); - nak->nak_sqn = g_htonl (nak_sqn); - -/* finalize PGM header */ - pgmhdr->pgm_type = PGM_NAK; - -/* finalize IP header */ - iphdr->ip_len = g_htons (skb->len); - - *packet = skb->head; - *len = skb->len; -} - -static -void -generate_peer_nak ( - const guint32 nak_sqn, - gpointer* packet, - gsize* len - ) -{ - struct pgm_sk_buff_t* skb = generate_packet (); - pgm_skb_put (skb, sizeof(struct pgm_spm)); - -/* update IP header */ - struct pgm_ip* iphdr = skb->data; - iphdr->ip_src.s_addr = inet_addr (TEST_PEER_ADDR); - iphdr->ip_dst.s_addr = inet_addr (TEST_GROUP_ADDR); - -/* update PGM header */ - struct pgm_header* pgmhdr = skb->pgm_header; - pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); - pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); - -/* add NAK header */ - struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); - nak->nak_sqn = g_htonl (nak_sqn); - -/* finalize PGM header */ - pgmhdr->pgm_type = PGM_NAK; - -/* finalize IP header */ - iphdr->ip_len = g_htons (skb->len); - - *packet = skb->head; - *len = skb->len; -} - -static -void -generate_nnak ( - const guint32 nak_sqn, - gpointer* packet, - gsize* len - ) -{ - struct pgm_sk_buff_t* skb = generate_packet (); - pgm_skb_put (skb, sizeof(struct pgm_nak)); - -/* update IP header */ - struct pgm_ip* iphdr = skb->data; - iphdr->ip_src.s_addr = inet_addr (TEST_DLR_ADDR); - iphdr->ip_dst.s_addr = inet_addr (TEST_SRC_ADDR); - -/* update PGM header */ - struct pgm_header* pgmhdr = skb->pgm_header; - pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); - pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); - -/* add NNAK header */ - struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); - nak->nak_sqn = g_htonl (nak_sqn); - -/* finalize PGM header */ - pgmhdr->pgm_type = PGM_NNAK; - -/* finalize IP header */ - iphdr->ip_len = g_htons (skb->len); - - *packet = skb->head; - *len = skb->len; -} - -static -void -generate_ncf ( - const guint32 nak_sqn, - gpointer* packet, - gsize* len - ) -{ - struct pgm_sk_buff_t* skb = generate_packet (); - pgm_skb_put (skb, sizeof(struct pgm_nak)); - -/* add NAK header */ - struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); - nak->nak_sqn = g_htonl (nak_sqn); - -/* finalize PGM header */ - struct pgm_header* pgmhdr = skb->pgm_header; - pgmhdr->pgm_type = PGM_NCF; - -/* finalize IP header */ - struct pgm_ip* iphdr = skb->data; - iphdr->ip_len = g_htons (skb->len); - - *packet = skb->head; - *len = skb->len; -} - -static -void -generate_spmr ( - gpointer* packet, - gsize* len - ) -{ - struct pgm_sk_buff_t* skb = generate_packet (); - -/* update IP header */ - struct pgm_ip* iphdr = skb->data; - iphdr->ip_src.s_addr = inet_addr (TEST_END_ADDR); - iphdr->ip_dst.s_addr = inet_addr (TEST_SRC_ADDR); - -/* update PGM header */ - struct pgm_header* pgmhdr = skb->pgm_header; - pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); - pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); - -/* finalize PGM header */ - pgmhdr->pgm_type = PGM_SPMR; - -/* finalize IP header */ - iphdr->ip_len = g_htons (skb->len); - - *packet = skb->head; - *len = skb->len; -} - -static -void -generate_peer_spmr ( - gpointer* packet, - gsize* len - ) -{ - struct pgm_sk_buff_t* skb = generate_packet (); - -/* update IP header */ - struct pgm_ip* iphdr = skb->data; - iphdr->ip_src.s_addr = inet_addr (TEST_PEER_ADDR); - iphdr->ip_dst.s_addr = inet_addr (TEST_GROUP_ADDR); - -/* update PGM header */ - struct pgm_header* pgmhdr = skb->pgm_header; - pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); - pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); - -/* finalize PGM header */ - pgmhdr->pgm_type = PGM_SPMR; - -/* finalize IP header */ - iphdr->ip_len = g_htons (skb->len); - - *packet = skb->head; - *len = skb->len; -} - -static -void -generate_msghdr ( - const gpointer packet, - const gsize packet_len - ) -{ - struct pgm_ip* iphdr = packet; - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = iphdr->ip_src.s_addr - }; - struct iovec iov = { - .iov_base = packet, - .iov_len = packet_len - }; - struct cmsghdr* packet_cmsg = g_malloc0 (sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)); - packet_cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo); - packet_cmsg->cmsg_level = IPPROTO_IP; - packet_cmsg->cmsg_type = IP_PKTINFO; - struct in_pktinfo packet_info = { - .ipi_ifindex = 2, - .ipi_spec_dst = iphdr->ip_src.s_addr, /* local address */ - .ipi_addr = iphdr->ip_dst.s_addr /* destination address */ - }; - memcpy ((char*)(packet_cmsg + 1), &packet_info, sizeof(struct in_pktinfo)); - struct msghdr packet_msg = { - .msg_name = g_memdup (&addr, sizeof(addr)), /* source address */ - .msg_namelen = sizeof(addr), - .msg_iov = g_memdup (&iov, sizeof(iov)), - .msg_iovlen = 1, - .msg_control = &packet_cmsg, - .msg_controllen = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), - .msg_flags = 0 - }; - - struct mock_recvmsg_t* mr = g_malloc (sizeof(struct mock_recvmsg_t)); - mr->mr_msg = g_memdup (&packet_msg, sizeof(packet_msg)); - mr->mr_errno = 0; - mr->mr_retval = packet_len; - mock_recvmsg_list = g_list_append (mock_recvmsg_list, mr); -} - -static -void -push_block_event (void) -{ -/* block */ - struct mock_recvmsg_t* mr = g_malloc (sizeof(struct mock_recvmsg_t)); - mr->mr_msg = NULL; - mr->mr_errno = EAGAIN; - mr->mr_retval = -1; - mock_recvmsg_list = g_list_append (mock_recvmsg_list, mr); -} - -/** packet module */ -bool -mock_pgm_parse_raw ( - struct pgm_sk_buff_t* const skb, - struct sockaddr* const dst, - pgm_error_t** error - ) -{ - const struct pgm_ip* ip = (struct pgm_ip*)skb->data; - struct sockaddr_in* sin = (struct sockaddr_in*)dst; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = ip->ip_dst.s_addr; - const gsize ip_header_length = ip->ip_hl * 4; - skb->pgm_header = (gpointer)( (guint8*)skb->data + ip_header_length ); - skb->data = skb->pgm_header; - skb->len -= ip_header_length; - memcpy (&skb->tsi.gsi, skb->pgm_header->pgm_gsi, sizeof(pgm_gsi_t)); - skb->tsi.sport = skb->pgm_header->pgm_sport; - return TRUE; -} - -bool -mock_pgm_parse_udp_encap ( - struct pgm_sk_buff_t* const skb, - pgm_error_t** error - ) -{ - skb->pgm_header = skb->data; - memcpy (&skb->tsi.gsi, skb->pgm_header->pgm_gsi, sizeof(pgm_gsi_t)); - skb->tsi.sport = skb->pgm_header->pgm_sport; - return TRUE; -} - -bool -mock_pgm_verify_spm ( - const struct pgm_sk_buff_t* const skb - ) -{ - return TRUE; -} - -bool -mock_pgm_verify_nak ( - const struct pgm_sk_buff_t* const skb - ) -{ - return TRUE; -} - -bool -mock_pgm_verify_ncf ( - const struct pgm_sk_buff_t* const skb - ) -{ - return TRUE; -} - -/** socket module */ -int -mock_pgm_poll_info ( - pgm_sock_t* const sock, - struct pollfd* fds, - int* n_fds, - int events - ) -{ -} - -pgm_peer_t* -mock__pgm_peer_ref ( - pgm_peer_t* peer - ) -{ - pgm_atomic_inc32 (&peer->ref_count); - return peer; -} - -PGM_GNUC_INTERNAL -pgm_peer_t* -mock_pgm_new_peer ( - pgm_sock_t* const sock, - const pgm_tsi_t* const tsi, - const struct sockaddr* const src_addr, - const socklen_t src_addr_len, - const struct sockaddr* const dst_addr, - const socklen_t dst_addr_len, - const pgm_time_t now - ) -{ - pgm_peer_t* peer = g_malloc0 (sizeof(pgm_peer_t)); - peer->expiry = now + sock->peer_expiry; - peer->sock = sock; - memcpy (&peer->tsi, tsi, sizeof(pgm_tsi_t)); - memcpy (&peer->group_nla, dst_addr, dst_addr_len); - memcpy (&peer->local_nla, src_addr, src_addr_len); - ((struct sockaddr_in*)&peer->local_nla)->sin_port = g_htons (sock->udp_encap_ucast_port); - ((struct sockaddr_in*)&peer->nla)->sin_port = g_htons (sock->udp_encap_ucast_port); - peer->window = mock_pgm_rxw_create (&peer->tsi, - sock->max_tpdu, - sock->rxw_sqns, - sock->rxw_secs, - sock->rxw_max_rte, - sock->ack_c_p); - peer->spmr_expiry = now + sock->spmr_expiry; - gpointer entry = mock__pgm_peer_ref(peer); - pgm_hashtable_insert (sock->peers_hashtable, &peer->tsi, entry); - peer->peers_link.next = sock->peers_list; - peer->peers_link.data = peer; - if (sock->peers_list) - sock->peers_list->prev = &peer->peers_link; - sock->peers_list = &peer->peers_link; - return peer; -} - -PGM_GNUC_INTERNAL -void -mock_pgm_set_reset_error ( - pgm_sock_t* const sock, - pgm_peer_t* const source, - struct pgm_msgv_t* const msgv - ) -{ -} - -PGM_GNUC_INTERNAL -int -mock_pgm_flush_peers_pending ( - pgm_sock_t* const sock, - struct pgm_msgv_t** pmsg, - const struct pgm_msgv_t* const msg_end, - size_t* const bytes_read, - unsigned* const data_read - ) -{ - if (mock_data_list) { - size_t len = 0; - unsigned count = 0; - while (mock_data_list && *pmsg <= msg_end) { - struct pgm_msgv_t* mock_msgv = mock_data_list->data; - (*pmsg)->msgv_len = mock_msgv->msgv_len; - for (unsigned i = 0; i < mock_msgv->msgv_len; i++) { - (*pmsg)->msgv_skb[i] = mock_msgv->msgv_skb[i]; - len += mock_msgv->msgv_skb[i]->len; - } - count++; - (*pmsg)++; - mock_data_list = g_list_delete_link (mock_data_list, mock_data_list); - } - *bytes_read = len; - *data_read = count; - if (*pmsg > msg_end) - return -ENOBUFS; - } - return 0; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_peer_has_pending ( - pgm_peer_t* const peer - ) -{ - return FALSE; -} - -PGM_GNUC_INTERNAL -void -mock_pgm_peer_set_pending ( - pgm_sock_t* const sock, - pgm_peer_t* const peer - ) -{ - g_assert (NULL != sock); - g_assert (NULL != peer); - if (peer->pending_link.data) return; - peer->pending_link.data = peer; - peer->pending_link.next = sock->peers_pending; - sock->peers_pending = &peer->pending_link; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_on_data ( - pgm_sock_t* const sock, - pgm_peer_t* const sender, - struct pgm_sk_buff_t* const skb - ) -{ - g_debug ("mock_pgm_on_data (sock:%p sender:%p skb:%p)", - (gpointer)sock, (gpointer)sender, (gpointer)skb); - mock_pgm_type = PGM_ODATA; - ((pgm_rxw_t*)sender->window)->has_event = 1; - return TRUE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_on_ack ( - pgm_sock_t* const sock, - struct pgm_sk_buff_t* const skb - ) -{ - g_debug ("mock_pgm_on_ack (sock:%p skb:%p)", - (gpointer)sock, (gpointer)skb); - mock_pgm_type = PGM_ACK; - return TRUE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_on_deferred_nak ( - pgm_sock_t* const sock - ) -{ - return TRUE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_on_nak ( - pgm_sock_t* const sock, - struct pgm_sk_buff_t* const skb - ) -{ - g_debug ("mock_pgm_on_nak (sock:%p skb:%p)", - (gpointer)sock, (gpointer)skb); - mock_pgm_type = PGM_NAK; - return TRUE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_on_peer_nak ( - pgm_sock_t* const sock, - pgm_peer_t* const sender, - struct pgm_sk_buff_t* const skb - ) -{ - g_debug ("mock_pgm_on_peer_nak (sock:%p sender:%p skb:%p)", - (gpointer)sock, (gpointer)sender, (gpointer)skb); - mock_pgm_type = PGM_NAK; - return TRUE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_on_ncf ( - pgm_sock_t* const sock, - pgm_peer_t* const sender, - struct pgm_sk_buff_t* const skb - ) -{ - g_debug ("mock_pgm_on_ncf (sock:%p sender:%p skb:%p)", - (gpointer)sock, (gpointer)sender, (gpointer)skb); - mock_pgm_type = PGM_NCF; - return TRUE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_on_nnak ( - pgm_sock_t* const sock, - struct pgm_sk_buff_t* const skb - ) -{ - g_debug ("mock_pgm_on_nnak (sock:%p skb:%p)", - (gpointer)sock, (gpointer)skb); - mock_pgm_type = PGM_NNAK; - return TRUE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_on_spm ( - pgm_sock_t* const sock, - pgm_peer_t* const sender, - struct pgm_sk_buff_t* const skb - ) -{ - g_debug ("mock_pgm_on_spm (sock:%p sender:%p skb:%p)", - (gpointer)sock, (gpointer)sender, (gpointer)skb); - mock_pgm_type = PGM_SPM; - return TRUE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_on_spmr ( - pgm_sock_t* const sock, - pgm_peer_t* const peer, - struct pgm_sk_buff_t* const skb - ) -{ - g_debug ("mock_pgm_on_spmr (sock:%p peer:%p skb:%p)", - (gpointer)sock, (gpointer)peer, (gpointer)skb); - mock_pgm_type = PGM_SPMR; - if (mock_reset_on_spmr) { - sock->is_reset = TRUE; - mock_pgm_peer_set_pending (sock, mock_peer); - } - if (mock_data_on_spmr) { - mock_pgm_peer_set_pending (sock, mock_peer); - } - return TRUE; -} - -/** transmit window */ -PGM_GNUC_INTERNAL -bool -mock_pgm_txw_retransmit_is_empty ( - const pgm_txw_t*const window - ) -{ - return TRUE; -} - -/** receive window */ -pgm_rxw_t* -mock_pgm_rxw_create ( - const pgm_tsi_t* tsi, - const uint16_t tpdu_size, - const unsigned sqns, - const unsigned secs, - const ssize_t max_rte, - const uint32_t ack_c_p - ) -{ - return g_new0 (pgm_rxw_t, 1); -} - -ssize_t -mock_pgm_rxw_readv ( - pgm_rxw_t* const window, - struct pgm_msgv_t** pmsg, - const unsigned pmsglen - ) -{ - return -1; -} - -/** net module */ -PGM_GNUC_INTERNAL -ssize_t -mock_pgm_sendto ( - pgm_sock_t* sock, - bool use_rate_limit, - bool use_router_alert, - const void* buf, - size_t len, - const struct sockaddr* to, - socklen_t tolen - ) -{ - return len; -} - -/** timer module */ -PGM_GNUC_INTERNAL -bool -mock_pgm_timer_prepare ( - pgm_sock_t* const sock - ) -{ - return FALSE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_timer_check ( - pgm_sock_t* const sock - ) -{ - return FALSE; -} - -PGM_GNUC_INTERNAL -pgm_time_t -mock_pgm_timer_expiration ( - pgm_sock_t* const sock - ) -{ - return 100L; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_timer_dispatch ( - pgm_sock_t* const sock - ) -{ - return TRUE; -} - -/** time module */ -static pgm_time_t mock_pgm_time_now = 0x1; - -static -pgm_time_t -_mock_pgm_time_update_now (void) -{ - return mock_pgm_time_now; -} - -/** libc */ -static -ssize_t -mock_recvmsg ( - int s, - struct msghdr* msg, - int flags - ) -{ - g_assert (NULL != msg); - g_assert (NULL != mock_recvmsg_list); - - g_debug ("mock_recvmsg (s:%d msg:%p flags:%d)", - s, (gpointer)msg, flags); - - struct mock_recvmsg_t* mr = mock_recvmsg_list->data; - struct msghdr* mock_msg = mr->mr_msg; - ssize_t mock_retval = mr->mr_retval; - int mock_errno = mr->mr_errno; - mock_recvmsg_list = g_list_delete_link (mock_recvmsg_list, mock_recvmsg_list); - if (mock_msg) { - g_assert_cmpuint (mock_msg->msg_namelen, <=, msg->msg_namelen); - g_assert_cmpuint (mock_msg->msg_iovlen, <=, msg->msg_iovlen); - g_assert_cmpuint (mock_msg->msg_controllen, <=, msg->msg_controllen); - if (mock_msg->msg_namelen) - memcpy (msg->msg_name, mock_msg->msg_name, mock_msg->msg_namelen); - if (mock_msg->msg_iovlen) { - for (unsigned i = 0; i < mock_msg->msg_iovlen; i++) { - g_assert (mock_msg->msg_iov[i].iov_len <= msg->msg_iov[i].iov_len); - memcpy (msg->msg_iov[i].iov_base, mock_msg->msg_iov[i].iov_base, mock_msg->msg_iov[i].iov_len); - } - } - if (mock_msg->msg_controllen) - memcpy (msg->msg_control, mock_msg->msg_control, mock_msg->msg_controllen); - msg->msg_flags = mock_msg->msg_flags; - } - errno = mock_errno; - return mock_retval; -} - - -/* mock functions for external references */ - -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return 0; -} - - -/* target: - * int - * pgm_recv ( - * pgm_sock_t* sock, - * void* data, - * size_t len, - * int flags, - * size_t* bytes_read, - * pgm_error_t** error - * ) - * - * Most tests default to PGM_IO_STATUS_TIMER_PENDING, PGM_IO_STATUS_WOULD_BLOCK is not expected due - * to peer state engine and SPM broadcasts. - */ - -START_TEST (test_block_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - push_block_event (); - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); -} -END_TEST - -/* recv -> on_data */ -START_TEST (test_data_pass_001) -{ - const char source[] = "i am not a string"; - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gpointer packet; gsize packet_len; - generate_odata (source, sizeof(source), 0 /* sqn */, -1 /* trail */, &packet, &packet_len); - generate_msghdr (packet, packet_len); - push_block_event (); - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (PGM_ODATA == mock_pgm_type, "unexpected PGM packet"); -} -END_TEST - -/* recv -> on_spm */ -START_TEST (test_spm_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gpointer packet; gsize packet_len; - generate_spm (200 /* spm-sqn */, -1 /* trail */, 0 /* lead */, &packet, &packet_len); - generate_msghdr (packet, packet_len); - push_block_event (); - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (PGM_SPM == mock_pgm_type, "unexpected PGM packet"); -} -END_TEST - -/* recv -> on_nak */ -START_TEST (test_nak_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gpointer packet; gsize packet_len; - generate_nak (0 /* sqn */, &packet, &packet_len); - generate_msghdr (packet, packet_len); - push_block_event (); - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (PGM_NAK == mock_pgm_type, "unexpected PGM packet"); -} -END_TEST - -/* recv -> on_peer_nak */ -START_TEST (test_peer_nak_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gpointer packet; gsize packet_len; - generate_peer_nak (0 /* sqn */, &packet, &packet_len); - generate_msghdr (packet, packet_len); - push_block_event (); - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (PGM_NAK == mock_pgm_type, "unexpected PGM packet"); -} -END_TEST - -/* recv -> on_nnak */ -START_TEST (test_nnak_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gpointer packet; gsize packet_len; - generate_nnak (0 /* sqn */, &packet, &packet_len); - generate_msghdr (packet, packet_len); - push_block_event (); - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (PGM_NNAK == mock_pgm_type, "unexpected PGM packet"); -} -END_TEST - -/* recv -> on_ncf */ -START_TEST (test_ncf_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gpointer packet; gsize packet_len; - generate_ncf (0 /* sqn */, &packet, &packet_len); - generate_msghdr (packet, packet_len); - push_block_event (); - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (PGM_NCF == mock_pgm_type, "unexpected PGM packet"); -} -END_TEST - -/* recv -> on_spmr */ -START_TEST (test_spmr_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gpointer packet; gsize packet_len; - generate_spmr (&packet, &packet_len); - generate_msghdr (packet, packet_len); - push_block_event (); - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (PGM_SPMR == mock_pgm_type, "unexpected PGM packet"); -} -END_TEST - -/* recv -> on (peer) spmr */ -START_TEST (test_peer_spmr_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gpointer packet; gsize packet_len; - generate_peer_spmr (&packet, &packet_len); - generate_msghdr (packet, packet_len); - push_block_event (); - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (PGM_SPMR == mock_pgm_type, "unexpected PGM packet"); -} -END_TEST - -/* recv -> lost data */ -START_TEST (test_lost_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - sock->is_reset = TRUE; - const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; - struct sockaddr_in grp_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) - }, peer_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_END_ADDR) - }; - pgm_peer_t* peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); - fail_if (NULL == peer, "new_peer failed"); - mock_pgm_peer_set_pending (sock, peer); - push_block_event (); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - if (err) { - g_message ("%s", err->message); - pgm_error_free (err); - err = NULL; - } - push_block_event (); - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); -} -END_TEST - -/* recv -> lost data and abort transport */ -START_TEST (test_abort_on_lost_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - sock->is_reset = TRUE; - sock->is_abort_on_reset = TRUE; - const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; - struct sockaddr_in grp_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) - }, peer_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_END_ADDR) - }; - pgm_peer_t* peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); - fail_if (NULL == peer, "new_peer failed"); - mock_pgm_peer_set_pending (sock, peer); - push_block_event (); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - if (err) { - g_message ("%s", err->message); - pgm_error_free (err); - err = NULL; - } - push_block_event (); - fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); -} -END_TEST - -/* recv -> (spmr) & loss */ -START_TEST (test_then_lost_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - mock_reset_on_spmr = TRUE; - gpointer packet; gsize packet_len; - generate_spmr (&packet, &packet_len); - generate_msghdr (packet, packet_len); - const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; - struct sockaddr_in grp_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) - }, peer_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_END_ADDR) - }; - mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); - fail_if (NULL == mock_peer, "new_peer failed"); - push_block_event (); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - if (err) { - g_message ("%s", err->message); - pgm_error_free (err); - err = NULL; - } - push_block_event (); - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); -} -END_TEST - -/* recv -> data & loss & abort transport */ -START_TEST (test_then_abort_on_lost_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - mock_reset_on_spmr = TRUE; - sock->is_abort_on_reset = TRUE; - gpointer packet; gsize packet_len; - generate_spmr (&packet, &packet_len); - generate_msghdr (packet, packet_len); - const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; - struct sockaddr_in grp_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) - }, peer_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_END_ADDR) - }; - mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); - fail_if (NULL == mock_peer, "new_peer failed"); - push_block_event (); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - if (err) { - g_message ("%s", err->message); - pgm_error_free (err); - err = NULL; - } - push_block_event (); - fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); -} -END_TEST - -/* new waiting peer -> return data */ -START_TEST (test_on_data_pass_001) -{ - const char source[] = "i am not a string"; - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - mock_data_on_spmr = TRUE; - gpointer packet; gsize packet_len; - generate_spmr (&packet, &packet_len); - generate_msghdr (packet, packet_len); - const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; - struct sockaddr_in grp_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) - }, peer_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_END_ADDR) - }; - mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); - fail_if (NULL == mock_peer, "new_peer failed"); - struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); - pgm_skb_put (skb, sizeof(source)); - memcpy (skb->data, source, sizeof(source)); - struct pgm_msgv_t* msgv = g_new0 (struct pgm_msgv_t, 1); - msgv->msgv_len = 1; - msgv->msgv_skb[0] = skb; - mock_data_list = g_list_append (mock_data_list, msgv); - push_block_event (); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (NULL == err, "error raised"); - fail_unless ((gsize)sizeof(source) == bytes_read, "unexpected data length"); - push_block_event (); - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); -} -END_TEST - -/* zero length data waiting */ -START_TEST (test_on_zero_pass_001) -{ - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - mock_data_on_spmr = TRUE; - gpointer packet; gsize packet_len; - generate_spmr (&packet, &packet_len); - generate_msghdr (packet, packet_len); - const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; - struct sockaddr_in grp_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) - }, peer_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_END_ADDR) - }; - mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); - fail_if (NULL == mock_peer, "new_peer failed"); - struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); - struct pgm_msgv_t* msgv = g_new0 (struct pgm_msgv_t, 1); - msgv->msgv_len = 1; - msgv->msgv_skb[0] = skb; - mock_data_list = g_list_append (mock_data_list, msgv); - push_block_event (); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (NULL == err, "error raised"); - fail_unless ((gsize)0 == bytes_read, "unexpected data length"); - push_block_event (); - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); -} -END_TEST - -/* more than vector length data waiting */ -START_TEST (test_on_many_data_pass_001) -{ - const char* source[] = { - "i am not a string", - "i am not an iguana", - "i am not a peach" - }; - pgm_sock_t* sock = generate_sock(); - fail_if (NULL == sock, "generate_sock failed"); - mock_data_on_spmr = TRUE; - gpointer packet; gsize packet_len; - generate_spmr (&packet, &packet_len); - generate_msghdr (packet, packet_len); - const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; - struct sockaddr_in grp_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) - }, peer_addr = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr(TEST_END_ADDR) - }; - mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); - fail_if (NULL == mock_peer, "new_peer failed"); - struct pgm_sk_buff_t* skb; - struct pgm_msgv_t* msgv; -/* #1 */ - msgv = g_new0 (struct pgm_msgv_t, 1); - skb = pgm_alloc_skb (TEST_MAX_TPDU); - pgm_skb_put (skb, strlen(source[0]) + 1); - memcpy (skb->data, source[0], strlen(source[0])); - msgv->msgv_len = 1; - msgv->msgv_skb[0] = skb; - mock_data_list = g_list_append (mock_data_list, msgv); -/* #2 */ - msgv = g_new0 (struct pgm_msgv_t, 1); - skb = pgm_alloc_skb (TEST_MAX_TPDU); - pgm_skb_put (skb, strlen(source[1]) + 1); - memcpy (skb->data, source[1], strlen(source[1])); - msgv->msgv_len = 1; - msgv->msgv_skb[0] = skb; - mock_data_list = g_list_append (mock_data_list, msgv); -/* #3 */ - msgv = g_new0 (struct pgm_msgv_t, 1); - skb = pgm_alloc_skb (TEST_MAX_TPDU); - pgm_skb_put (skb, strlen(source[2]) + 1); - memcpy (skb->data, source[2], strlen(source[2])); - msgv->msgv_len = 1; - msgv->msgv_skb[0] = skb; - mock_data_list = g_list_append (mock_data_list, msgv); - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - gsize bytes_read; - pgm_error_t* err = NULL; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (NULL == err, "error raised"); - fail_unless ((gsize)(strlen(source[0]) + 1) == bytes_read, "unexpected data length"); - g_message ("#1 = \"%s\"", buffer); - fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (NULL == err, "error raised"); - fail_unless ((gsize)(strlen(source[1]) + 1) == bytes_read, "unexpected data length"); - g_message ("#2 = \"%s\"", buffer); - fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); - fail_unless (NULL == err, "error raised"); - fail_unless ((gsize)(strlen(source[2]) + 1) == bytes_read, "unexpected data length"); - g_message ("#3 = \"%s\"", buffer); - push_block_event (); - fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); -} -END_TEST - -START_TEST (test_recv_fail_001) -{ - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - fail_unless (PGM_IO_STATUS_ERROR == pgm_recv (NULL, buffer, sizeof(buffer), 0, NULL, NULL), "recv faied"); -} -END_TEST - -/* target: - * int - * pgm_recvfrom ( - * pgm_sock_t* sock, - * void* data, - * size_t len, - * int flags, - * size_t* bytes_read, - * struct pgm_sockaddr_t* from, - * socklen_t* fromlen, - * pgm_error_t** error - * ) - */ - -START_TEST (test_recvfrom_fail_001) -{ - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - struct pgm_sockaddr_t from; - socklen_t fromlen = sizeof(from); - fail_unless (PGM_IO_STATUS_ERROR == pgm_recvfrom (NULL, buffer, sizeof(buffer), 0, NULL, &from, &fromlen, NULL), "recvfrom failed"); -} -END_TEST - -/* target: - * int - * pgm_recvmsg ( - * pgm_sock_t* sock, - * pgm_msgv_t* msgv, - * int flags, - * size_t* bytes_read, - * pgm_error_t** error - * ) - */ - -START_TEST (test_recvmsg_fail_001) -{ - struct pgm_msgv_t msgv; - fail_unless (PGM_IO_STATUS_ERROR == pgm_recvmsg (NULL, &msgv, 0, NULL, NULL), "recvmsg failed"); -} -END_TEST - -/* target: - * int - * pgm_recvmsgv ( - * pgm_sock_t* sock, - * pgm_msgv_t* msgv, - * unsigned msgv_length, - * int flags, - * size_t* bytes_read, - * pgm_error_t** error - * ) - */ - -START_TEST (test_recvmsgv_fail_001) -{ - struct pgm_msgv_t msgv[1]; - fail_unless (PGM_IO_STATUS_ERROR == pgm_recvmsgv (NULL, msgv, G_N_ELEMENTS(msgv), 0, NULL, NULL), "recvmsgv failed"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_block = tcase_create ("block"); - suite_add_tcase (s, tc_block); - tcase_add_checked_fixture (tc_block, mock_setup, NULL); - tcase_add_test (tc_block, test_block_pass_001); - - TCase* tc_data = tcase_create ("data"); - suite_add_tcase (s, tc_data); - tcase_add_checked_fixture (tc_data, mock_setup, NULL); - tcase_add_test (tc_data, test_data_pass_001); - - TCase* tc_spm = tcase_create ("spm"); - suite_add_tcase (s, tc_spm); - tcase_add_checked_fixture (tc_spm, mock_setup, NULL); - tcase_add_test (tc_spm, test_spm_pass_001); - - TCase* tc_nak = tcase_create ("nak"); - suite_add_tcase (s, tc_nak); - tcase_add_checked_fixture (tc_nak, mock_setup, NULL); - tcase_add_test (tc_nak, test_nak_pass_001); - - TCase* tc_peer_nak = tcase_create ("peer-nak"); - suite_add_tcase (s, tc_peer_nak); - tcase_add_checked_fixture (tc_peer_nak, mock_setup, NULL); - tcase_add_test (tc_peer_nak, test_peer_nak_pass_001); - - TCase* tc_nnak = tcase_create ("nnak"); - suite_add_tcase (s, tc_nnak); - tcase_add_checked_fixture (tc_nnak, mock_setup, NULL); - tcase_add_test (tc_nnak, test_nnak_pass_001); - - TCase* tc_ncf = tcase_create ("ncf"); - suite_add_tcase (s, tc_ncf); - tcase_add_checked_fixture (tc_ncf, mock_setup, NULL); - tcase_add_test (tc_ncf, test_ncf_pass_001); - - TCase* tc_spmr = tcase_create ("spmr"); - suite_add_tcase (s, tc_spmr); - tcase_add_checked_fixture (tc_spmr, mock_setup, NULL); - tcase_add_test (tc_spmr, test_spmr_pass_001); - - TCase* tc_peer_spmr = tcase_create ("peer-spmr"); - suite_add_tcase (s, tc_peer_spmr); - tcase_add_checked_fixture (tc_peer_spmr, mock_setup, NULL); - tcase_add_test (tc_peer_spmr, test_peer_spmr_pass_001); - - TCase* tc_lost = tcase_create ("lost"); - suite_add_tcase (s, tc_lost); - tcase_add_checked_fixture (tc_lost, mock_setup, NULL); - tcase_add_test (tc_lost, test_lost_pass_001); - - TCase* tc_abort_on_lost = tcase_create ("abort-on-lost"); - suite_add_tcase (s, tc_abort_on_lost); - tcase_add_checked_fixture (tc_abort_on_lost, mock_setup, NULL); - tcase_add_test (tc_abort_on_lost, test_abort_on_lost_pass_001); - - TCase* tc_then_lost = tcase_create ("then-lost"); - suite_add_tcase (s, tc_then_lost); - tcase_add_checked_fixture (tc_then_lost, mock_setup, NULL); - tcase_add_test (tc_then_lost, test_then_lost_pass_001); - - TCase* tc_then_abort_on_lost = tcase_create ("then-abort-on-lost"); - suite_add_tcase (s, tc_then_abort_on_lost); - tcase_add_checked_fixture (tc_then_abort_on_lost, mock_setup, NULL); - tcase_add_test (tc_then_abort_on_lost, test_then_abort_on_lost_pass_001); - - TCase* tc_on_data = tcase_create ("on-data"); - suite_add_tcase (s, tc_on_data); - tcase_add_checked_fixture (tc_on_data, mock_setup, NULL); - tcase_add_test (tc_on_data, test_on_data_pass_001); - - TCase* tc_on_zero = tcase_create ("on-zero"); - suite_add_tcase (s, tc_on_zero); - tcase_add_checked_fixture (tc_on_zero, mock_setup, NULL); - tcase_add_test (tc_on_zero, test_on_zero_pass_001); - - TCase* tc_on_many_data = tcase_create ("on-many-data"); - suite_add_tcase (s, tc_on_many_data); - tcase_add_checked_fixture (tc_on_many_data, mock_setup, NULL); - tcase_add_test (tc_on_many_data, test_on_many_data_pass_001); - - TCase* tc_recv = tcase_create ("recv"); - suite_add_tcase (s, tc_recv); - tcase_add_checked_fixture (tc_recv, mock_setup, NULL); - tcase_add_test (tc_recv, test_recv_fail_001); - - TCase* tc_recvfrom = tcase_create ("recvfrom"); - suite_add_tcase (s, tc_recvfrom); - tcase_add_checked_fixture (tc_recvfrom, mock_setup, NULL); - tcase_add_test (tc_recvfrom, test_recvfrom_fail_001); - - TCase* tc_recvmsg = tcase_create ("recvmsg"); - suite_add_tcase (s, tc_recvmsg); - tcase_add_checked_fixture (tc_recvmsg, mock_setup, NULL); - tcase_add_test (tc_recvmsg, test_recvmsg_fail_001); - - TCase* tc_recvmsgv = tcase_create ("recvmsgv"); - suite_add_tcase (s, tc_recvmsgv); - tcase_add_checked_fixture (tc_recvmsgv, mock_setup, NULL); - tcase_add_test (tc_recvmsgv, test_recvmsgv_fail_001); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/reed_solomon.c b/3rdparty/openpgm-svn-r1085/pgm/reed_solomon.c deleted file mode 100644 index a9a292c..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/reed_solomon.c +++ /dev/null @@ -1,576 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Reed-Solomon forward error correction based on Vandermonde matrices. - * - * Output is incompatible with BCH style Reed-Solomon encoding. - * - * draft-ietf-rmt-bb-fec-rs-05.txt - * + rfc5052 - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - - -/* Vector GF(2⁸) plus-equals multiplication. - * - * d[] += b • s[] - */ - -static -void -_pgm_gf_vec_addmul ( - pgm_gf8_t* restrict d, - const pgm_gf8_t b, - const pgm_gf8_t* restrict s, - uint16_t len /* length of vectors */ - ) -{ - uint_fast16_t i; - uint_fast16_t count8; - - if (PGM_UNLIKELY(b == 0)) - return; - -#ifdef CONFIG_GALOIS_MUL_LUT - const pgm_gf8_t* gfmul_b = &pgm_gftable[ (uint16_t)b << 8 ]; -#endif - - i = 0; - count8 = len >> 3; /* 8-way unrolls */ - if (count8) - { - while (count8--) { -#ifdef CONFIG_GALOIS_MUL_LUT - d[i ] ^= gfmul_b[ s[i ] ]; - d[i+1] ^= gfmul_b[ s[i+1] ]; - d[i+2] ^= gfmul_b[ s[i+2] ]; - d[i+3] ^= gfmul_b[ s[i+3] ]; - d[i+4] ^= gfmul_b[ s[i+4] ]; - d[i+5] ^= gfmul_b[ s[i+5] ]; - d[i+6] ^= gfmul_b[ s[i+6] ]; - d[i+7] ^= gfmul_b[ s[i+7] ]; -#else - d[i ] ^= gfmul( b, s[i ] ); - d[i+1] ^= gfmul( b, s[i+1] ); - d[i+2] ^= gfmul( b, s[i+2] ); - d[i+3] ^= gfmul( b, s[i+3] ); - d[i+4] ^= gfmul( b, s[i+4] ); - d[i+5] ^= gfmul( b, s[i+5] ); - d[i+6] ^= gfmul( b, s[i+6] ); - d[i+7] ^= gfmul( b, s[i+7] ); -#endif - i += 8; - } - -/* remaining */ - len %= 8; - } - - while (len--) { -#ifdef CONFIG_GALOIS_MUL_LUT - d[i] ^= gfmul_b[ s[i] ]; -#else - d[i] ^= gfmul( b, s[i] ); -#endif - i++; - } -} - -/* Basic matrix multiplication. - * - * C = AB - * n - * c_i,j = ∑ a_i,j × b_r,j = a_i,1 × b_1,j + a_i,2 × b_2,j + ⋯ + a_i,n × b_n,j - * r=1 - */ - -static -void -_pgm_matmul ( - const pgm_gf8_t* restrict a, /* m-by-n */ - const pgm_gf8_t* restrict b, /* n-by-p */ - pgm_gf8_t* restrict c, /* ∴ m-by-p */ - const uint16_t m, - const uint16_t n, - const uint16_t p - ) -{ - for (uint_fast16_t j = 0; j < m; j++) - { - for (uint_fast16_t i = 0; i < p; i++) - { - pgm_gf8_t sum = 0; - - for (uint_fast16_t k = 0; k < n; k++) - { - sum ^= pgm_gfmul ( a[ (j * n) + k ], b[ (k * p) + i ] ); - } - - c[ (j * p) + i ] = sum; - } - } -} - -/* Generic square matrix inversion - */ - -#ifdef CONFIG_XOR_SWAP -/* whilst cute the xor swap is quite slow */ -#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) -#else -#define SWAP(a, b) do { const pgm_gf8_t _t = (b); (b) = (a); (a) = _t; } while (0) -#endif - -static -void -_pgm_matinv ( - pgm_gf8_t* M, /* is n-by-n */ - const uint8_t n - ) -{ - uint8_t pivot_rows[ n ]; - uint8_t pivot_cols[ n ]; - bool pivots[ n ]; - memset (pivots, 0, sizeof(pivots)); - - pgm_gf8_t identity[ n ]; - memset (identity, 0, sizeof(identity)); - - for (uint_fast8_t i = 0; i < n; i++) - { - uint_fast8_t row = 0, col = 0; - -/* check diagonal for new pivot */ - if (!pivots[ i ] && M[ (i * n) + i ]) - { - row = col = i; - } - else - { - for (uint_fast8_t j = 0; j < n; j++) - { - if (pivots[ j ]) continue; - - for (uint_fast8_t x = 0; x < n; x++) - { - if (!pivots[ x ] && M[ (j * n) + x ]) - { - row = j; - col = x; - goto found; - } - } - } - } - -found: - pivots[ col ] = TRUE; - -/* pivot */ - if (row != col) - { - for (uint_fast8_t x = 0; x < n; x++) - { - pgm_gf8_t *pivot_row = &M[ (row * n) + x ], - *pivot_col = &M[ (col * n) + x ]; - SWAP( *pivot_row, *pivot_col ); - } - } - -/* save location */ - pivot_rows[ i ] = row; - pivot_cols[ i ] = col; - -/* divide row by pivot element */ - if (M[ (col * n) + col ] != 1) - { - const pgm_gf8_t c = M[ (col * n) + col ]; - M[ (col * n) + col ] = 1; - - for (uint_fast8_t x = 0; x < n; x++) - { - M[ (col * n) + x ] = pgm_gfdiv( M[ (col * n) + x ], c ); - } - } - -/* reduce if not an identity row */ - identity[ col ] = 1; - if (memcmp (&M[ (col * n) ], identity, n * sizeof(pgm_gf8_t))) - { - for ( uint_fast8_t x = 0; - x < n; - x++ ) - { - if (x == col) continue; - - const pgm_gf8_t c = M[ (x * n) + col ]; - M[ (x * n) + col ] = 0; - - _pgm_gf_vec_addmul (&M[ x * n ], c, &M[ col * n ], n); - } - } - identity[ col ] = 0; - } - -/* revert all pivots */ - for (int_fast16_t i = n - 1; i >= 0; i--) - { - if (pivot_rows[ i ] != pivot_cols[ i ]) - { - for (uint_fast8_t j = 0; j < n; j++) - { - pgm_gf8_t *pivot_row = &M[ (j * n) + pivot_rows[ i ] ], - *pivot_col = &M[ (j * n) + pivot_cols[ i ] ]; - SWAP( *pivot_row, *pivot_col ); - } - } - } -} - -/* Gauss–Jordan elimination optimised for Vandermonde matrices - * - * matrix = matrix⁻¹ - * - * A Vandermonde matrix exhibits geometric progression in each row: - * - * ⎡ 1 α₁ α₁² ⋯ α₁^^(n-1) ⎤ - * V = ⎢ 1 α₂ α₂² ⋯ α₂^^(n-1) ⎥ - * ⎣ 1 α₃ α₃² ⋯ α₃^^(n-1) ⎦ - * - * First column is actually α_m⁰, second column is α_m¹. - * - * As only the second column is actually unique so optimise from that. - */ - -static -void -_pgm_matinv_vandermonde ( - pgm_gf8_t* V, /* is n-by-n */ - const uint8_t n - ) -{ -/* trivial cases */ - if (n == 1) return; - -/* P_j(α) is polynomial of degree n - 1 defined by - * - * n - * P_j(α) = ∏ (α - α_m) - * m=1 - * - * 1: Work out coefficients. - */ - - pgm_gf8_t P[ n ]; - memset (P, 0, sizeof(P)); - -/* copy across second row, i.e. j = 2 */ - for (uint_fast8_t i = 0; i < n; i++) - { - P[ i ] = V[ (i * n) + 1 ]; - } - - pgm_gf8_t alpha[ n ]; - memset (alpha, 0, sizeof(alpha)); - - alpha[ n - 1 ] = P[ 0 ]; - for (uint_fast8_t i = 1; i < n; i++) - { - for (uint_fast8_t j = (n - i); j < (n - 1); j++) - { - alpha[ j ] ^= pgm_gfmul( P[ i ], alpha[ j + 1 ] ); - } - alpha[ n - 1 ] ^= P[ i ]; - } - -/* 2: Obtain numberators and denominators by synthetic division. - */ - - pgm_gf8_t b[ n ]; - b[ n - 1 ] = 1; - for (uint_fast8_t j = 0; j < n; j++) - { - const pgm_gf8_t xx = P[ j ]; - pgm_gf8_t t = 1; - -/* skip first iteration */ - for (int_fast16_t i = n - 2; i >= 0; i--) - { - b[ i ] = alpha[ i + 1 ] ^ pgm_gfmul( xx, b[ i + 1 ] ); - t = pgm_gfmul( xx, t ) ^ b[ i ]; - } - - for (uint_fast8_t i = 0; i < n; i++) - { - V[ (i * n) + j ] = pgm_gfdiv ( b[ i ], t ); - } - } -} - -/* create the generator matrix of a reed-solomon code. - * - * s GM e - * ⎧ ⎡ s₀ ⎤ ⎡ 1 0 0 ⎤ ⎡ e₀ ⎤ ⎫ - * ⎪ ⎢ ⋮ ⎥ ⎢ 0 1 ⎥ = ⎢ ⋮ ⎥ ⎬ n - * k ⎨ ⎢ ⋮ ⎥ × ⎢ ⋱ ⎥ ⎣e_{n-1}⎦ ⎭ - * ⎪ ⎢ ⋮ ⎥ ⎢ ⋱ ⎥ - * ⎩ ⎣s_{k-1}⎦ ⎣ 0 0 1 ⎦ - * - * e = s × GM - */ - -void -pgm_rs_create ( - pgm_rs_t* rs, - const uint8_t n, - const uint8_t k - ) -{ - pgm_assert (NULL != rs); - pgm_assert (n > 0); - pgm_assert (k > 0); - - rs->n = n; - rs->k = k; - rs->GM = pgm_new0 (pgm_gf8_t, n * k); - rs->RM = pgm_new0 (pgm_gf8_t, k * k); - -/* alpha = root of primitive polynomial of degree m - * ( 1 + x² + x³ + x⁴ + x⁸ ) - * - * V = Vandermonde matrix of k rows and n columns. - * - * Be careful, Harry! - */ -#ifdef CONFIG_PREFER_MALLOC - pgm_gf8_t* V = pgm_new0 (pgm_gf8_t, n * k); -#else - pgm_gf8_t* V = pgm_newa (pgm_gf8_t, n * k); - memset (V, 0, n * k); -#endif - pgm_gf8_t* p = V + k; - V[0] = 1; - for (uint_fast8_t j = 0; j < (n - 1); j++) - { - for (uint_fast8_t i = 0; i < k; i++) - { -/* the {i, j} entry of V_{k,n} is v_{i,j} = α^^(i×j), - * where 0 <= i <= k - 1 and 0 <= j <= n - 1. - */ - *p++ = pgm_gfantilog[ ( i * j ) % PGM_GF_MAX ]; - } - } - -/* This generator matrix would create a Maximum Distance Separable (MDS) - * matrix, a systematic result is required, i.e. original data is left - * unchanged. - * - * GM = V_{k,k}⁻¹ × V_{k,n} - * - * 1: matrix V_{k,k} formed by the first k columns of V_{k,n} - */ - pgm_gf8_t* V_kk = V; - pgm_gf8_t* V_kn = V + (k * k); - -/* 2: invert it - */ - _pgm_matinv_vandermonde (V_kk, k); - -/* 3: multiply by V_{k,n} - */ - _pgm_matmul (V_kn, V_kk, rs->GM + (k * k), n - k, k, k); - -#ifdef CONFIG_PREFER_MALLOC - pgm_free (V); -#endif - -/* 4: set identity matrix for original data - */ - for (uint_fast8_t i = 0; i < k; i++) - { - rs->GM[ (i * k) + i ] = 1; - } -} - -void -pgm_rs_destroy ( - pgm_rs_t* rs - ) -{ - pgm_assert (NULL != rs); - - if (rs->RM) { - pgm_free (rs->RM); - rs->RM = NULL; - } - - if (rs->GM) { - pgm_free (rs->GM); - rs->GM = NULL; - } -} - -/* create a parity packet from a vector of original data packets and - * FEC block packet offset. - */ - -void -pgm_rs_encode ( - pgm_rs_t* restrict rs, - const pgm_gf8_t** restrict src, /* length rs_t::k */ - const uint8_t offset, - pgm_gf8_t* restrict dst, - const uint16_t len - ) -{ - pgm_assert (NULL != rs); - pgm_assert (NULL != src); - pgm_assert (offset >= rs->k && offset < rs->n); /* parity packet */ - pgm_assert (NULL != dst); - pgm_assert (len > 0); - - memset (dst, 0, len); - for (uint_fast8_t i = 0; i < rs->k; i++) - { - const pgm_gf8_t c = rs->GM[ (offset * rs->k) + i ]; - _pgm_gf_vec_addmul (dst, c, src[i], len); - } -} - -/* original data block of packets with missing packet entries replaced - * with on-demand parity packets. - */ - -void -pgm_rs_decode_parity_inline ( - pgm_rs_t* restrict rs, - pgm_gf8_t** restrict block, /* length rs_t::k */ - const uint8_t* restrict offsets, /* offsets within FEC block, 0 < offset < n */ - const uint16_t len /* packet length */ - ) -{ - pgm_assert (NULL != rs); - pgm_assert (NULL != block); - pgm_assert (NULL != offsets); - pgm_assert (len > 0); - -/* create new recovery matrix from generator - */ - for (uint_fast8_t i = 0; i < rs->k; i++) - { - if (offsets[i] < rs->k) { - memset (&rs->RM[ i * rs->k ], 0, rs->k * sizeof(pgm_gf8_t)); - rs->RM[ (i * rs->k) + i ] = 1; - continue; - } - memcpy (&rs->RM[ i * rs->k ], &rs->GM[ offsets[ i ] * rs->k ], rs->k * sizeof(pgm_gf8_t)); - } - -/* invert */ - _pgm_matinv (rs->RM, rs->k); - - pgm_gf8_t* repairs[ rs->k ]; - -/* multiply out, through the length of erasures[] */ - for (uint_fast8_t j = 0; j < rs->k; j++) - { - if (offsets[ j ] < rs->k) - continue; - -#ifdef CONFIG_PREFER_MALLOC - pgm_gf8_t* erasure = repairs[ j ] = pgm_malloc0 (len); -#else - pgm_gf8_t* erasure = repairs[ j ] = pgm_alloca (len); - memset (erasure, 0, len); -#endif - for (uint_fast8_t i = 0; i < rs->k; i++) - { - pgm_gf8_t* src = block[ i ]; - pgm_gf8_t c = rs->RM[ (j * rs->k) + i ]; - _pgm_gf_vec_addmul (erasure, c, src, len); - } - } - -/* move repaired over parity packets */ - for (uint_fast8_t j = 0; j < rs->k; j++) - { - if (offsets[ j ] < rs->k) - continue; - - memcpy (block[ j ], repairs[ j ], len * sizeof(pgm_gf8_t)); -#ifdef CONFIG_PREFER_MALLOC - pgm_free (repairs[ j ]); -#endif - } -} - -/* entire FEC block of original data and parity packets. - * - * erased packet buffers must be zeroed. - */ -void -pgm_rs_decode_parity_appended ( - pgm_rs_t* restrict rs, - pgm_gf8_t** restrict block, /* length rs_t::n, the FEC block */ - const uint8_t* restrict offsets, /* ordered index of packets */ - const uint16_t len /* packet length */ - ) -{ - pgm_assert (NULL != rs); - pgm_assert (NULL != block); - pgm_assert (NULL != offsets); - pgm_assert (len > 0); - -/* create new recovery matrix from generator - */ - for (uint_fast8_t i = 0; i < rs->k; i++) - { - if (offsets[i] < rs->k) { - memset (&rs->RM[ i * rs->k ], 0, rs->k * sizeof(pgm_gf8_t)); - rs->RM[ (i * rs->k) + i ] = 1; - continue; - } - memcpy (&rs->RM[ i * rs->k ], &rs->GM[ offsets[ i ] * rs->k ], rs->k * sizeof(pgm_gf8_t)); - } - -/* invert */ - _pgm_matinv (rs->RM, rs->k); - -/* multiply out, through the length of erasures[] */ - for (uint_fast8_t j = 0; j < rs->k; j++) - { - if (offsets[ j ] < rs->k) - continue; - - uint_fast8_t p = rs->k; - pgm_gf8_t* erasure = block[ j ]; - for (uint_fast8_t i = 0; i < rs->k; i++) - { - pgm_gf8_t* src; - if (offsets[ i ] < rs->k) - src = block[ i ]; - else - src = block[ p++ ]; - const pgm_gf8_t c = rs->RM[ (j * rs->k) + i ]; - _pgm_gf_vec_addmul (erasure, c, src, len); - } - } -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/reed_solomon_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/reed_solomon_unittest.c deleted file mode 100644 index 5e0e75e..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/reed_solomon_unittest.c +++ /dev/null @@ -1,305 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for Reed-Solomon forward error correction based on Vandermonde matrices. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include - - -/* mock state */ - - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - - -#define REED_SOLOMON_DEBUG -#include "reed_solomon.c" - - -/* target: - * void - * pgm_rs_create ( - * pgm_rs_t* rs, - * const uint8_t n, - * const uint8_t k - * ) - */ - -START_TEST (test_create_pass_001) -{ - pgm_rs_t rs; - pgm_rs_create (&rs, 255, 16); -} -END_TEST - -START_TEST (test_create_fail_001) -{ - pgm_rs_create (NULL, 255, 16); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_rs_destroy ( - * pgm_rs_t* rs, - * ) - */ - -START_TEST (test_destroy_pass_001) -{ - pgm_rs_t rs; - pgm_rs_create (&rs, 255, 16); - pgm_rs_destroy (&rs); -} -END_TEST - -START_TEST (test_destroy_fail_001) -{ - pgm_rs_destroy (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_rs_encode ( - * pgm_rs_t* rs, - * const pgm_gf8_t** src, - * const uint8_t offset, - * pgm_gf8_t* dst, - * const uint16_t len - * ) - */ - -START_TEST (test_encode_pass_001) -{ - const gchar source[] = "i am not a string"; - const guint16 source_len = strlen (source); - pgm_rs_t rs; - const guint8 k = source_len; - const guint8 parity_index = k; - const guint16 packet_len = 100; - pgm_gf8_t* source_packets[k]; - pgm_gf8_t* parity_packet = g_malloc0 (packet_len); - pgm_rs_create (&rs, 255, k); - for (unsigned i = 0; i < k; i++) { - source_packets[i] = g_malloc0 (packet_len); - source_packets[i][0] = source[i]; - g_message ("packet#%2.2d: 0x%02.2x '%c'", i, source[i], source[i]); - } - pgm_rs_encode (&rs, (const pgm_gf8_t**)source_packets, parity_index, parity_packet, packet_len); - g_message ("parity-packet: %02.2x", parity_packet[0]); - pgm_rs_destroy (&rs); -} -END_TEST - -START_TEST (test_encode_fail_001) -{ - pgm_rs_encode (NULL, NULL, 0, NULL, 0); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_rs_decode_parity_inline ( - * pgm_rs_t* rs, - * pgm_gf8_t** block, - * const uint8_t* offsets, - * const uint16_t len - * ) - */ - -START_TEST (test_decode_parity_inline_pass_001) -{ - const gchar source[] = "i am not a string"; - const guint16 source_len = strlen (source); - pgm_rs_t rs; - const guint8 k = source_len; - const guint8 parity_index = k; - const guint16 packet_len = 100; - pgm_gf8_t* source_packets[k]; - pgm_gf8_t* parity_packet = g_malloc0 (packet_len); - pgm_rs_create (&rs, 255, k); - for (unsigned i = 0; i < k; i++) { - source_packets[i] = g_malloc0 (packet_len); - source_packets[i][0] = source[i]; - } - pgm_rs_encode (&rs, (const pgm_gf8_t**)source_packets, parity_index, parity_packet, packet_len); -/* simulate error occuring at index #3 */ - const guint erased_index = 3; - source_packets[erased_index][0] = 'X'; - for (unsigned i = 0; i < k; i++) { - g_message ("damaged-packet#%2.2d: 0x%02.2x '%c'", - i, source_packets[i][0], source_packets[i][0]); - } - guint8 offsets[k]; - for (unsigned i = 0; i < k; i++) - offsets[i] = i; -/* erased offset now points to parity packet at k */ - offsets[erased_index] = parity_index; -/* move parity inline */ - g_free (source_packets[erased_index]); - source_packets[erased_index] = parity_packet; - pgm_rs_decode_parity_inline (&rs, source_packets, offsets, packet_len); - pgm_rs_destroy (&rs); - for (unsigned i = 0; i < k; i++) { - g_message ("repaired-packet#%2.2d: 0x%02.2x '%c'", - i, source_packets[i][0], source_packets[i][0]); - } -} -END_TEST - -START_TEST (test_decode_parity_inline_fail_001) -{ - pgm_rs_decode_parity_inline (NULL, NULL, NULL, 0); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_rs_decode_parity_appended ( - * pgm_rs_t* rs, - * pgm_gf8_t* block, - * const uint8_t* offsets, - * const uint16_t len - * ) - */ - -START_TEST (test_decode_parity_appended_pass_001) -{ - const gchar source[] = "i am not a string"; - const guint16 source_len = strlen (source); - pgm_rs_t rs; - const guint8 k = source_len; - const guint8 parity_index = k; - const guint16 packet_len = 100; - pgm_gf8_t* source_packets[k+1]; /* include 1 appended parity packet */ - pgm_gf8_t* parity_packet = g_malloc0 (packet_len); - pgm_rs_create (&rs, 255, k); - for (unsigned i = 0; i < k; i++) { - source_packets[i] = g_malloc0 (packet_len); - source_packets[i][0] = source[i]; - } - pgm_rs_encode (&rs, (const pgm_gf8_t**)source_packets, parity_index, parity_packet, packet_len); -/* simulate error occuring at index #3 */ - const guint erased_index = 3; - source_packets[erased_index][0] = 'X'; - for (unsigned i = 0; i < k; i++) { - g_message ("damaged-packet#%2.2d: 0x%02.2x '%c'", - i, source_packets[i][0], source_packets[i][0]); - } - guint8 offsets[k]; - for (unsigned i = 0; i < k; i++) - offsets[i] = i; -/* erased offset now points to parity packet at k */ - offsets[erased_index] = parity_index; -/* erase damaged packet */ - memset (source_packets[erased_index], 0, packet_len); -/* append parity to source packet block */ - source_packets[parity_index] = parity_packet; - pgm_rs_decode_parity_appended (&rs, source_packets, offsets, packet_len); - pgm_rs_destroy (&rs); - for (unsigned i = 0; i < k; i++) { - g_message ("repaired-packet#%2.2d: 0x%02.2x '%c'", - i, source_packets[i][0], source_packets[i][0]); - } -} -END_TEST - -START_TEST (test_decode_parity_appended_fail_001) -{ - pgm_rs_decode_parity_appended (NULL, NULL, NULL, 0); - fail ("reached"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_create = tcase_create ("create"); - suite_add_tcase (s, tc_create); - tcase_add_test (tc_create, test_create_pass_001); - tcase_add_test_raise_signal (tc_create, test_create_fail_001, SIGABRT); - - TCase* tc_destroy = tcase_create ("destroy"); - suite_add_tcase (s, tc_destroy); - tcase_add_test (tc_destroy, test_destroy_pass_001); - tcase_add_test_raise_signal (tc_destroy, test_destroy_fail_001, SIGABRT); - - TCase* tc_encode = tcase_create ("encode"); - suite_add_tcase (s, tc_encode); - tcase_add_test (tc_encode, test_encode_pass_001); - tcase_add_test_raise_signal (tc_encode, test_encode_fail_001, SIGABRT); - - TCase* tc_decode_parity_inline = tcase_create ("decode-parity-inline"); - suite_add_tcase (s, tc_decode_parity_inline); - tcase_add_test (tc_decode_parity_inline, test_decode_parity_inline_pass_001); - tcase_add_test_raise_signal (tc_decode_parity_inline, test_decode_parity_inline_fail_001, SIGABRT); - - TCase* tc_decode_parity_appended = tcase_create ("decode-parity-appended"); - suite_add_tcase (s, tc_decode_parity_appended); - tcase_add_test (tc_decode_parity_appended, test_decode_parity_appended_pass_001); - tcase_add_test_raise_signal (tc_decode_parity_appended, test_decode_parity_appended_fail_001, SIGABRT); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/rxw.c b/3rdparty/openpgm-svn-r1085/pgm/rxw.c deleted file mode 100644 index ce04ef5..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/rxw.c +++ /dev/null @@ -1,2229 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * A basic receive window: pointer array implementation. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include - - -//#define RXW_DEBUG - -#ifndef RXW_DEBUG -# define PGM_DISABLE_ASSERT -#endif - - -/* testing function: is TSI null - * - * returns TRUE if null, returns FALSE if not null. - */ - -static inline -bool -_pgm_tsi_is_null ( - const void*const tsi - ) -{ - const union { - pgm_tsi_t tsi; - uint32_t l[2]; - } *u = tsi; - -/* pre-conditions */ - pgm_assert (NULL != tsi); - - return (0 == u->l[0] && 0 == u->l[1]); -} - -/* sequence state must be smaller than PGM skbuff control buffer */ -PGM_STATIC_ASSERT(sizeof(struct pgm_rxw_state_t) <= sizeof(((struct pgm_sk_buff_t*)0)->cb)); - -static void _pgm_rxw_define (pgm_rxw_t*const, const uint32_t); -static void _pgm_rxw_update_trail (pgm_rxw_t*const, const uint32_t); -static inline uint32_t _pgm_rxw_update_lead (pgm_rxw_t*const, const uint32_t, const pgm_time_t, const pgm_time_t); -static inline uint32_t _pgm_rxw_tg_sqn (pgm_rxw_t*const, const uint32_t); -static inline uint32_t _pgm_rxw_pkt_sqn (pgm_rxw_t*const, const uint32_t); -static inline bool _pgm_rxw_is_first_of_tg_sqn (pgm_rxw_t*const, const uint32_t); -static inline bool _pgm_rxw_is_last_of_tg_sqn (pgm_rxw_t*const, const uint32_t); -static int _pgm_rxw_insert (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict); -static int _pgm_rxw_append (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict, const pgm_time_t); -static int _pgm_rxw_add_placeholder_range (pgm_rxw_t*const, const uint32_t, const pgm_time_t, const pgm_time_t); -static void _pgm_rxw_unlink (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*restrict); -static uint32_t _pgm_rxw_remove_trail (pgm_rxw_t*const); -static void _pgm_rxw_state (pgm_rxw_t*restrict, struct pgm_sk_buff_t*restrict, const int); -static inline void _pgm_rxw_shuffle_parity (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict); -static inline ssize_t _pgm_rxw_incoming_read (pgm_rxw_t*const restrict, struct pgm_msgv_t**restrict, uint32_t); -static bool _pgm_rxw_is_apdu_complete (pgm_rxw_t*const restrict, const uint32_t); -static inline ssize_t _pgm_rxw_incoming_read_apdu (pgm_rxw_t*const restrict, struct pgm_msgv_t**restrict); -static inline int _pgm_rxw_recovery_update (pgm_rxw_t*const, const uint32_t, const pgm_time_t); -static inline int _pgm_rxw_recovery_append (pgm_rxw_t*const, const pgm_time_t, const pgm_time_t); - - -/* returns the pointer at the given index of the window. - */ - -static -struct pgm_sk_buff_t* -_pgm_rxw_peek ( - const pgm_rxw_t* const window, - const uint32_t sequence - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - - if (pgm_rxw_is_empty (window)) - return NULL; - - if (pgm_uint32_gte (sequence, window->trail) && pgm_uint32_lte (sequence, window->lead)) - { - const uint_fast32_t index_ = sequence % pgm_rxw_max_length (window); - struct pgm_sk_buff_t* skb = window->pdata[index_]; -/* availability only guaranteed inside commit window */ - if (pgm_uint32_lt (sequence, window->commit_lead)) { - pgm_assert (NULL != skb); - pgm_assert (pgm_skb_is_valid (skb)); - pgm_assert (!_pgm_tsi_is_null (&skb->tsi)); - } - return skb; - } - - return NULL; -} - -/* sections of the receive window: - * - * | Commit | Incoming | - * |<---------------->|<------------>| - * | | | - * trail commit-lead lead - * - * commit buffers are currently held by the application, the window trail - * cannot be advanced if packets remain in the commit buffer. - * - * incoming buffers are waiting to be passed to the application. - */ - -static inline -uint32_t -_pgm_rxw_commit_length ( - const pgm_rxw_t* const window - ) -{ - pgm_assert (NULL != window); - return window->commit_lead - window->trail; -} - -static inline -bool -_pgm_rxw_commit_is_empty ( - const pgm_rxw_t* const window - ) -{ - pgm_assert (NULL != window); - return (_pgm_rxw_commit_length (window) == 0); -} - -static inline -uint32_t -_pgm_rxw_incoming_length ( - const pgm_rxw_t* const window - ) -{ - pgm_assert (NULL != window); - return ( 1 + window->lead ) - window->commit_lead; -} - -static inline -bool -_pgm_rxw_incoming_is_empty ( - const pgm_rxw_t* const window - ) -{ - pgm_assert (NULL != window); - return (_pgm_rxw_incoming_length (window) == 0); -} - -/* constructor for receive window. zero-length windows are not permitted. - * - * returns pointer to window. - */ - -pgm_rxw_t* -pgm_rxw_create ( - const pgm_tsi_t* tsi, - const uint16_t tpdu_size, - const unsigned sqns, /* transmit window size in sequence numbers */ - const unsigned secs, /* size in seconds */ - const ssize_t max_rte, /* max bandwidth */ - const uint32_t ack_c_p - ) -{ - pgm_rxw_t* window; - -/* pre-conditions */ - pgm_assert (NULL != tsi); - pgm_assert_cmpuint (tpdu_size, >, 0); - if (sqns) { - pgm_assert_cmpuint (sqns, >, 0); - pgm_assert_cmpuint (sqns & PGM_UINT32_SIGN_BIT, ==, 0); - pgm_assert_cmpuint (secs, ==, 0); - pgm_assert_cmpuint (max_rte, ==, 0); - } else { - pgm_assert_cmpuint (secs, >, 0); - pgm_assert_cmpuint (max_rte, >, 0); - } - - pgm_debug ("create (tsi:%s max-tpdu:%" PRIu16 " sqns:%" PRIu32 " secs %u max-rte %zd ack-c_p %" PRIu32 ")", - pgm_tsi_print (tsi), tpdu_size, sqns, secs, max_rte, ack_c_p); - -/* calculate receive window parameters */ - pgm_assert (sqns || (secs && max_rte)); - const unsigned alloc_sqns = sqns ? sqns : ( (secs * max_rte) / tpdu_size ); - window = pgm_malloc0 (sizeof(pgm_rxw_t) + ( alloc_sqns * sizeof(struct pgm_sk_buff_t*) )); - - window->tsi = tsi; - window->max_tpdu = tpdu_size; - -/* empty state: - * - * trail = 0, lead = -1 - * commit_trail = commit_lead = rxw_trail = rxw_trail_init = 0 - */ - window->lead = -1; - window->trail = window->lead + 1; - -/* limit retransmit requests on late session joining */ - window->is_constrained = TRUE; - -/* minimum value of RS::k = 1 */ - window->tg_size = 1; - -/* PGMCC filter weight */ - window->ack_c_p = pgm_fp16 (ack_c_p); - window->bitmap = 0xffffffff; - -/* pointer array */ - window->alloc = alloc_sqns; - -/* post-conditions */ - pgm_assert_cmpuint (pgm_rxw_max_length (window), ==, alloc_sqns); - pgm_assert_cmpuint (pgm_rxw_length (window), ==, 0); - pgm_assert_cmpuint (pgm_rxw_size (window), ==, 0); - pgm_assert (pgm_rxw_is_empty (window)); - pgm_assert (!pgm_rxw_is_full (window)); - - return window; -} - -/* destructor for receive window. must not be called more than once for same window. - */ - -void -pgm_rxw_destroy ( - pgm_rxw_t* const window - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert_cmpuint (window->alloc, >, 0); - - pgm_debug ("destroy (window:%p)", (const void*)window); - -/* contents of window */ - while (!pgm_rxw_is_empty (window)) { - _pgm_rxw_remove_trail (window); - } - -/* window must now be empty */ - pgm_assert_cmpuint (pgm_rxw_length (window), ==, 0); - pgm_assert_cmpuint (pgm_rxw_size (window), ==, 0); - pgm_assert (pgm_rxw_is_empty (window)); - pgm_assert (!pgm_rxw_is_full (window)); - -/* window */ - pgm_free (window); -} - -/* add skb to receive window. window has fixed size and will not grow. - * PGM skbuff data/tail pointers must point to the PGM payload, and hence skb->len - * is allowed to be zero. - * - * if the skb sequence number indicates lost packets placeholders will be defined - * for each missing entry in the window. - * - * side effects: - * - * 1) sequence number is set in skb from PGM header value. - * 2) window may be updated with new skb. - * 3) placeholders may be created for detected lost packets. - * 4) parity skbs may be shuffled to accomodate original data. - * - * returns: - * PGM_RXW_INSERTED - packet filled a waiting placeholder, skb consumed. - * PGM_RXW_APPENDED - packet advanced window lead, skb consumed. - * PGM_RXW_MISSING - missing packets detected whilst window lead was adanced, skb consumed. - * PGM_RXW_DUPLICATE - re-transmission of previously seen packet. - * PGM_RXW_MALFORMED - corrupted or invalid packet. - * PGM_RXW_BOUNDS - packet out of window. - * - * it is an error to try to free the skb after adding to the window. - */ - -int -pgm_rxw_add ( - pgm_rxw_t* const restrict window, - struct pgm_sk_buff_t* const restrict skb, - const pgm_time_t now, - const pgm_time_t nak_rb_expiry /* calculated expiry time for this skb */ - ) -{ - pgm_rxw_state_t* const state = (pgm_rxw_state_t*)&skb->cb; - int status; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != skb); - pgm_assert_cmpuint (nak_rb_expiry, >, 0); - pgm_assert_cmpuint (pgm_rxw_max_length (window), >, 0); - pgm_assert (pgm_skb_is_valid (skb)); - pgm_assert (((const pgm_list_t*)skb)->next == NULL); - pgm_assert (((const pgm_list_t*)skb)->prev == NULL); - pgm_assert (!_pgm_tsi_is_null (&skb->tsi)); - pgm_assert ((char*)skb->data > (char*)skb->head); - pgm_assert (sizeof(struct pgm_header) + sizeof(struct pgm_data) <= (size_t)((char*)skb->data - (char*)skb->head)); - pgm_assert (skb->len == ((char*)skb->tail - (char*)skb->data)); - - pgm_debug ("add (window:%p skb:%p nak_rb_expiry:%" PGM_TIME_FORMAT ")", - (const void*)window, (const void*)skb, nak_rb_expiry); - - skb->sequence = ntohl (skb->pgm_data->data_sqn); - -/* protocol sanity check: tsdu size */ - if (PGM_UNLIKELY(skb->len != ntohs (skb->pgm_header->pgm_tsdu_length))) - return PGM_RXW_MALFORMED; - -/* protocol sanity check: valid trail pointer wrt. sequence */ - if (PGM_UNLIKELY(skb->sequence - ntohl (skb->pgm_data->data_trail) >= ((UINT32_MAX/2)-1))) - return PGM_RXW_MALFORMED; - -/* verify fragment header for original data, parity packets include a - * parity fragment header - */ - if (!(skb->pgm_header->pgm_options & PGM_OPT_PARITY) && - skb->pgm_opt_fragment) - { -/* protocol sanity check: single fragment APDU */ - if (PGM_UNLIKELY(ntohl (skb->of_apdu_len) == skb->len)) - skb->pgm_opt_fragment = NULL; - -/* protocol sanity check: minimum APDU length */ - if (PGM_UNLIKELY(ntohl (skb->of_apdu_len) < skb->len)) - return PGM_RXW_MALFORMED; - -/* protocol sanity check: sequential ordering */ - if (PGM_UNLIKELY(pgm_uint32_gt (ntohl (skb->of_apdu_first_sqn), skb->sequence))) - return PGM_RXW_MALFORMED; - -/* protocol sanity check: maximum APDU length */ - if (PGM_UNLIKELY(ntohl (skb->of_apdu_len) > PGM_MAX_APDU)) - return PGM_RXW_MALFORMED; - } - -/* first packet of a session defines the window */ - if (PGM_UNLIKELY(!window->is_defined)) - _pgm_rxw_define (window, skb->sequence - 1); /* previous_lead needed for append to occur */ - else - _pgm_rxw_update_trail (window, ntohl (skb->pgm_data->data_trail)); - -/* bounds checking for parity data occurs at the transmission group sequence number */ - if (skb->pgm_header->pgm_options & PGM_OPT_PARITY) - { - if (pgm_uint32_lt (_pgm_rxw_tg_sqn (window, skb->sequence), _pgm_rxw_tg_sqn (window, window->commit_lead))) - return PGM_RXW_DUPLICATE; - - if (pgm_uint32_lt (_pgm_rxw_tg_sqn (window, skb->sequence), _pgm_rxw_tg_sqn (window, window->lead))) { - window->has_event = 1; - return _pgm_rxw_insert (window, skb); - } - - const struct pgm_sk_buff_t* const first_skb = _pgm_rxw_peek (window, _pgm_rxw_tg_sqn (window, skb->sequence)); - const pgm_rxw_state_t* const first_state = (pgm_rxw_state_t*)&first_skb->cb; - - if (_pgm_rxw_tg_sqn (window, skb->sequence) == _pgm_rxw_tg_sqn (window, window->lead)) { - window->has_event = 1; - if (NULL == first_state || first_state->is_contiguous) { - state->is_contiguous = 1; - return _pgm_rxw_append (window, skb, now); - } else - return _pgm_rxw_insert (window, skb); - } - - pgm_assert (NULL != first_state); - status = _pgm_rxw_add_placeholder_range (window, _pgm_rxw_tg_sqn (window, skb->sequence), now, nak_rb_expiry); - } - else - { - if (pgm_uint32_lt (skb->sequence, window->commit_lead)) { - if (pgm_uint32_gte (skb->sequence, window->trail)) - return PGM_RXW_DUPLICATE; - else - return PGM_RXW_BOUNDS; - } - - if (pgm_uint32_lte (skb->sequence, window->lead)) { - window->has_event = 1; - return _pgm_rxw_insert (window, skb); - } - - if (skb->sequence == pgm_rxw_next_lead (window)) { - window->has_event = 1; - if (_pgm_rxw_is_first_of_tg_sqn (window, skb->sequence)) - state->is_contiguous = 1; - return _pgm_rxw_append (window, skb, now); - } - - status = _pgm_rxw_add_placeholder_range (window, skb->sequence, now, nak_rb_expiry); - } - - if (PGM_RXW_APPENDED == status) { - status = _pgm_rxw_append (window, skb, now); - if (PGM_RXW_APPENDED == status) - status = PGM_RXW_MISSING; - } - return status; -} - -/* trail is the next packet to commit upstream, lead is the leading edge - * of the receive window with possible gaps inside, rxw_trail is the transmit - * window trail for retransmit requests. - */ - -/* define window by parameters of first data packet. - */ - -static -void -_pgm_rxw_define ( - pgm_rxw_t* const window, - const uint32_t lead - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (pgm_rxw_is_empty (window)); - pgm_assert (_pgm_rxw_commit_is_empty (window)); - pgm_assert (_pgm_rxw_incoming_is_empty (window)); - pgm_assert (!window->is_defined); - - window->lead = lead; - window->commit_lead = window->rxw_trail = window->rxw_trail_init = window->trail = window->lead + 1; - window->is_constrained = window->is_defined = TRUE; - -/* post-conditions */ - pgm_assert (pgm_rxw_is_empty (window)); - pgm_assert (_pgm_rxw_commit_is_empty (window)); - pgm_assert (_pgm_rxw_incoming_is_empty (window)); - pgm_assert (window->is_defined); - pgm_assert (window->is_constrained); -} - -/* update window with latest transmitted parameters. - * - * returns count of placeholders added into window, used to start sending naks. - */ - -unsigned -pgm_rxw_update ( - pgm_rxw_t* const window, - const uint32_t txw_lead, - const uint32_t txw_trail, - const pgm_time_t now, - const pgm_time_t nak_rb_expiry /* packet expiration time */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert_cmpuint (nak_rb_expiry, >, 0); - - pgm_debug ("pgm_rxw_update (window:%p txw-lead:%" PRIu32 " txw-trail:%" PRIu32 " nak-rb-expiry:%" PGM_TIME_FORMAT ")", - (void*)window, txw_lead, txw_trail, nak_rb_expiry); - - if (PGM_UNLIKELY(!window->is_defined)) { - _pgm_rxw_define (window, txw_lead); - return 0; - } - - _pgm_rxw_update_trail (window, txw_trail); - return _pgm_rxw_update_lead (window, txw_lead, now, nak_rb_expiry); -} - -/* update trailing edge of receive window - */ - -static -void -_pgm_rxw_update_trail ( - pgm_rxw_t* const window, - const uint32_t txw_trail - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - -/* advertised trail is less than the current value */ - if (PGM_UNLIKELY(pgm_uint32_lte (txw_trail, window->rxw_trail))) - return; - -/* protocol sanity check: advertised trail jumps too far ahead */ - if (PGM_UNLIKELY(txw_trail - window->rxw_trail > ((UINT32_MAX/2)-1))) - return; - -/* retransmissions requests are constrained on startup until the advertised trail advances - * beyond the first data sequence number. - */ - if (PGM_UNLIKELY(window->is_constrained)) - { - if (pgm_uint32_gt (txw_trail, window->rxw_trail_init)) - window->is_constrained = FALSE; - else - return; - } - - window->rxw_trail = txw_trail; - -/* new value doesn't affect window */ - if (PGM_UNLIKELY(pgm_uint32_lte (window->rxw_trail, window->trail))) - return; - -/* jump remaining sequence numbers if window is empty */ - if (pgm_rxw_is_empty (window)) - { - const uint32_t distance = (int32_t)(window->rxw_trail) - (int32_t)(window->trail); - window->commit_lead = window->trail += distance; - window->lead += distance; - -/* add loss to bitmap */ - if (distance > 32) window->bitmap = 0; - else window->bitmap <<= distance; - -/* update the Exponential Moving Average (EMA) data loss with long jump: - * s_t = α × (p₁ + (1 - α) × p₂ + (1 - α)² × p₃ + ⋯) - * omitting the weight by stopping after k terms, - * = α × ((1 - α)^^k + (1 - α)^^{k+1} +(1 - α)^^{k+1} + ⋯) - * = α × (1 - α)^^k × (1 + (1 - α) + (1 - α)² + ⋯) - * = (1 - α)^^k - */ - window->data_loss = pgm_fp16mul (window->data_loss, pgm_fp16pow (pgm_fp16 (1) - window->ack_c_p, distance)); - - window->cumulative_losses += distance; - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Data loss due to trailing edge update, fragment count %" PRIu32 "."),window->fragment_count); - pgm_assert (pgm_rxw_is_empty (window)); - pgm_assert (_pgm_rxw_commit_is_empty (window)); - pgm_assert (_pgm_rxw_incoming_is_empty (window)); - return; - } - -/* remove all buffers between commit lead and advertised rxw_trail */ - for (uint32_t sequence = window->commit_lead; - pgm_uint32_gt (window->rxw_trail, sequence) && pgm_uint32_gte (window->lead, sequence); - sequence++) - { - struct pgm_sk_buff_t* skb; - pgm_rxw_state_t* state; - - skb = _pgm_rxw_peek (window, sequence); - pgm_assert (NULL != skb); - state = (pgm_rxw_state_t*)&skb->cb; - - switch (state->pkt_state) { - case PGM_PKT_STATE_HAVE_DATA: - case PGM_PKT_STATE_HAVE_PARITY: - case PGM_PKT_STATE_LOST_DATA: - break; - - case PGM_PKT_STATE_ERROR: - pgm_assert_not_reached(); - - default: - pgm_rxw_lost (window, sequence); - break; - } - } - -/* post-conditions: only after flush */ -// pgm_assert (!pgm_rxw_is_full (window)); -} - -/* update FEC parameters - */ - -void -pgm_rxw_update_fec ( - pgm_rxw_t* const window, - const uint8_t rs_k - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert_cmpuint (rs_k, >, 1); - - pgm_debug ("pgm_rxw_update_fec (window:%p rs(k):%u)", - (void*)window, rs_k); - - if (window->is_fec_available) { - if (rs_k == window->rs.k) return; - pgm_rs_destroy (&window->rs); - } else - window->is_fec_available = 1; - pgm_rs_create (&window->rs, PGM_RS_DEFAULT_N, rs_k); - window->tg_sqn_shift = pgm_power2_log2 (rs_k); - window->tg_size = window->rs.k; -} - -/* add one placeholder to leading edge due to detected lost packet. - */ - -static -void -_pgm_rxw_add_placeholder ( - pgm_rxw_t* const window, - const pgm_time_t now, - const pgm_time_t nak_rb_expiry - ) -{ - struct pgm_sk_buff_t* skb; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (!pgm_rxw_is_full (window)); - -/* advance lead */ - window->lead++; - -/* add loss to bitmap */ - window->bitmap <<= 1; - -/* update the Exponential Moving Average (EMA) data loss with loss: - * s_t = α × x_{t-1} + (1 - α) × s_{t-1} - * x_{t-1} = 1 - * ∴ s_t = α + (1 - α) × s_{t-1} - */ - window->data_loss = window->ack_c_p + pgm_fp16mul ((pgm_fp16 (1) - window->ack_c_p), window->data_loss); - - skb = pgm_alloc_skb (window->max_tpdu); - pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; - skb->tstamp = now; - skb->sequence = window->lead; - state->timer_expiry = nak_rb_expiry; - - if (!_pgm_rxw_is_first_of_tg_sqn (window, skb->sequence)) - { - struct pgm_sk_buff_t* first_skb = _pgm_rxw_peek (window, _pgm_rxw_tg_sqn (window, skb->sequence)); - if (first_skb) { - pgm_rxw_state_t* first_state = (pgm_rxw_state_t*)&first_skb->cb; - first_state->is_contiguous = 0; - } - } - -/* add skb to window */ - const uint_fast32_t index_ = skb->sequence % pgm_rxw_max_length (window); - window->pdata[index_] = skb; - - pgm_rxw_state (window, skb, PGM_PKT_STATE_BACK_OFF); - -/* post-conditions */ - pgm_assert_cmpuint (pgm_rxw_length (window), >, 0); - pgm_assert_cmpuint (pgm_rxw_length (window), <=, pgm_rxw_max_length (window)); - pgm_assert_cmpuint (_pgm_rxw_incoming_length (window), >, 0); -} - -/* add a range of placeholders to the window. - */ - -static -int -_pgm_rxw_add_placeholder_range ( - pgm_rxw_t* const window, - const uint32_t sequence, - const pgm_time_t now, - const pgm_time_t nak_rb_expiry - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (pgm_uint32_gt (sequence, pgm_rxw_lead (window))); - -/* check bounds of commit window */ - const uint32_t new_commit_sqns = ( 1 + sequence ) - window->trail; - if ( !_pgm_rxw_commit_is_empty (window) && - (new_commit_sqns >= pgm_rxw_max_length (window)) ) - { - _pgm_rxw_update_lead (window, sequence, now, nak_rb_expiry); - return PGM_RXW_BOUNDS; /* effectively a slow consumer */ - } - - if (pgm_rxw_is_full (window)) { - pgm_assert (_pgm_rxw_commit_is_empty (window)); - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Receive window full on placeholder sequence.")); - _pgm_rxw_remove_trail (window); - } - -/* if packet is non-contiguous to current leading edge add place holders - * TODO: can be rather inefficient on packet loss looping through dropped sequence numbers - */ - while (pgm_rxw_next_lead (window) != sequence) - { - _pgm_rxw_add_placeholder (window, now, nak_rb_expiry); - if (pgm_rxw_is_full (window)) { - pgm_assert (_pgm_rxw_commit_is_empty (window)); - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Receive window full on placeholder sequence.")); - _pgm_rxw_remove_trail (window); - } - } - -/* post-conditions */ - pgm_assert (!pgm_rxw_is_full (window)); - - return PGM_RXW_APPENDED; -} - -/* update leading edge of receive window. - * - * returns number of place holders added. - */ - -static -unsigned -_pgm_rxw_update_lead ( - pgm_rxw_t* const window, - const uint32_t txw_lead, - const pgm_time_t now, - const pgm_time_t nak_rb_expiry - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - -/* advertised lead is less than the current value */ - if (PGM_UNLIKELY(pgm_uint32_lte (txw_lead, window->lead))) - return 0; - - uint32_t lead; - -/* committed packets limit constrain the lead until they are released */ - if (!_pgm_rxw_commit_is_empty (window) && - (txw_lead - window->trail) >= pgm_rxw_max_length (window)) - { - lead = window->trail + pgm_rxw_max_length (window) - 1; - if (lead == window->lead) - return 0; - } - else - lead = txw_lead; - - unsigned lost = 0; - - while (window->lead != lead) - { -/* slow consumer or fast producer */ - if (pgm_rxw_is_full (window)) { - pgm_assert (_pgm_rxw_commit_is_empty (window)); - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Receive window full on window lead advancement.")); - _pgm_rxw_remove_trail (window); - } - _pgm_rxw_add_placeholder (window, now, nak_rb_expiry); - lost++; - } - - return lost; -} - -/* checks whether an APDU is unrecoverable due to lost TPDUs. - */ -static inline -bool -_pgm_rxw_is_apdu_lost ( - pgm_rxw_t* const restrict window, - struct pgm_sk_buff_t* const restrict skb - ) -{ - const pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != skb); - -/* lost is lost */ - if (PGM_PKT_STATE_LOST_DATA == state->pkt_state) - return TRUE; - -/* by definition, a single-TPDU APDU is complete */ - if (!skb->pgm_opt_fragment) - return FALSE; - - const uint32_t apdu_first_sqn = ntohl (skb->of_apdu_first_sqn); - -/* by definition, first fragment indicates APDU is available */ - if (apdu_first_sqn == skb->sequence) - return FALSE; - - const struct pgm_sk_buff_t* const first_skb = _pgm_rxw_peek (window, apdu_first_sqn); -/* first fragment out-of-bounds */ - if (NULL == first_skb) - return TRUE; - - const pgm_rxw_state_t* first_state = (pgm_rxw_state_t*)&first_skb->cb; - if (PGM_PKT_STATE_LOST_DATA == first_state->pkt_state) - return TRUE; - - return FALSE; -} - -/* return the first missing packet sequence in the specified transmission - * group or NULL if not required. - */ - -static inline -struct pgm_sk_buff_t* -_pgm_rxw_find_missing ( - pgm_rxw_t* const window, - const uint32_t tg_sqn /* tg_sqn | pkt_sqn */ - ) -{ - struct pgm_sk_buff_t* skb; - pgm_rxw_state_t* state; - -/* pre-conditions */ - pgm_assert (NULL != window); - - for (uint32_t i = tg_sqn, j = 0; j < window->tg_size; i++, j++) - { - skb = _pgm_rxw_peek (window, i); - pgm_assert (NULL != skb); - state = (pgm_rxw_state_t*)&skb->cb; - switch (state->pkt_state) { - case PGM_PKT_STATE_BACK_OFF: - case PGM_PKT_STATE_WAIT_NCF: - case PGM_PKT_STATE_WAIT_DATA: - case PGM_PKT_STATE_LOST_DATA: - return skb; - - case PGM_PKT_STATE_HAVE_DATA: - case PGM_PKT_STATE_HAVE_PARITY: - break; - - default: pgm_assert_not_reached(); break; - } - } - - return NULL; -} - -/* returns TRUE if skb is a parity packet with packet length not - * matching the transmission group length without the variable-packet-length - * flag set. - */ - -static inline -bool -_pgm_rxw_is_invalid_var_pktlen ( - pgm_rxw_t* const restrict window, - const struct pgm_sk_buff_t* const restrict skb - ) -{ - const struct pgm_sk_buff_t* first_skb; - -/* pre-conditions */ - pgm_assert (NULL != window); - - if (!window->is_fec_available) - return FALSE; - - if (skb->pgm_header->pgm_options & PGM_OPT_VAR_PKTLEN) - return FALSE; - - const uint32_t tg_sqn = _pgm_rxw_tg_sqn (window, skb->sequence); - if (tg_sqn == skb->sequence) - return FALSE; - - first_skb = _pgm_rxw_peek (window, tg_sqn); - if (NULL == first_skb) - return TRUE; /* transmission group unrecoverable */ - - if (first_skb->len == skb->len) - return FALSE; - - return TRUE; -} - -static inline -bool -_pgm_rxw_has_payload_op ( - const struct pgm_sk_buff_t* const skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != skb); - pgm_assert (NULL != skb->pgm_header); - - return skb->pgm_opt_fragment || skb->pgm_header->pgm_options & PGM_OP_ENCODED; -} - -/* returns TRUE is skb options are invalid when compared to the transmission group - */ - -static inline -bool -_pgm_rxw_is_invalid_payload_op ( - pgm_rxw_t* const restrict window, - const struct pgm_sk_buff_t* const restrict skb - ) -{ - const struct pgm_sk_buff_t* first_skb; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != skb); - - if (!window->is_fec_available) - return FALSE; - - const uint32_t tg_sqn = _pgm_rxw_tg_sqn (window, skb->sequence); - if (tg_sqn == skb->sequence) - return FALSE; - - first_skb = _pgm_rxw_peek (window, tg_sqn); - if (NULL == first_skb) - return TRUE; /* transmission group unrecoverable */ - - if (_pgm_rxw_has_payload_op (first_skb) == _pgm_rxw_has_payload_op (skb)) - return FALSE; - - return TRUE; -} - -/* insert skb into window range, discard if duplicate. window will have placeholder, - * parity, or data packet already matching sequence. - * - * returns: - * PGM_RXW_INSERTED - packet filled a waiting placeholder, skb consumed. - * PGM_RXW_DUPLICATE - re-transmission of previously seen packet. - * PGM_RXW_MALFORMED - corrupted or invalid packet. - * PGM_RXW_BOUNDS - packet out of window. - */ - -static -int -_pgm_rxw_insert ( - pgm_rxw_t* const restrict window, - struct pgm_sk_buff_t* const restrict new_skb - ) -{ - struct pgm_sk_buff_t* skb; - pgm_rxw_state_t* state; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != new_skb); - pgm_assert (!_pgm_rxw_incoming_is_empty (window)); - - if (PGM_UNLIKELY(_pgm_rxw_is_invalid_var_pktlen (window, new_skb) || - _pgm_rxw_is_invalid_payload_op (window, new_skb))) - return PGM_RXW_MALFORMED; - - if (new_skb->pgm_header->pgm_options & PGM_OPT_PARITY) - { - skb = _pgm_rxw_find_missing (window, new_skb->sequence); - if (NULL == skb) - return PGM_RXW_DUPLICATE; - state = (pgm_rxw_state_t*)&skb->cb; - } - else - { - skb = _pgm_rxw_peek (window, new_skb->sequence); - pgm_assert (NULL != skb); - state = (pgm_rxw_state_t*)&skb->cb; - - if (state->pkt_state == PGM_PKT_STATE_HAVE_DATA) - return PGM_RXW_DUPLICATE; - } - -/* APDU fragments are already declared lost */ - if (new_skb->pgm_opt_fragment && - _pgm_rxw_is_apdu_lost (window, new_skb)) - { - pgm_rxw_lost (window, skb->sequence); - return PGM_RXW_BOUNDS; - } - -/* verify placeholder state */ - switch (state->pkt_state) { - case PGM_PKT_STATE_BACK_OFF: - case PGM_PKT_STATE_WAIT_NCF: - case PGM_PKT_STATE_WAIT_DATA: - case PGM_PKT_STATE_LOST_DATA: - break; - - case PGM_PKT_STATE_HAVE_PARITY: - _pgm_rxw_shuffle_parity (window, skb); - break; - - default: pgm_assert_not_reached(); break; - } - -/* statistics */ - const pgm_time_t fill_time = new_skb->tstamp - skb->tstamp; - PGM_HISTOGRAM_TIMES("Rx.RepairTime", fill_time); - PGM_HISTOGRAM_COUNTS("Rx.NakTransmits", state->nak_transmit_count); - PGM_HISTOGRAM_COUNTS("Rx.NcfRetries", state->ncf_retry_count); - PGM_HISTOGRAM_COUNTS("Rx.DataRetries", state->data_retry_count); - if (!window->max_fill_time) { - window->max_fill_time = window->min_fill_time = fill_time; - } - else - { - if (fill_time > window->max_fill_time) - window->max_fill_time = fill_time; - else if (fill_time < window->min_fill_time) - window->min_fill_time = fill_time; - - if (!window->max_nak_transmit_count) { - window->max_nak_transmit_count = window->min_nak_transmit_count = state->nak_transmit_count; - } else { - if (state->nak_transmit_count > window->max_nak_transmit_count) - window->max_nak_transmit_count = state->nak_transmit_count; - else if (state->nak_transmit_count < window->min_nak_transmit_count) - window->min_nak_transmit_count = state->nak_transmit_count; - } - } - -/* add packet to bitmap */ - const uint_fast32_t pos = window->lead - new_skb->sequence; - if (pos < 32) { - window->bitmap |= 1 << pos; - } - -/* update the Exponential Moving Average (EMA) data loss with repair data. - * s_t = α × x_{t-1} + (1 - α) × s_{t-1} - * x_{t-1} = 0 - * ∴ s_t = (1 - α) × s_{t-1} - */ - const uint_fast32_t s = pgm_fp16pow (pgm_fp16 (1) - window->ack_c_p, pos); - if (s > window->data_loss) window->data_loss = 0; - else window->data_loss -= s; - -/* replace place holder skb with incoming skb */ - memcpy (new_skb->cb, skb->cb, sizeof(skb->cb)); - pgm_rxw_state_t* rxw_state = (void*)new_skb->cb; - rxw_state->pkt_state = PGM_PKT_STATE_ERROR; - _pgm_rxw_unlink (window, skb); - pgm_free_skb (skb); - const uint_fast32_t index_ = new_skb->sequence % pgm_rxw_max_length (window); - window->pdata[index_] = new_skb; - if (new_skb->pgm_header->pgm_options & PGM_OPT_PARITY) - _pgm_rxw_state (window, new_skb, PGM_PKT_STATE_HAVE_PARITY); - else - _pgm_rxw_state (window, new_skb, PGM_PKT_STATE_HAVE_DATA); - window->size += new_skb->len; - - return PGM_RXW_INSERTED; -} - -/* shuffle parity packet at skb->sequence to any other needed spot. - */ - -static inline -void -_pgm_rxw_shuffle_parity ( - pgm_rxw_t* const restrict window, - struct pgm_sk_buff_t* const restrict skb - ) -{ - uint_fast32_t index_; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != skb); - - struct pgm_sk_buff_t* restrict missing = _pgm_rxw_find_missing (window, skb->sequence); - if (NULL == missing) - return; - -/* replace place holder skb with parity skb */ - char cb[48]; - _pgm_rxw_unlink (window, missing); - memcpy (cb, skb->cb, sizeof(skb->cb)); - memcpy (skb->cb, missing->cb, sizeof(skb->cb)); - memcpy (missing->cb, cb, sizeof(skb->cb)); - index_ = skb->sequence % pgm_rxw_max_length (window); - window->pdata[index_] = skb; - index_ = missing->sequence % pgm_rxw_max_length (window); - window->pdata[index_] = missing; -} - -/* skb advances the window lead. - * - * returns: - * PGM_RXW_APPENDED - packet advanced window lead, skb consumed. - * PGM_RXW_MALFORMED - corrupted or invalid packet. - * PGM_RXW_BOUNDS - packet out of window. - */ - -static -int -_pgm_rxw_append ( - pgm_rxw_t* const restrict window, - struct pgm_sk_buff_t* const restrict skb, - const pgm_time_t now - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != skb); - if (skb->pgm_header->pgm_options & PGM_OPT_PARITY) { - pgm_assert (_pgm_rxw_tg_sqn (window, skb->sequence) == _pgm_rxw_tg_sqn (window, pgm_rxw_lead (window))); - } else { - pgm_assert (skb->sequence == pgm_rxw_next_lead (window)); - } - - if (PGM_UNLIKELY(_pgm_rxw_is_invalid_var_pktlen (window, skb) || - _pgm_rxw_is_invalid_payload_op (window, skb))) - return PGM_RXW_MALFORMED; - - if (pgm_rxw_is_full (window)) { - if (_pgm_rxw_commit_is_empty (window)) { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Receive window full on new data.")); - _pgm_rxw_remove_trail (window); - } else { - return PGM_RXW_BOUNDS; /* constrained by commit window */ - } - } - -/* advance leading edge */ - window->lead++; - -/* add packet to bitmap */ - window->bitmap = (window->bitmap << 1) | 1; - -/* update the Exponential Moving Average (EMA) data loss with data: - * s_t = α × x_{t-1} + (1 - α) × s_{t-1} - * x_{t-1} = 0 - * ∴ s_t = (1 - α) × s_{t-1} - */ - window->data_loss = pgm_fp16mul (window->data_loss, pgm_fp16 (1) - window->ack_c_p); - -/* APDU fragments are already declared lost */ - if (PGM_UNLIKELY(skb->pgm_opt_fragment && - _pgm_rxw_is_apdu_lost (window, skb))) - { - struct pgm_sk_buff_t* lost_skb = pgm_alloc_skb (window->max_tpdu); - lost_skb->tstamp = now; - lost_skb->sequence = skb->sequence; - -/* add lost-placeholder skb to window */ - const uint_fast32_t index_ = lost_skb->sequence % pgm_rxw_max_length (window); - window->pdata[index_] = lost_skb; - - _pgm_rxw_state (window, lost_skb, PGM_PKT_STATE_LOST_DATA); - return PGM_RXW_BOUNDS; - } - -/* add skb to window */ - if (skb->pgm_header->pgm_options & PGM_OPT_PARITY) - { - const uint_fast32_t index_ = skb->sequence % pgm_rxw_max_length (window); - window->pdata[index_] = skb; - _pgm_rxw_state (window, skb, PGM_PKT_STATE_HAVE_PARITY); - } - else - { - const uint_fast32_t index_ = skb->sequence % pgm_rxw_max_length (window); - window->pdata[index_] = skb; - _pgm_rxw_state (window, skb, PGM_PKT_STATE_HAVE_DATA); - } - -/* statistics */ - window->size += skb->len; - - return PGM_RXW_APPENDED; -} - -/* remove references to all commit packets not in the same transmission group - * as the commit-lead - */ - -void -pgm_rxw_remove_commit ( - pgm_rxw_t* const window - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - - const uint32_t tg_sqn_of_commit_lead = _pgm_rxw_tg_sqn (window, window->commit_lead); - - while (!_pgm_rxw_commit_is_empty (window) && - tg_sqn_of_commit_lead != _pgm_rxw_tg_sqn (window, window->trail)) - { - _pgm_rxw_remove_trail (window); - } -} - -/* flush packets but instead of calling on_data append the contiguous data packets - * to the provided scatter/gather vector. - * - * when transmission groups are enabled, packets remain in the windows tagged committed - * until the transmission group has been completely committed. this allows the packet - * data to be used in parity calculations to recover the missing packets. - * - * returns -1 on nothing read, returns length of bytes read, 0 is a valid read length. - * - * PGM skbuffs will have an increased reference count and must be unreferenced by the - * calling application. - */ - -ssize_t -pgm_rxw_readv ( - pgm_rxw_t* const restrict window, - struct pgm_msgv_t** restrict pmsg, /* message array, updated as messages appended */ - const unsigned pmsglen /* number of items in pmsg */ - ) -{ - const struct pgm_msgv_t* msg_end; - struct pgm_sk_buff_t* skb; - pgm_rxw_state_t* state; - ssize_t bytes_read; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != pmsg); - pgm_assert_cmpuint (pmsglen, >, 0); - - pgm_debug ("readv (window:%p pmsg:%p pmsglen:%u)", - (void*)window, (void*)pmsg, pmsglen); - - msg_end = *pmsg + pmsglen - 1; - - if (_pgm_rxw_incoming_is_empty (window)) - return -1; - - skb = _pgm_rxw_peek (window, window->commit_lead); - pgm_assert (NULL != skb); - - state = (pgm_rxw_state_t*)&skb->cb; - switch (state->pkt_state) { - case PGM_PKT_STATE_HAVE_DATA: - bytes_read = _pgm_rxw_incoming_read (window, pmsg, msg_end - *pmsg + 1); - break; - - case PGM_PKT_STATE_LOST_DATA: -/* do not purge in situ sequence */ - if (_pgm_rxw_commit_is_empty (window)) { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Removing lost trail from window")); - _pgm_rxw_remove_trail (window); - } else { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Locking trail at commit window")); - } -/* fall through */ - case PGM_PKT_STATE_BACK_OFF: - case PGM_PKT_STATE_WAIT_NCF: - case PGM_PKT_STATE_WAIT_DATA: - case PGM_PKT_STATE_HAVE_PARITY: - bytes_read = -1; - break; - - case PGM_PKT_STATE_COMMIT_DATA: - case PGM_PKT_STATE_ERROR: - default: - pgm_assert_not_reached(); - break; - } - - return bytes_read; -} - -/* remove lost sequences from the trailing edge of the window. lost sequence - * at lead of commit window invalidates all parity-data packets as any - * transmission group is now unrecoverable. - * - * returns number of sequences purged. - */ - -static -unsigned -_pgm_rxw_remove_trail ( - pgm_rxw_t* const window - ) -{ - struct pgm_sk_buff_t* skb; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (!pgm_rxw_is_empty (window)); - - skb = _pgm_rxw_peek (window, window->trail); - pgm_assert (NULL != skb); - _pgm_rxw_unlink (window, skb); - window->size -= skb->len; -/* remove reference to skb */ - if (PGM_UNLIKELY(pgm_mem_gc_friendly)) { - const uint_fast32_t index_ = skb->sequence % pgm_rxw_max_length (window); - window->pdata[index_] = NULL; - } - pgm_free_skb (skb); - if (window->trail++ == window->commit_lead) { -/* data-loss */ - window->commit_lead++; - window->cumulative_losses++; - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Data loss due to pulled trailing edge, fragment count %" PRIu32 "."),window->fragment_count); - return 1; - } - return 0; -} - -unsigned -pgm_rxw_remove_trail ( - pgm_rxw_t* const window - ) -{ - pgm_debug ("remove_trail (window:%p)", (const void*)window); - return _pgm_rxw_remove_trail (window); -} - -/* read contiguous APDU-grouped sequences from the incoming window. - * - * side effects: - * - * 1) increments statics for window messages and bytes read. - * - * returns count of bytes read. - */ - -static inline -ssize_t -_pgm_rxw_incoming_read ( - pgm_rxw_t* const restrict window, - struct pgm_msgv_t** restrict pmsg, /* message array, updated as messages appended */ - unsigned pmsglen /* number of items in pmsg */ - ) -{ - const struct pgm_msgv_t* msg_end; - struct pgm_sk_buff_t* skb; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != pmsg); - pgm_assert_cmpuint (pmsglen, >, 0); - pgm_assert (!_pgm_rxw_incoming_is_empty (window)); - - pgm_debug ("_pgm_rxw_incoming_read (window:%p pmsg:%p pmsglen:%u)", - (void*)window, (void*)pmsg, pmsglen); - - msg_end = *pmsg + pmsglen - 1; - ssize_t bytes_read = 0; - size_t data_read = 0; - - do { - skb = _pgm_rxw_peek (window, window->commit_lead); - pgm_assert (NULL != skb); - if (_pgm_rxw_is_apdu_complete (window, - skb->pgm_opt_fragment ? ntohl (skb->of_apdu_first_sqn) : skb->sequence)) - { - bytes_read += _pgm_rxw_incoming_read_apdu (window, pmsg); - data_read ++; - } - else break; - } while (*pmsg <= msg_end && !_pgm_rxw_incoming_is_empty (window)); - - window->bytes_delivered += bytes_read; - window->msgs_delivered += data_read; - return data_read > 0 ? bytes_read : -1; -} - -/* returns TRUE if transmission group is lost. - * - * checking is lightly limited to bounds. - */ - -static inline -bool -_pgm_rxw_is_tg_sqn_lost ( - pgm_rxw_t* const window, - const uint32_t tg_sqn /* transmission group sequence */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert_cmpuint (_pgm_rxw_pkt_sqn (window, tg_sqn), ==, 0); - - if (pgm_rxw_is_empty (window)) - return TRUE; - - if (pgm_uint32_lt (tg_sqn, window->trail)) - return TRUE; - - return FALSE; -} - -/* reconstruct missing sequences in a transmission group using embedded parity data. - */ - -static -void -_pgm_rxw_reconstruct ( - pgm_rxw_t* const window, - const uint32_t tg_sqn /* transmission group sequence */ - ) -{ - struct pgm_sk_buff_t* skb; - pgm_rxw_state_t* state; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (1 == window->is_fec_available); - pgm_assert_cmpuint (_pgm_rxw_pkt_sqn (window, tg_sqn), ==, 0); - - skb = _pgm_rxw_peek (window, tg_sqn); - pgm_assert (NULL != skb); - - const bool is_var_pktlen = skb->pgm_header->pgm_options & PGM_OPT_VAR_PKTLEN; - const bool is_op_encoded = skb->pgm_header->pgm_options & PGM_OPT_PRESENT; - const uint16_t parity_length = ntohs (skb->pgm_header->pgm_tsdu_length); - struct pgm_sk_buff_t* tg_skbs[ window->rs.n ]; - pgm_gf8_t* tg_data[ window->rs.n ]; - pgm_gf8_t* tg_opts[ window->rs.n ]; - uint8_t offsets[ window->rs.k ]; - uint8_t rs_h = 0; - - for (uint32_t i = tg_sqn, j = 0; i != (tg_sqn + window->rs.k); i++, j++) - { - skb = _pgm_rxw_peek (window, i); - pgm_assert (NULL != skb); - state = (pgm_rxw_state_t*)&skb->cb; - switch (state->pkt_state) { - case PGM_PKT_STATE_HAVE_DATA: - tg_skbs[ j ] = skb; - tg_data[ j ] = skb->data; - tg_opts[ j ] = (pgm_gf8_t*)skb->pgm_opt_fragment; - offsets[ j ] = j; - break; - - case PGM_PKT_STATE_HAVE_PARITY: - tg_skbs[ window->rs.k + rs_h ] = skb; - tg_data[ window->rs.k + rs_h ] = skb->data; - tg_opts[ window->rs.k + rs_h ] = (pgm_gf8_t*)skb->pgm_opt_fragment; - offsets[ j ] = window->rs.k + rs_h; - ++rs_h; -/* fall through and alloc new skb for reconstructed data */ - case PGM_PKT_STATE_BACK_OFF: - case PGM_PKT_STATE_WAIT_NCF: - case PGM_PKT_STATE_WAIT_DATA: - case PGM_PKT_STATE_LOST_DATA: - skb = pgm_alloc_skb (window->max_tpdu); - pgm_skb_reserve (skb, sizeof(struct pgm_header) + sizeof(struct pgm_data)); - skb->pgm_header = skb->head; - skb->pgm_data = (void*)( skb->pgm_header + 1 ); - if (is_op_encoded) { - const uint16_t opt_total_length = sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fragment); - pgm_skb_reserve (skb, opt_total_length); - skb->pgm_opt_fragment = (void*)( skb->pgm_data + 1 ); - pgm_skb_put (skb, parity_length); - memset (skb->pgm_opt_fragment, 0, opt_total_length + parity_length); - } else { - pgm_skb_put (skb, parity_length); - memset (skb->data, 0, parity_length); - } - tg_skbs[ j ] = skb; - tg_data[ j ] = skb->data; - tg_opts[ j ] = (void*)skb->pgm_opt_fragment; - break; - - default: pgm_assert_not_reached(); break; - } - - if (!skb->zero_padded) { - memset (skb->tail, 0, parity_length - skb->len); - skb->zero_padded = 1; - } - - } - -/* reconstruct payload */ - pgm_rs_decode_parity_appended (&window->rs, - tg_data, - offsets, - parity_length); - -/* reconstruct opt_fragment option */ - if (is_op_encoded) - pgm_rs_decode_parity_appended (&window->rs, - tg_opts, - offsets, - sizeof(struct pgm_opt_fragment)); - -/* swap parity skbs with reconstructed skbs */ - for (uint_fast8_t i = 0; i < window->rs.k; i++) - { - if (offsets[i] < window->rs.k) - continue; - - struct pgm_sk_buff_t* repair_skb = tg_skbs[i]; - - if (is_var_pktlen) - { - const uint16_t pktlen = *(uint16_t*)( (char*)repair_skb->tail - sizeof(uint16_t)); - if (pktlen > parity_length) { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Invalid encoded variable packet length in reconstructed packet, dropping entire transmission group.")); - pgm_free_skb (repair_skb); - for (uint_fast8_t j = i; j < window->rs.k; j++) - { - if (offsets[j] < window->rs.k) - continue; - pgm_rxw_lost (window, tg_skbs[offsets[j]]->sequence); - } - break; - } - const uint16_t padding = parity_length - pktlen; - repair_skb->len -= padding; - repair_skb->tail = (char*)repair_skb->tail - padding; - } - -#ifdef PGM_DISABLE_ASSERT - _pgm_rxw_insert (window, repair_skb); -#else - pgm_assert_cmpint (_pgm_rxw_insert (window, repair_skb), ==, PGM_RXW_INSERTED); -#endif - } -} - -/* check every TPDU in an APDU and verify that the data has arrived - * and is available to commit to the application. - * - * if APDU sits in a transmission group that can be reconstructed use parity - * data then the entire group will be decoded and any missing data packets - * replaced by the recovery calculation. - * - * packets with single fragment fragment headers must be normalised as regular - * packets before calling. - * - * APDUs exceeding PGM_MAX_FRAGMENTS or PGM_MAX_APDU length will be discarded. - * - * returns FALSE if APDU is incomplete or longer than max_len sequences. - */ - -static -bool -_pgm_rxw_is_apdu_complete ( - pgm_rxw_t* const window, - const uint32_t first_sequence - ) -{ - struct pgm_sk_buff_t* skb; - pgm_rxw_state_t* state; - -/* pre-conditions */ - pgm_assert (NULL != window); - - pgm_debug ("_pgm_rxw_is_apdu_complete (window:%p first-sequence:%" PRIu32 ")", - (const void*)window, first_sequence); - - skb = _pgm_rxw_peek (window, first_sequence); - if (PGM_UNLIKELY(NULL == skb)) { - return FALSE; - } - - const size_t apdu_size = skb->pgm_opt_fragment ? ntohl (skb->of_apdu_len) : skb->len; - const uint32_t tg_sqn = _pgm_rxw_tg_sqn (window, first_sequence); - uint32_t sequence = first_sequence; - unsigned contiguous_tpdus = 0; - size_t contiguous_size = 0; - bool check_parity = FALSE; - - pgm_assert_cmpuint (apdu_size, >=, skb->len); - -/* protocol sanity check: maximum length */ - if (PGM_UNLIKELY(apdu_size > PGM_MAX_APDU)) { - pgm_rxw_lost (window, first_sequence); - return FALSE; - } - - do { - state = (pgm_rxw_state_t*)&skb->cb; - - if (!check_parity && - PGM_PKT_STATE_HAVE_DATA != state->pkt_state) - { - if (window->is_fec_available && - !_pgm_rxw_is_tg_sqn_lost (window, tg_sqn) ) - { - check_parity = TRUE; -/* pre-seed committed sequence count */ - if (pgm_uint32_lte (tg_sqn, window->commit_lead)) - contiguous_tpdus += window->commit_lead - tg_sqn; - } - else - return FALSE; - } - - if (check_parity) - { - if (PGM_PKT_STATE_HAVE_DATA == state->pkt_state || - PGM_PKT_STATE_HAVE_PARITY == state->pkt_state) - ++contiguous_tpdus; - -/* have sufficient been received for reconstruction */ - if (contiguous_tpdus >= window->tg_size) { - _pgm_rxw_reconstruct (window, tg_sqn); - return _pgm_rxw_is_apdu_complete (window, first_sequence); - } - } - else - { -/* single packet APDU, already complete */ - if (PGM_PKT_STATE_HAVE_DATA == state->pkt_state && - !skb->pgm_opt_fragment) - return TRUE; - -/* protocol sanity check: matching first sequence reference */ - if (PGM_UNLIKELY(ntohl (skb->of_apdu_first_sqn) != first_sequence)) { - pgm_rxw_lost (window, first_sequence); - return FALSE; - } - -/* protocol sanity check: matching apdu length */ - if (PGM_UNLIKELY(ntohl (skb->of_apdu_len) != apdu_size)) { - pgm_rxw_lost (window, first_sequence); - return FALSE; - } - -/* protocol sanity check: maximum number of fragments per apdu */ - if (PGM_UNLIKELY(++contiguous_tpdus > PGM_MAX_FRAGMENTS)) { - pgm_rxw_lost (window, first_sequence); - return FALSE; - } - - contiguous_size += skb->len; - if (apdu_size == contiguous_size) - return TRUE; - else if (PGM_UNLIKELY(apdu_size < contiguous_size)) { - pgm_rxw_lost (window, first_sequence); - return FALSE; - } - } - - skb = _pgm_rxw_peek (window, ++sequence); - } while (skb); - -/* pending */ - return FALSE; -} - -/* read one APDU consisting of one or more TPDUs. target array is guaranteed - * to be big enough to store complete APDU. - */ - -static inline -ssize_t -_pgm_rxw_incoming_read_apdu ( - pgm_rxw_t* const restrict window, - struct pgm_msgv_t** restrict pmsg /* message array, updated as messages appended */ - ) -{ - struct pgm_sk_buff_t *skb; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != pmsg); - - pgm_debug ("_pgm_rxw_incoming_read_apdu (window:%p pmsg:%p)", - (const void*)window, (const void*)pmsg); - - skb = _pgm_rxw_peek (window, window->commit_lead); - size_t contiguous_len = 0; - const size_t apdu_len = skb->pgm_opt_fragment ? ntohl (skb->of_apdu_len) : skb->len; - unsigned i = 0; - pgm_assert_cmpuint (apdu_len, >=, skb->len); - (*pmsg)->msgv_len = 0; - do { - _pgm_rxw_state (window, skb, PGM_PKT_STATE_COMMIT_DATA); - (*pmsg)->msgv_skb[i++] = skb; - (*pmsg)->msgv_len++; - contiguous_len += skb->len; - window->commit_lead++; - if (apdu_len == contiguous_len) - break; - skb = _pgm_rxw_peek (window, window->commit_lead); - } while (apdu_len > contiguous_len); - - (*pmsg)++; - -/* post-conditions */ - pgm_assert (!_pgm_rxw_commit_is_empty (window)); - -return contiguous_len; -} - -/* returns transmission group sequence (TG_SQN) from sequence (SQN). - */ - -static inline -uint32_t -_pgm_rxw_tg_sqn ( - pgm_rxw_t* const window, - const uint32_t sequence - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - - const uint32_t tg_sqn_mask = 0xffffffff << window->tg_sqn_shift; - return sequence & tg_sqn_mask; -} - -/* returns packet number (PKT_SQN) from sequence (SQN). - */ - -static inline -uint32_t -_pgm_rxw_pkt_sqn ( - pgm_rxw_t* const window, - const uint32_t sequence - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - - const uint32_t tg_sqn_mask = 0xffffffff << window->tg_sqn_shift; - return sequence & ~tg_sqn_mask; -} - -/* returns TRUE when the sequence is the first of a transmission group. - */ - -static inline -bool -_pgm_rxw_is_first_of_tg_sqn ( - pgm_rxw_t* const window, - const uint32_t sequence - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - - return _pgm_rxw_pkt_sqn (window, sequence) == 0; -} - -/* returns TRUE when the sequence is the last of a transmission group - */ - -static inline -bool -_pgm_rxw_is_last_of_tg_sqn ( - pgm_rxw_t* const window, - const uint32_t sequence - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - - return _pgm_rxw_pkt_sqn (window, sequence) == window->tg_size - 1; -} - -/* set PGM skbuff to new FSM state. - */ - -static -void -_pgm_rxw_state ( - pgm_rxw_t* const restrict window, - struct pgm_sk_buff_t* const restrict skb, - const int new_pkt_state - ) -{ - pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != skb); - -/* remove current state */ - if (PGM_PKT_STATE_ERROR != state->pkt_state) - _pgm_rxw_unlink (window, skb); - - switch (new_pkt_state) { - case PGM_PKT_STATE_BACK_OFF: - pgm_queue_push_head_link (&window->nak_backoff_queue, (pgm_list_t*)skb); - break; - - case PGM_PKT_STATE_WAIT_NCF: - pgm_queue_push_head_link (&window->wait_ncf_queue, (pgm_list_t*)skb); - break; - - case PGM_PKT_STATE_WAIT_DATA: - pgm_queue_push_head_link (&window->wait_data_queue, (pgm_list_t*)skb); - break; - - case PGM_PKT_STATE_HAVE_DATA: - window->fragment_count++; - pgm_assert_cmpuint (window->fragment_count, <=, pgm_rxw_length (window)); - break; - - case PGM_PKT_STATE_HAVE_PARITY: - window->parity_count++; - pgm_assert_cmpuint (window->parity_count, <=, pgm_rxw_length (window)); - break; - - case PGM_PKT_STATE_COMMIT_DATA: - window->committed_count++; - pgm_assert_cmpuint (window->committed_count, <=, pgm_rxw_length (window)); - break; - - case PGM_PKT_STATE_LOST_DATA: - window->lost_count++; - window->cumulative_losses++; - window->has_event = 1; - pgm_assert_cmpuint (window->lost_count, <=, pgm_rxw_length (window)); - break; - - case PGM_PKT_STATE_ERROR: - break; - - default: pgm_assert_not_reached(); break; - } - - state->pkt_state = new_pkt_state; -} - -void -pgm_rxw_state ( - pgm_rxw_t* const restrict window, - struct pgm_sk_buff_t* const restrict skb, - const int new_pkt_state - ) -{ - pgm_debug ("state (window:%p skb:%p new_pkt_state:%s)", - (const void*)window, (const void*)skb, pgm_pkt_state_string (new_pkt_state)); - _pgm_rxw_state (window, skb, new_pkt_state); -} - -/* remove current state from sequence. - */ - -static -void -_pgm_rxw_unlink ( - pgm_rxw_t* const restrict window, - struct pgm_sk_buff_t* const restrict skb - ) -{ - pgm_queue_t* queue; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != skb); - - pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; - - switch (state->pkt_state) { - case PGM_PKT_STATE_BACK_OFF: - pgm_assert (!pgm_queue_is_empty (&window->nak_backoff_queue)); - queue = &window->nak_backoff_queue; - goto unlink_queue; - - case PGM_PKT_STATE_WAIT_NCF: - pgm_assert (!pgm_queue_is_empty (&window->wait_ncf_queue)); - queue = &window->wait_ncf_queue; - goto unlink_queue; - - case PGM_PKT_STATE_WAIT_DATA: - pgm_assert (!pgm_queue_is_empty (&window->wait_data_queue)); - queue = &window->wait_data_queue; -unlink_queue: - pgm_queue_unlink (queue, (pgm_list_t*)skb); - break; - - case PGM_PKT_STATE_HAVE_DATA: - pgm_assert_cmpuint (window->fragment_count, >, 0); - window->fragment_count--; - break; - - case PGM_PKT_STATE_HAVE_PARITY: - pgm_assert_cmpuint (window->parity_count, >, 0); - window->parity_count--; - break; - - case PGM_PKT_STATE_COMMIT_DATA: - pgm_assert_cmpuint (window->committed_count, >, 0); - window->committed_count--; - break; - - case PGM_PKT_STATE_LOST_DATA: - pgm_assert_cmpuint (window->lost_count, >, 0); - window->lost_count--; - break; - - case PGM_PKT_STATE_ERROR: - break; - - default: pgm_assert_not_reached(); break; - } - - state->pkt_state = PGM_PKT_STATE_ERROR; - pgm_assert (((pgm_list_t*)skb)->next == NULL); - pgm_assert (((pgm_list_t*)skb)->prev == NULL); -} - -/* returns the pointer at the given index of the window. - */ - -struct pgm_sk_buff_t* -pgm_rxw_peek ( - pgm_rxw_t* const window, - const uint32_t sequence - ) -{ - pgm_debug ("peek (window:%p sequence:%" PRIu32 ")", (void*)window, sequence); - return _pgm_rxw_peek (window, sequence); -} - -/* mark an existing sequence lost due to failed recovery. - */ - -void -pgm_rxw_lost ( - pgm_rxw_t* const window, - const uint32_t sequence - ) -{ - struct pgm_sk_buff_t* skb; - pgm_rxw_state_t* state; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (!pgm_rxw_is_empty (window)); - - pgm_debug ("lost (window:%p sequence:%" PRIu32 ")", - (const void*)window, sequence); - - skb = _pgm_rxw_peek (window, sequence); - pgm_assert (NULL != skb); - - state = (pgm_rxw_state_t*)&skb->cb; - - if (PGM_UNLIKELY(!(state->pkt_state == PGM_PKT_STATE_BACK_OFF || - state->pkt_state == PGM_PKT_STATE_WAIT_NCF || - state->pkt_state == PGM_PKT_STATE_WAIT_DATA || - state->pkt_state == PGM_PKT_STATE_HAVE_DATA || /* fragments */ - state->pkt_state == PGM_PKT_STATE_HAVE_PARITY))) - { - pgm_fatal (_("Unexpected state %s(%u)"), pgm_pkt_state_string (state->pkt_state), state->pkt_state); - pgm_assert_not_reached(); - } - - _pgm_rxw_state (window, skb, PGM_PKT_STATE_LOST_DATA); -} - -/* received a uni/multicast ncf, search for a matching nak & tag or extend window if - * beyond lead - * - * returns: - * PGM_RXW_BOUNDS - sequence is outside of window, or window is undefined. - * PGM_RXW_UPDATED - receiver state updated, waiting for data. - * PGM_RXW_DUPLICATE - data already exists at sequence. - * PGM_RXW_APPENDED - lead is extended with state set waiting for data. - */ - -int -pgm_rxw_confirm ( - pgm_rxw_t* const window, - const uint32_t sequence, - const pgm_time_t now, - const pgm_time_t nak_rdata_expiry, /* pre-calculated expiry times */ - const pgm_time_t nak_rb_expiry - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - - pgm_debug ("confirm (window:%p sequence:%" PRIu32 " nak_rdata_expiry:%" PGM_TIME_FORMAT " nak_rb_expiry:%" PGM_TIME_FORMAT ")", - (void*)window, sequence, nak_rdata_expiry, nak_rb_expiry); - -/* NCFs do not define the transmit window */ - if (PGM_UNLIKELY(!window->is_defined)) - return PGM_RXW_BOUNDS; - -/* sequence already committed */ - if (pgm_uint32_lt (sequence, window->commit_lead)) { - if (pgm_uint32_gte (sequence, window->trail)) - return PGM_RXW_DUPLICATE; - else - return PGM_RXW_BOUNDS; - } - - if (pgm_uint32_lte (sequence, window->lead)) - return _pgm_rxw_recovery_update (window, sequence, nak_rdata_expiry); - - if (sequence == window->lead) - return _pgm_rxw_recovery_append (window, now, nak_rdata_expiry); - else { - _pgm_rxw_add_placeholder_range (window, sequence, now, nak_rb_expiry); - return _pgm_rxw_recovery_append (window, now, nak_rdata_expiry); - } -} - -/* update an incoming sequence with state transition to WAIT-DATA. - * - * returns: - * PGM_RXW_UPDATED - receiver state updated, waiting for data. - * PGM_RXW_DUPLICATE - data already exists at sequence. - */ - -static inline -int -_pgm_rxw_recovery_update ( - pgm_rxw_t* const window, - const uint32_t sequence, - const pgm_time_t nak_rdata_expiry /* pre-calculated expiry times */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - -/* fetch skb from window and bump expiration times */ - struct pgm_sk_buff_t* skb = _pgm_rxw_peek (window, sequence); - pgm_assert (NULL != skb); - pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; - switch (state->pkt_state) { - case PGM_PKT_STATE_BACK_OFF: - case PGM_PKT_STATE_WAIT_NCF: - pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_DATA); - -/* fall through */ - case PGM_PKT_STATE_WAIT_DATA: - state->timer_expiry = nak_rdata_expiry; - return PGM_RXW_UPDATED; - - case PGM_PKT_STATE_HAVE_DATA: - case PGM_PKT_STATE_HAVE_PARITY: - case PGM_PKT_STATE_COMMIT_DATA: - case PGM_PKT_STATE_LOST_DATA: - break; - - default: pgm_assert_not_reached(); break; - } - - return PGM_RXW_DUPLICATE; -} - -/* append an skb to the incoming window with WAIT-DATA state. - * - * returns: - * PGM_RXW_APPENDED - lead is extended with state set waiting for data. - * PGM_RXW_BOUNDS - constrained by commit window - */ - -static inline -int -_pgm_rxw_recovery_append ( - pgm_rxw_t* const window, - const pgm_time_t now, - const pgm_time_t nak_rdata_expiry /* pre-calculated expiry times */ - ) -{ - struct pgm_sk_buff_t* skb; - -/* pre-conditions */ - pgm_assert (NULL != window); - - if (pgm_rxw_is_full (window)) { - if (_pgm_rxw_commit_is_empty (window)) { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Receive window full on confirmed sequence.")); - _pgm_rxw_remove_trail (window); - } else { - return PGM_RXW_BOUNDS; /* constrained by commit window */ - } - } - -/* advance leading edge */ - window->lead++; - -/* add loss to bitmap */ - window->bitmap <<= 1; - -/* update the Exponential Moving Average (EMA) data loss with loss: - * s_t = α × x_{t-1} + (1 - α) × s_{t-1} - * x_{t-1} = 1 - * ∴ s_t = α + (1 - α) × s_{t-1} - */ - window->data_loss = window->ack_c_p + pgm_fp16mul (pgm_fp16 (1) - window->ack_c_p, window->data_loss); - - skb = pgm_alloc_skb (window->max_tpdu); - pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; - skb->tstamp = now; - skb->sequence = window->lead; - state->timer_expiry = nak_rdata_expiry; - - const uint_fast32_t index_ = pgm_rxw_lead (window) % pgm_rxw_max_length (window); - window->pdata[index_] = skb; - _pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_DATA); - - return PGM_RXW_APPENDED; -} - -/* dumps window state to stdout - */ - -void -pgm_rxw_dump ( - const pgm_rxw_t* const window - ) -{ - pgm_info ("window = {" - "tsi = {gsi = {identifier = %i.%i.%i.%i.%i.%i}, sport = %" PRIu16 "}, " - "nak_backoff_queue = {head = %p, tail = %p, length = %u}, " - "wait_ncf_queue = {head = %p, tail = %p, length = %u}, " - "wait_data_queue = {head = %p, tail = %p, length = %u}, " - "lost_count = %" PRIu32 ", " - "fragment_count = %" PRIu32 ", " - "parity_count = %" PRIu32 ", " - "committed_count = %" PRIu32 ", " - "max_tpdu = %" PRIu16 ", " - "tg_size = %" PRIu32 ", " - "tg_sqn_shift = %u, " - "lead = %" PRIu32 ", " - "trail = %" PRIu32 ", " - "rxw_trail = %" PRIu32 ", " - "rxw_trail_init = %" PRIu32 ", " - "commit_lead = %" PRIu32 ", " - "is_constrained = %u, " - "is_defined = %u, " - "has_event = %u, " - "is_fec_available = %u, " - "min_fill_time = %" PRIu32 ", " - "max_fill_time = %" PRIu32 ", " - "min_nak_transmit_count = %" PRIu32 ", " - "max_nak_transmit_count = %" PRIu32 ", " - "cumulative_losses = %" PRIu32 ", " - "bytes_delivered = %" PRIu32 ", " - "msgs_delivered = %" PRIu32 ", " - "size = %zu, " - "alloc = %" PRIu32 ", " - "pdata = []" - "}", - window->tsi->gsi.identifier[0], - window->tsi->gsi.identifier[1], - window->tsi->gsi.identifier[2], - window->tsi->gsi.identifier[3], - window->tsi->gsi.identifier[4], - window->tsi->gsi.identifier[5], - ntohs (window->tsi->sport), - (void*)window->nak_backoff_queue.head, - (void*)window->nak_backoff_queue.tail, - window->nak_backoff_queue.length, - (void*)window->wait_ncf_queue.head, - (void*)window->wait_ncf_queue.tail, - window->wait_ncf_queue.length, - (void*)window->wait_data_queue.head, - (void*)window->wait_data_queue.tail, - window->wait_data_queue.length, - window->lost_count, - window->fragment_count, - window->parity_count, - window->committed_count, - window->max_tpdu, - window->tg_size, - window->tg_sqn_shift, - window->lead, - window->trail, - window->rxw_trail, - window->rxw_trail_init, - window->commit_lead, - window->is_constrained, - window->is_defined, - window->has_event, - window->is_fec_available, - window->min_fill_time, - window->max_fill_time, - window->min_nak_transmit_count, - window->max_nak_transmit_count, - window->cumulative_losses, - window->bytes_delivered, - window->msgs_delivered, - window->size, - window->alloc - ); -} - -/* state string helper - */ - -const char* -pgm_pkt_state_string ( - const int pkt_state - ) -{ - const char* c; - - switch (pkt_state) { - case PGM_PKT_STATE_BACK_OFF: c = "PGM_PKT_STATE_BACK_OFF"; break; - case PGM_PKT_STATE_WAIT_NCF: c = "PGM_PKT_STATE_WAIT_NCF"; break; - case PGM_PKT_STATE_WAIT_DATA: c = "PGM_PKT_STATE_WAIT_DATA"; break; - case PGM_PKT_STATE_HAVE_DATA: c = "PGM_PKT_STATE_HAVE_DATA"; break; - case PGM_PKT_STATE_HAVE_PARITY: c = "PGM_PKT_STATE_HAVE_PARITY"; break; - case PGM_PKT_STATE_COMMIT_DATA: c = "PGM_PKT_STATE_COMMIT_DATA"; break; - case PGM_PKT_STATE_LOST_DATA: c = "PGM_PKT_STATE_LOST_DATA"; break; - case PGM_PKT_STATE_ERROR: c = "PGM_PKT_STATE_ERROR"; break; - default: c = "(unknown)"; break; - } - - return c; -} - -const char* -pgm_rxw_returns_string ( - const int rxw_returns - ) -{ - const char* c; - - switch (rxw_returns) { - case PGM_RXW_OK: c = "PGM_RXW_OK"; break; - case PGM_RXW_INSERTED: c = "PGM_RXW_INSERTED"; break; - case PGM_RXW_APPENDED: c = "PGM_RXW_APPENDED"; break; - case PGM_RXW_UPDATED: c = "PGM_RXW_UPDATED"; break; - case PGM_RXW_MISSING: c = "PGM_RXW_MISSING"; break; - case PGM_RXW_DUPLICATE: c = "PGM_RXW_DUPLICATE"; break; - case PGM_RXW_MALFORMED: c = "PGM_RXW_MALFORMED"; break; - case PGM_RXW_BOUNDS: c = "PGM_RXW_BOUNDS"; break; - case PGM_RXW_SLOW_CONSUMER: c = "PGM_RXW_SLOW_CONSUMER"; break; - case PGM_RXW_UNKNOWN: c = "PGM_RXW_UNKNOWN"; break; - default: c = "(unknown)"; break; - } - - return c; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/rxw_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/rxw_unittest.c deleted file mode 100644 index 635c854..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/rxw_unittest.c +++ /dev/null @@ -1,1844 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for receive window. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include - - -/* mock global */ - - -#define pgm_histogram_add mock_pgm_histogram_add -#define pgm_time_now mock_pgm_time_now -#define pgm_rs_create mock_pgm_rs_create -#define pgm_rs_destroy mock_pgm_rs_destroy -#define pgm_rs_decode_parity_appended mock_pgm_rs_decode_parity_appended -#define pgm_histogram_init mock_pgm_histogram_init - -#define RXW_DEBUG -#include "rxw.c" - -#ifdef PGM_DISABLE_ASSERT -# error "PGM_DISABLE_ASSERT set" -#endif - -static pgm_time_t mock_pgm_time_now = 0x1; - - -/* mock functions for external references */ - -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return 0; -} - -/** reed-solomon module */ -void -mock_pgm_rs_create ( - pgm_rs_t* rs, - uint8_t n, - uint8_t k - ) -{ -} - -void -mock_pgm_rs_destroy ( - pgm_rs_t* rs - ) -{ -} - -void -mock_pgm_rs_decode_parity_appended ( - pgm_rs_t* rs, - pgm_gf8_t** block, - const uint8_t* offsets, - uint16_t len - ) -{ -// null -} - -void -mock_pgm_histogram_init ( - pgm_histogram_t* histogram - ) -{ -} - -void -mock_pgm_histogram_add ( - pgm_histogram_t* histogram, - int value - ) -{ -} - - -/* generate valid skb, data pointer pointing to PGM payload - */ -static -struct pgm_sk_buff_t* -generate_valid_skb (void) -{ - const pgm_tsi_t tsi = { { 200, 202, 203, 204, 205, 206 }, 2000 }; - const guint16 tsdu_length = 1000; - const guint16 header_length = sizeof(struct pgm_header) + sizeof(struct pgm_data); - struct pgm_sk_buff_t* skb = pgm_alloc_skb (1500); - memcpy (&skb->tsi, &tsi, sizeof(tsi)); -/* fake but valid socket and timestamp */ - skb->sock = (pgm_sock_t*)0x1; - skb->tstamp = pgm_time_now; -/* header */ - pgm_skb_reserve (skb, header_length); - memset (skb->head, 0, header_length); - skb->pgm_header = (struct pgm_header*)skb->head; - skb->pgm_data = (struct pgm_data*)(skb->pgm_header + 1); - skb->pgm_header->pgm_type = PGM_ODATA; - skb->pgm_header->pgm_tsdu_length = g_htons (tsdu_length); -/* DATA */ - pgm_skb_put (skb, tsdu_length); - return skb; -} - -/* target: - * pgm_rxw_t* - * pgm_rxw_create ( - * const pgm_tsi_t* tsi, - * const uint16_t tpdu_size, - * const unsigned sqns, - * const unsigned secs, - * const ssize_t max_rte, - * const uint32_t ack_c_p - * ) - */ - -/* vanilla sequence count window */ -START_TEST (test_create_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - fail_if (NULL == pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p), "create failed"); -} -END_TEST - -/* vanilla time based window */ -START_TEST (test_create_pass_002) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - fail_if (NULL == pgm_rxw_create (&tsi, 1500, 0, 60, 800000, ack_c_p), "create failed"); -} -END_TEST - -/* jumbo frame */ -START_TEST (test_create_pass_003) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - fail_if (NULL == pgm_rxw_create (&tsi, 9000, 0, 60, 800000, ack_c_p), "create failed"); -} -END_TEST - -/* max frame */ -START_TEST (test_create_pass_004) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - fail_if (NULL == pgm_rxw_create (&tsi, UINT16_MAX, 0, 60, 800000, ack_c_p), "create failed"); -} -END_TEST - -/* invalid tsi pointer */ -START_TEST (test_create_fail_001) -{ - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (NULL, 1500, 100, 0, 0, ack_c_p); - fail ("reached"); -} -END_TEST - -/* invalid tpdu size */ -START_TEST (test_create_fail_002) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - fail_if (NULL == pgm_rxw_create (&tsi, 0, 100, 0, 0, ack_c_p), "create failed"); -} -END_TEST - -START_TEST (test_create_fail_003) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 0, 0, 60, 800000, ack_c_p); - fail ("reached"); -} -END_TEST - -/* no specified sequence count or time value */ -START_TEST (test_create_fail_004) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 0, 0, 0, 800000, ack_c_p); - fail ("reached"); -} -END_TEST - -/* no specified rate */ -START_TEST (test_create_fail_005) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 0, 0, 60, 0, ack_c_p); - fail ("reached"); -} -END_TEST - -/* all invalid */ -START_TEST (test_create_fail_006) -{ - pgm_rxw_t* window = pgm_rxw_create (NULL, 0, 0, 0, 0, 0); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_rxw_destroy ( - * pgm_rxw_t* const window - * ) - */ - -START_TEST (test_destroy_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_destroy_fail_001) -{ - pgm_rxw_destroy (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * int - * pgm_rxw_add ( - * pgm_rxw_t* const window, - * struct pgm_sk_buff_t* const skb, - * const pgm_time_t now, - * const pgm_time_t nak_rb_expiry - * ) - * failures raise assert errors and stop process execution. - */ - -START_TEST (test_add_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - pgm_rxw_destroy (window); -} -END_TEST - -/* missing + inserted */ -START_TEST (test_add_pass_002) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); -/* #1 */ - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); -/* #2 with jump */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (2); - fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not missing"); -/* #3 to fill in gap */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (1); - fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); - pgm_rxw_destroy (window); -} -END_TEST - -/* duplicate + append */ -START_TEST (test_add_pass_003) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); -/* #1 */ - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); -/* #2 repeat sequence */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - fail_unless (PGM_RXW_DUPLICATE == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not duplicate"); -/* #3 append */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (1); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - pgm_rxw_destroy (window); -} -END_TEST - -/* malformed: tpdu too long */ -START_TEST (test_add_pass_004) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_header->pgm_tsdu_length = g_htons (65535); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_MALFORMED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not malformed"); -} -END_TEST - -/* bounds + append */ -START_TEST (test_add_pass_005) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); -/* #1 */ - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - skb->pgm_data->data_trail = g_htonl (-10); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); -/* #2 jump backwards */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (-1); - skb->pgm_data->data_trail = g_htonl (-10); - fail_unless (PGM_RXW_BOUNDS == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not bounds"); -/* #3 append */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (1); - skb->pgm_data->data_trail = g_htonl (-10); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); -/* #4 jump forward */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (100 + (UINT32_MAX / 2)); - skb->pgm_data->data_trail = g_htonl (UINT32_MAX / 2); - fail_unless (PGM_RXW_BOUNDS == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not bounds"); -/* #5 append */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (2); - skb->pgm_data->data_trail = g_htonl (-10); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - pgm_rxw_destroy (window); -} -END_TEST - -/* null skb */ -START_TEST (test_add_fail_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - int retval = pgm_rxw_add (window, NULL, now, nak_rb_expiry); - fail ("reached"); -} -END_TEST - -/* null window */ -START_TEST (test_add_fail_002) -{ - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - int retval = pgm_rxw_add (NULL, skb, now, nak_rb_expiry); - fail ("reached"); -} -END_TEST - -/* null skb content */ -START_TEST (test_add_fail_003) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - char buffer[1500]; - memset (buffer, 0, sizeof(buffer)); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - int retval = pgm_rxw_add (window, (struct pgm_sk_buff_t*)buffer, now, nak_rb_expiry); - fail ("reached"); -} -END_TEST - -/* 0 nak_rb_expiry */ -START_TEST (test_add_fail_004) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - int retval = pgm_rxw_add (window, skb, now, 0); - fail ("reached"); -} -END_TEST - -/* target: - * struct pgm_sk_buff_t* - * pgm_rxw_peek ( - * pgm_rxw_t* const window, - * const uint32_t sequence - * ) - */ - -START_TEST (test_peek_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - fail_unless (NULL == pgm_rxw_peek (window, 0)); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (skb == pgm_rxw_peek (window, 0), "peek failed"); - fail_unless (NULL == pgm_rxw_peek (window, 1), "peek failed"); - fail_unless (NULL == pgm_rxw_peek (window, -1), "peek failed"); - pgm_rxw_destroy (window); -} -END_TEST - -/* null window */ -START_TEST (test_peek_fail_001) -{ - struct pgm_sk_buff_t* skb = pgm_rxw_peek (NULL, 0); - fail ("reached"); -} -END_TEST - -/** inline function tests **/ -/* pgm_rxw_max_length () - */ -START_TEST (test_max_length_pass_001) -{ - const guint window_length = 100; - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, window_length, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - fail_unless (window_length == pgm_rxw_max_length (window), "max_length failed"); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_max_length_fail_001) -{ - const unsigned len = pgm_rxw_max_length (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_rxw_length () - */ -START_TEST (test_length_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - fail_unless (0 == pgm_rxw_length (window), "length failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (1 == pgm_rxw_length (window), "length failed"); -/* #2 */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (1); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (2 == pgm_rxw_length (window), "length failed"); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_length_fail_001) -{ - const uint32_t answer = pgm_rxw_length (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_rxw_size () - */ -START_TEST (test_size_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - fail_unless (0 == pgm_rxw_size (window), "size failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (1000 == pgm_rxw_size (window), "size failed"); -/* #2 */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (1); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (2000 == pgm_rxw_size (window), "size failed"); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_size_fail_001) -{ - const size_t answer = pgm_rxw_size (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_rxw_is_empty - */ -START_TEST (test_is_empty_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - fail_unless (pgm_rxw_is_empty (window), "is_empty failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_if (pgm_rxw_is_empty (window), "is_empty failed"); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_is_empty_fail_001) -{ - const bool answer = pgm_rxw_is_empty (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_rxw_is_full - */ -START_TEST (test_is_full_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 1, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - fail_if (pgm_rxw_is_full (window), "is_full failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (pgm_rxw_is_full (window), "is_full failed"); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_is_full_fail_001) -{ - const bool answer = pgm_rxw_is_full (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_rxw_lead - */ -START_TEST (test_lead_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - guint32 lead = pgm_rxw_lead (window); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (lead + 1 == pgm_rxw_lead (window), "lead failed"); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_lead_fail_001) -{ - const uint32_t answer = pgm_rxw_lead (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_rxw_next_lead - */ -START_TEST (test_next_lead_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - guint32 next_lead = pgm_rxw_next_lead (window); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (next_lead == pgm_rxw_lead (window), "lead failed"); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_next_lead_fail_001) -{ - const uint32_t answer = pgm_rxw_next_lead (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * ssize_t - * pgm_rxw_readv ( - * pgm_rxw_t* const window, - * struct pgm_msgv_t** pmsg, - * const unsigned msg_len - * ) - */ - -START_TEST (test_readv_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_msgv_t msgv[2], *pmsg; -/* #1 empty */ - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); -/* #2 single TPDU-APDU */ - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - pmsg = msgv; - fail_unless (1000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); -/* #3,4 two APDUs */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (1); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (2); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - pmsg = msgv; - fail_unless (2000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); -/* #5,6 skip and repair APDU */ - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (4); - fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not missing"); - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (3); - fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); - pmsg = msgv; - fail_unless (2000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - pgm_rxw_destroy (window); -} -END_TEST - -/* zero-length */ -START_TEST (test_readv_pass_002) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_msgv_t msgv[2], *pmsg; - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - pgm_rxw_destroy (window); -} -END_TEST - -/* full window */ -START_TEST (test_readv_pass_003) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_msgv_t msgv[1], *pmsg; - struct pgm_sk_buff_t* skb; - for (unsigned i = 0; i < 100; i++) - { - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless ((1 + i) == pgm_rxw_length (window), "length failed"); - } - fail_unless (pgm_rxw_is_full (window), "is_full failed"); - fail_unless (_pgm_rxw_commit_is_empty (window), "commit_is_empty failed"); - for (unsigned i = 0; i < 100; i++) - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - fail_unless ((1 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); - } - fail_unless (pgm_rxw_length (window) == _pgm_rxw_commit_length (window), "commit_length failed"); - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - pgm_rxw_destroy (window); -} -END_TEST - -/* full + 1 window */ -START_TEST (test_readv_pass_004) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_msgv_t msgv[1], *pmsg; - struct pgm_sk_buff_t* skb; - for (unsigned i = 0; i < 101; i++) - { - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (MIN(100, 1 + i) == pgm_rxw_length (window), "length failed"); - } - fail_unless (pgm_rxw_is_full (window), "is_full failed"); - fail_unless (_pgm_rxw_commit_is_empty (window), "commit_is_empty failed"); - for (unsigned i = 0; i < 100; i++) - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - fail_unless ((1 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); - } - fail_unless (pgm_rxw_length (window) == _pgm_rxw_commit_length (window), "commit_length failed"); - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - pgm_rxw_destroy (window); -} -END_TEST - -/* full - 2 lost last in window */ -START_TEST (test_readv_pass_005) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_msgv_t msgv[1], *pmsg; - struct pgm_sk_buff_t* skb; - for (unsigned i = 0; i < 98; i++) - { - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless ((1 + i) == pgm_rxw_length (window), "length failed"); - } - fail_if (pgm_rxw_is_full (window), "is_full failed"); - fail_unless (_pgm_rxw_commit_is_empty (window), "commit_is_empty failed"); - { - unsigned i = 99; - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not missing"); - fail_unless ((1 + i) == pgm_rxw_length (window), "length failed"); - } - fail_unless (pgm_rxw_is_full (window)); - fail_unless (_pgm_rxw_commit_is_empty (window)); - for (unsigned i = 0; i < 98; i++) - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - fail_unless ((1 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); - } - fail_unless (pgm_rxw_length (window) == (2 + _pgm_rxw_commit_length (window)), "commit_length failed"); -/* read end-of-window */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - } - pgm_rxw_destroy (window); -} -END_TEST - -/* add full window, readv 1 skb, add 1 more */ -START_TEST (test_readv_pass_006) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_msgv_t msgv[1], *pmsg; - struct pgm_sk_buff_t* skb; - for (unsigned i = 0; i < 100; i++) - { - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (MIN(100, 1 + i) == pgm_rxw_length (window), "length failed"); - } - fail_unless (pgm_rxw_is_full (window)); - fail_unless (_pgm_rxw_commit_is_empty (window)); -/* read one skb */ - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - fail_unless (1 == _pgm_rxw_commit_length (window), "commit_length failed"); - } -/* add one more new skb */ - { - unsigned i = 100; - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_BOUNDS == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not bounds"); - fail_unless (MIN(100, 1 + i) == pgm_rxw_length (window), "length failed"); - } -/* read off 99 more skbs */ - for (unsigned i = 0; i < 99; i++) - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - fail_unless ((2 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); - } -/* read end-of-window */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - } - pgm_rxw_destroy (window); -} -END_TEST - -/* NULL window */ -START_TEST (test_readv_fail_001) -{ - struct pgm_msgv_t msgv[1], *pmsg = msgv; - gssize len = pgm_rxw_readv (NULL, &pmsg, G_N_ELEMENTS(msgv)); - fail ("reached"); -} -END_TEST - -/* NULL pmsg */ -START_TEST (test_readv_fail_002) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - struct pgm_msgv_t msgv[1], *pmsg = msgv; - gssize len = pgm_rxw_readv (window, NULL, G_N_ELEMENTS(msgv)); - fail ("reached"); -} -END_TEST - -/* 0 msg-len */ -START_TEST (test_readv_fail_003) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - struct pgm_msgv_t msgv[1], *pmsg = msgv; - gssize len = pgm_rxw_readv (window, &pmsg, 0); - fail ("reached"); -} -END_TEST - -/* target: - * - * void - * pgm_rxw_remove_commit ( - * pgm_rxw_t* const window - * ) - */ - -/* full - 2 lost last in window */ -START_TEST (test_remove_commit_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_msgv_t msgv[1], *pmsg; - struct pgm_sk_buff_t* skb; - for (unsigned i = 0; i < 98; i++) - { - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless ((1 + i) == pgm_rxw_length (window), "length failed"); - } - fail_if (pgm_rxw_is_full (window)); - fail_unless (_pgm_rxw_commit_is_empty (window)); -/* #98 is missing */ - { - unsigned i = 99; - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless ((1 + i) == pgm_rxw_length (window), "length failed"); - } - fail_unless (pgm_rxw_is_full (window), "is_full failed"); - fail_unless (_pgm_rxw_commit_is_empty (window), "commit_is_empty"); -/* now mark #98 lost */ - pgm_rxw_lost (window, 98); - for (unsigned i = 0; i < 98; i++) - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - fail_unless ((1 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); - } - fail_unless (100 == pgm_rxw_length (window), "length failed"); - fail_unless ( 98 == _pgm_rxw_commit_length (window), "commit_length failed"); -/* read end-of-window */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - } - fail_unless (100 == pgm_rxw_length (window), "length failed"); - fail_unless ( 98 == _pgm_rxw_commit_length (window), "commit_length failed"); - pgm_rxw_remove_commit (window); -/* read lost skb #98 */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - } - pgm_rxw_remove_commit (window); -/* read valid skb #99 */ - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - } -/* read end-of-window */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - } - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_remove_commit_fail_001) -{ - pgm_rxw_remove_commit (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * unsigned - * pgm_rxw_remove_trail ( - * pgm_rxw_t* const window - * ) - */ - -START_TEST (test_remove_trail_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_msgv_t msgv[2], *pmsg; - fail_unless (0 == pgm_rxw_remove_trail (window), "remove_trail failed"); -/* #1,2 two APDUs */ - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (1); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry)); - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (2); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry)); - fail_unless (1 == pgm_rxw_remove_trail (window), "remove_trail failed"); - fail_unless (1 == pgm_rxw_length (window), "length failed"); - fail_unless (1000 == pgm_rxw_size (window), "size failed"); - pmsg = msgv; - fail_unless (1000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - fail_unless (0 == pgm_rxw_remove_trail (window), "remove_trail failed"); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_remove_trail_fail_001) -{ - guint count = pgm_rxw_remove_trail (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * unsigned - * pgm_rxw_update ( - * pgm_rxw_t* const window, - * const uint32_t txw_trail, - * const uint32_t txw_lead, - * const pgm_time_t now, - * const pgm_time_t nak_rb_expiry - * ) - */ - -START_TEST (test_update_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (0 == pgm_rxw_update (window, 100, 99, now, nak_rb_expiry), "update failed"); -/* dupe */ - fail_unless (0 == pgm_rxw_update (window, 100, 99, now, nak_rb_expiry), "update failed"); -/* #1 at 100 */ - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (100); - fail_unless (PGM_RXW_BOUNDS == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not bounds"); -/* #2 at 101 */ - skb->pgm_data->data_sqn = g_htonl (101); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - struct pgm_msgv_t msgv[1], *pmsg = msgv; - fail_unless (1000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); -/* #3 at 102 */ - fail_unless (1 == pgm_rxw_update (window, 102, 99, now, nak_rb_expiry), "update failed"); - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (102); - fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_update_fail_001) -{ - guint count = pgm_rxw_update (NULL, 0, 0, 0, 0); - fail ("reached"); -} -END_TEST - -/* target: - * int - * pgm_rxw_confirm ( - * pgm_rxw_t* const window, - * const uint32_t sequence, - * const pgm_time_t now, - * const pgm_time_t nak_rdata_expiry, - * const pgm_time_t nak_rb_expiry - * ) - */ - -START_TEST (test_confirm_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - const pgm_time_t now = 1; - const pgm_time_t nak_rdata_expiry = 2; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_BOUNDS == pgm_rxw_confirm (window, 0, now, nak_rdata_expiry, nak_rb_expiry), "confirm not bounds"); -/* #1 at 100 */ - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (100); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (1 == pgm_rxw_length (window), "length failed"); - fail_unless (PGM_RXW_BOUNDS == pgm_rxw_confirm (window, 99, now, nak_rdata_expiry, nak_rb_expiry), "confirm not bounds"); - fail_unless (PGM_RXW_DUPLICATE == pgm_rxw_confirm (window, 100, now, nak_rdata_expiry, nak_rb_expiry), "confirm not duplicate"); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_confirm (window, 101, now, nak_rdata_expiry, nak_rb_expiry), "confirm not appended"); - fail_unless (2 == pgm_rxw_length (window)); - fail_unless (PGM_RXW_UPDATED == pgm_rxw_confirm (window, 101, now, nak_rdata_expiry, nak_rb_expiry), "confirm not updated"); -/* #2 at 101 */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (101); - fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); - struct pgm_msgv_t msgv[2], *pmsg = msgv; - fail_unless (2000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - pgm_rxw_destroy (window); -} -END_TEST - -/* constrained confirm */ -START_TEST (test_confirm_pass_002) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_msgv_t msgv[1], *pmsg; - struct pgm_sk_buff_t* skb; - for (unsigned i = 0; i < 100; i++) - { - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (MIN(100, 1 + i) == pgm_rxw_length (window), "length failed"); - } - fail_unless (pgm_rxw_is_full (window), "is_full failed"); - fail_unless (_pgm_rxw_commit_is_empty (window), "is_empty failed"); -/* read one skb */ - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - fail_unless (1 == _pgm_rxw_commit_length (window), "commit_length failed"); - } -/* confirm next sequence */ - const pgm_time_t now = 1; - const pgm_time_t nak_rdata_expiry = 2; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_BOUNDS == pgm_rxw_confirm (window, 100, now, nak_rdata_expiry, nak_rb_expiry), "confirm not bounds"); -/* read off 99 more skbs */ - for (unsigned i = 0; i < 99; i++) - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - fail_unless ((2 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); - } -/* read end-of-window */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - } - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_confirm_fail_001) -{ - int retval = pgm_rxw_confirm (NULL, 0, 0, 0, 0); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_rxw_lost ( - * pgm_rxw_t* const window, - * const uint32_t sequence - * ) - */ - -START_TEST (test_lost_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - const pgm_time_t now = 1; - const pgm_time_t nak_rdata_expiry = 2; - const pgm_time_t nak_rb_expiry = 2; -/* #1 at 100 */ - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (100); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); - fail_unless (1 == pgm_rxw_length (window), "length failed"); - fail_unless (1000 == pgm_rxw_size (window), "size failed"); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_confirm (window, 101, now, nak_rdata_expiry, nak_rb_expiry), "confirm not appended"); - fail_unless (2 == pgm_rxw_length (window), "length failed"); - fail_unless (1000 == pgm_rxw_size (window), "size failed"); - pgm_rxw_lost (window, 101); - fail_unless (2 == pgm_rxw_length (window), "length failed"); - fail_unless (1000 == pgm_rxw_size (window), "size failed"); -/* #2 at 101 */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (101); - fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); - fail_unless (2 == pgm_rxw_length (window), "length failed"); - fail_unless (2000 == pgm_rxw_size (window), "size failed"); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_lost_fail_001) -{ - pgm_rxw_lost (NULL, 0); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_rxw_state ( - * pgm_rxw_t* const window, - * struct pgm_sk_buff_t* skb, - * int new_state - * ) - */ - -START_TEST (test_state_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - const pgm_time_t now = 1; - const pgm_time_t nak_rdata_expiry = 2; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (0 == pgm_rxw_update (window, 100, 99, now, nak_rb_expiry), "update failed"); - fail_unless (PGM_RXW_APPENDED == pgm_rxw_confirm (window, 101, now, nak_rdata_expiry, nak_rb_expiry), "confirm not appended"); - struct pgm_sk_buff_t* skb = pgm_rxw_peek (window, 101); - pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_NCF); - pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_DATA); - pgm_rxw_destroy (window); -} -END_TEST - -START_TEST (test_state_fail_001) -{ - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - pgm_rxw_state (NULL, skb, PGM_PKT_STATE_BACK_OFF); - fail ("reached"); -} -END_TEST - -START_TEST (test_state_fail_002) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - pgm_rxw_state (window, NULL, PGM_PKT_STATE_BACK_OFF); - fail ("reached"); -} -END_TEST - -START_TEST (test_state_fail_003) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - pgm_rxw_state (window, skb, -1); - fail ("reached"); -} -END_TEST - -/* pgm_peer_has_pending - */ - -START_TEST (test_has_pending_pass_001) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window, "create failed"); -/* empty */ - fail_unless (0 == window->has_event, "unexpected event"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (0); - const pgm_time_t now = 1; - const pgm_time_t nak_rdata_expiry = 2; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); -/* 1 sequence */ - fail_unless (1 == window->has_event, "no event"); - window->has_event = 0; -/* jump */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (2); - fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not missing"); - fail_unless (0 == window->has_event, "unexpected event"); -/* loss */ - pgm_rxw_lost (window, 1); - fail_unless (1 == window->has_event, "no event"); - window->has_event = 0; -/* insert */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - skb->pgm_data->data_sqn = g_htonl (1); - fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); - fail_unless (1 == window->has_event, "no event"); - window->has_event = 0; -/* confirm */ - fail_unless (PGM_RXW_APPENDED == pgm_rxw_confirm (window, 3, now, nak_rdata_expiry, nak_rb_expiry), "confirm not appended"); - fail_unless (0 == window->has_event, "unexpected event"); -/* partial read */ - struct pgm_msgv_t msgv[2], *pmsg = msgv; - fail_unless (2000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - fail_unless (0 == window->has_event, "unexpected event"); -/* finish read */ - pmsg = msgv; - fail_unless (1000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); - fail_unless (0 == window->has_event, "unexpected event"); - pgm_rxw_destroy (window); -} -END_TEST - -static -Suite* -make_basic_test_suite (void) -{ - Suite* s; - - s = suite_create ("basic receive window API"); - - TCase* tc_create = tcase_create ("create"); - suite_add_tcase (s, tc_create); - tcase_add_test (tc_create, test_create_pass_001); - tcase_add_test (tc_create, test_create_pass_002); - tcase_add_test (tc_create, test_create_pass_003); - tcase_add_test (tc_create, test_create_pass_004); - tcase_add_test_raise_signal (tc_create, test_create_fail_001, SIGABRT); - tcase_add_test_raise_signal (tc_create, test_create_fail_002, SIGABRT); - tcase_add_test_raise_signal (tc_create, test_create_fail_003, SIGABRT); - tcase_add_test_raise_signal (tc_create, test_create_fail_004, SIGABRT); - - TCase* tc_destroy = tcase_create ("destroy"); - suite_add_tcase (s, tc_destroy); - tcase_add_test (tc_destroy, test_destroy_pass_001); - tcase_add_test_raise_signal (tc_destroy, test_destroy_fail_001, SIGABRT); - - TCase* tc_add = tcase_create ("add"); - suite_add_tcase (s, tc_add); - tcase_add_test (tc_add, test_add_pass_001); - tcase_add_test (tc_add, test_add_pass_002); - tcase_add_test (tc_add, test_add_pass_003); - tcase_add_test (tc_add, test_add_pass_004); - tcase_add_test (tc_add, test_add_pass_005); - tcase_add_test_raise_signal (tc_add, test_add_fail_001, SIGABRT); - tcase_add_test_raise_signal (tc_add, test_add_fail_002, SIGABRT); - tcase_add_test_raise_signal (tc_add, test_add_fail_003, SIGABRT); - - TCase* tc_peek = tcase_create ("peek"); - suite_add_tcase (s, tc_peek); - tcase_add_test (tc_peek, test_peek_pass_001); - tcase_add_test_raise_signal (tc_peek, test_peek_fail_001, SIGABRT); - - TCase* tc_max_length = tcase_create ("max-length"); - suite_add_tcase (s, tc_max_length); - tcase_add_test (tc_max_length, test_max_length_pass_001); - tcase_add_test_raise_signal (tc_max_length, test_max_length_fail_001, SIGABRT); - - TCase* tc_length = tcase_create ("length"); - suite_add_tcase (s, tc_length); - tcase_add_test (tc_length, test_length_pass_001); - tcase_add_test_raise_signal (tc_length, test_length_fail_001, SIGABRT); - - TCase* tc_size = tcase_create ("size"); - suite_add_tcase (s, tc_size); - tcase_add_test (tc_size, test_size_pass_001); - tcase_add_test_raise_signal (tc_size, test_size_fail_001, SIGABRT); - - TCase* tc_is_empty = tcase_create ("is-empty"); - suite_add_tcase (s, tc_is_empty); - tcase_add_test (tc_is_empty, test_is_empty_pass_001); - tcase_add_test_raise_signal (tc_is_empty, test_is_empty_fail_001, SIGABRT); - - TCase* tc_is_full = tcase_create ("is-full"); - suite_add_tcase (s, tc_is_full); - tcase_add_test (tc_is_full, test_is_full_pass_001); - tcase_add_test_raise_signal (tc_is_full, test_is_full_fail_001, SIGABRT); - - TCase* tc_lead = tcase_create ("lead"); - suite_add_tcase (s, tc_lead); - tcase_add_test (tc_lead, test_lead_pass_001); - tcase_add_test_raise_signal (tc_lead, test_lead_fail_001, SIGABRT); - - TCase* tc_next_lead = tcase_create ("next-lead"); - suite_add_tcase (s, tc_next_lead); - tcase_add_test (tc_next_lead, test_next_lead_pass_001); - tcase_add_test_raise_signal (tc_next_lead, test_next_lead_fail_001, SIGABRT); - - TCase* tc_readv = tcase_create ("readv"); - suite_add_tcase (s, tc_readv); - tcase_add_test (tc_readv, test_readv_pass_001); - tcase_add_test (tc_readv, test_readv_pass_002); - tcase_add_test (tc_readv, test_readv_pass_003); - tcase_add_test (tc_readv, test_readv_pass_004); - tcase_add_test (tc_readv, test_readv_pass_005); - tcase_add_test (tc_readv, test_readv_pass_006); - tcase_add_test_raise_signal (tc_readv, test_readv_fail_001, SIGABRT); - tcase_add_test_raise_signal (tc_readv, test_readv_fail_002, SIGABRT); - tcase_add_test_raise_signal (tc_readv, test_readv_fail_003, SIGABRT); - - TCase* tc_remove_commit = tcase_create ("remove-commit"); - suite_add_tcase (s, tc_remove_commit); - tcase_add_test (tc_remove_commit, test_remove_commit_pass_001); - tcase_add_test_raise_signal (tc_remove_commit, test_remove_commit_fail_001, SIGABRT); - - TCase* tc_remove_trail = tcase_create ("remove-trail"); - TCase* tc_update = tcase_create ("update"); - suite_add_tcase (s, tc_update); - tcase_add_test (tc_update, test_update_pass_001); - tcase_add_test_raise_signal (tc_update, test_update_fail_001, SIGABRT); - - TCase* tc_confirm = tcase_create ("confirm"); - suite_add_tcase (s, tc_confirm); - tcase_add_test (tc_confirm, test_confirm_pass_001); - tcase_add_test (tc_confirm, test_confirm_pass_002); - tcase_add_test_raise_signal (tc_confirm, test_confirm_fail_001, SIGABRT); - - TCase* tc_lost = tcase_create ("lost"); - suite_add_tcase (s, tc_lost); - tcase_add_test (tc_lost, test_lost_pass_001); - tcase_add_test_raise_signal (tc_lost, test_lost_fail_001, SIGABRT); - - TCase* tc_state = tcase_create ("state"); - suite_add_tcase (s, tc_state); - tcase_add_test (tc_state, test_state_pass_001); - tcase_add_test_raise_signal (tc_state, test_state_fail_001, SIGABRT); - - return s; -} - -/* read through lost packet */ -START_TEST (test_readv_pass_007) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window); - struct pgm_msgv_t msgv[1], *pmsg; - struct pgm_sk_buff_t* skb; -/* add #0 */ - { - unsigned i = 0; - skb = generate_valid_skb (); - fail_if (NULL == skb); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry)); - fail_unless ((1 + i) == pgm_rxw_length (window)); - } -/* add # 2 */ - { - unsigned i = 2; - skb = generate_valid_skb (); - fail_if (NULL == skb); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry)); - fail_unless ((1 + i) == pgm_rxw_length (window)); - } -/* lose #1 */ - { - pgm_rxw_lost (window, 1); - } - fail_unless (_pgm_rxw_commit_is_empty (window)); -/* read #0 */ - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - } -/* end-of-window */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - } - pgm_rxw_remove_commit (window); -/* read lost skb #1 */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - } - pgm_rxw_remove_commit (window); -/* read #2 */ - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - } -/* end-of-window */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - } - pgm_rxw_destroy (window); -} -END_TEST - -/* read through loss extended window */ -START_TEST (test_readv_pass_008) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window); - struct pgm_msgv_t msgv[1], *pmsg; - struct pgm_sk_buff_t* skb; -/* add #0 */ - { - unsigned i = 0; - skb = generate_valid_skb (); - fail_if (NULL == skb); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry)); - fail_unless ((1 + i) == pgm_rxw_length (window)); - } - fail_unless (_pgm_rxw_commit_is_empty (window)); -/* read #0 */ - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - } - pgm_rxw_remove_commit (window); -/* end-of-window */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - } -/* add #100 */ - { - unsigned i = 100; - skb = generate_valid_skb (); - fail_if (NULL == skb); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry)); - } -/* lose #1-99 */ - { - for (unsigned i = 1; i < 100; i++) - pgm_rxw_lost (window, i); - } -/* read #100 */ - { - int i = 0; - int bytes_read; - pmsg = msgv; - do { - bytes_read = pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)); - pgm_rxw_remove_commit (window); - i++; - if (i > 100) break; - } while (-1 == bytes_read); - fail_unless (100 == i); - } -/* end-of-window */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - } - pgm_rxw_destroy (window); -} -END_TEST - -/* read through long data-loss */ -START_TEST (test_readv_pass_009) -{ - pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const uint32_t ack_c_p = 500; - pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); - fail_if (NULL == window); - struct pgm_msgv_t msgv[1], *pmsg; - struct pgm_sk_buff_t* skb; -/* add #0 */ - { - unsigned i = 0; - skb = generate_valid_skb (); - fail_if (NULL == skb); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry)); - fail_unless ((1 + i) == pgm_rxw_length (window)); - } - fail_unless (_pgm_rxw_commit_is_empty (window)); -/* read #0 */ - { - pmsg = msgv; - fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - } - pgm_rxw_remove_commit (window); -/* end-of-window */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - } -/* add #2000 */ - { - unsigned i = 2000; - skb = generate_valid_skb (); - fail_if (NULL == skb); - skb->pgm_header->pgm_tsdu_length = g_htons (0); - skb->tail = (guint8*)skb->tail - skb->len; - skb->len = 0; - skb->pgm_data->data_sqn = g_htonl (i); - const pgm_time_t now = 1; - const pgm_time_t nak_rb_expiry = 2; - fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry)); - } -/* lose #1-1999 */ - { - for (unsigned i = 1901; i < 2000; i++) - pgm_rxw_lost (window, i); - } -/* read #2000 */ - { - int i = 0; - int bytes_read; - pmsg = msgv; - do { - bytes_read = pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)); - pgm_rxw_remove_commit (window); - i++; - if (i > 100) break; - } while (-1 == bytes_read); - fail_unless (100 == i); - } -/* end-of-window */ - { - pmsg = msgv; - fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); - } - pgm_rxw_destroy (window); -} -END_TEST - -/* a.k.a. unreliable delivery - */ - -static -Suite* -make_best_effort_test_suite (void) -{ - Suite* s; - - s = suite_create ("Best effort delivery"); - - TCase* tc_readv = tcase_create ("readv"); - suite_add_tcase (s, tc_readv); - tcase_add_test (tc_readv, test_readv_pass_007); - tcase_add_test (tc_readv, test_readv_pass_008); - tcase_add_test (tc_readv, test_readv_pass_009); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_basic_test_suite ()); - srunner_add_suite (sr, make_best_effort_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/signal.c b/3rdparty/openpgm-svn-r1085/pgm/signal.c deleted file mode 100644 index 1279a8f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/signal.c +++ /dev/null @@ -1,176 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Re-entrant safe signal handling. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define _GNU_SOURCE -#include -#include /* _GNU_SOURCE for strsignal() */ -#include -#ifndef G_OS_WIN32 -# include -#else -# include -#endif -#include -#include "pgm/signal.h" - - -//#define SIGNAL_DEBUG - - -/* globals */ - -static pgm_sighandler_t signal_list[NSIG]; -static int signal_pipe[2]; -static GIOChannel* signal_io = NULL; - -static void on_signal (int); -static gboolean on_io_signal (GIOChannel*, GIOCondition, gpointer); -static const char* cond_string (GIOCondition); - - -static -void -set_nonblock ( - const int s, - const gboolean v - ) -{ -#ifndef G_OS_WIN32 - int flags = fcntl (s, F_GETFL); - if (!v) flags &= ~O_NONBLOCK; - else flags |= O_NONBLOCK; - fcntl (s, F_SETFL, flags); -#else - u_long mode = v; - ioctlsocket (s, FIONBIO, &mode); -#endif -} - -/* install signal handler and return unix fd to add to event loop - */ - -gboolean -pgm_signal_install ( - int signum, - pgm_sighandler_t handler, - gpointer user_data - ) -{ - g_debug ("pgm_signal_install (signum:%d handler:%p user_data:%p)", - signum, (const void*)handler, user_data); - - if (NULL == signal_io) - { -#ifdef G_OS_UNIX - if (pipe (signal_pipe)) -#else - if (_pipe (signal_pipe, 4096, _O_BINARY | _O_NOINHERIT)) -#endif - return FALSE; - - set_nonblock (signal_pipe[0], TRUE); - set_nonblock (signal_pipe[1], TRUE); -/* add to evm */ - signal_io = g_io_channel_unix_new (signal_pipe[0]); - g_io_add_watch (signal_io, G_IO_IN, on_io_signal, user_data); - } - - signal_list[signum] = handler; - return (SIG_ERR != signal (signum, on_signal)); -} - -/* process signal from operating system - */ - -static -void -on_signal ( - int signum - ) -{ - g_debug ("on_signal (signum:%d)", signum); - if (write (signal_pipe[1], &signum, sizeof(signum)) != sizeof(signum)) - { -#ifndef G_OS_WIN32 - g_warning ("Unix signal %s (%d) lost", strsignal (signum), signum); -#else - g_warning ("Unix signal (%d) lost", signum); -#endif - } -} - -/* process signal from pipe - */ - -static -gboolean -on_io_signal ( - GIOChannel* source, - GIOCondition cond, - gpointer user_data - ) -{ -/* pre-conditions */ - g_assert (NULL != source); - g_assert (G_IO_IN == cond); - - g_debug ("on_io_signal (source:%p cond:%s user_data:%p)", - (gpointer)source, cond_string (cond), user_data); - - int signum; - const gsize bytes_read = read (g_io_channel_unix_get_fd (source), &signum, sizeof(signum)); - - if (sizeof(signum) == bytes_read) - { - signal_list[signum] (signum, user_data); - } - else - { - g_warning ("Lost data in signal pipe, read %" G_GSIZE_FORMAT " byte%s expected %" G_GSIZE_FORMAT ".", - bytes_read, bytes_read > 1 ? "s" : "", sizeof(signum)); - } - - return TRUE; -} - -static -const char* -cond_string ( - GIOCondition cond - ) -{ - const char* c; - - switch (cond) { - case G_IO_IN: c = "G_IO_IN"; break; - case G_IO_OUT: c = "G_IO_OUT"; break; - case G_IO_PRI: c = "G_IO_PRI"; break; - case G_IO_ERR: c = "G_IO_ERR"; break; - case G_IO_HUP: c = "G_IO_HUP"; break; - case G_IO_NVAL: c = "G_IO_NVAL"; break; - default: c = "(unknown)"; break; - } - - return c; -} - - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/signal_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/signal_unittest.c deleted file mode 100644 index 4784053..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/signal_unittest.c +++ /dev/null @@ -1,115 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for re-entrant safe signal handling. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include - - -/* mock state */ - -static -void -on_sigusr1 ( - int signum, - gpointer user_data - ) -{ - g_assert (SIGUSR1 == signum); - g_assert (NULL != user_data); - GMainLoop* loop = (GMainLoop*)user_data; - g_debug ("on_sigusr1 (signum:%d)", signum); - g_main_loop_quit (loop); -} - -/* mock functions for external references */ - -#define SIGNAL_DEBUG -#include "signal.c" - - -/* target: - * pgm_sighandler_t - * pgm_signal_install ( - * int signum, - pgm_sighandler_t handler - * ) - */ - -static -gboolean -on_startup ( - gpointer data - ) -{ - g_assert (NULL != data); - const int signum = *(const int*)data; - fail_unless (0 == raise (signum)); - return FALSE; -} - -START_TEST (test_install_pass_001) -{ - const int signum = SIGUSR1; - GMainLoop* loop = g_main_loop_new (NULL, FALSE); - fail_unless (TRUE == pgm_signal_install (signum, on_sigusr1, loop)); - g_timeout_add (0, (GSourceFunc)on_startup, &signum); - g_main_loop_run (loop); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_install = tcase_create ("install"); - suite_add_tcase (s, tc_install); - tcase_add_test (tc_install, test_install_pass_001); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/skbuff.c b/3rdparty/openpgm-svn-r1085/pgm/skbuff.c deleted file mode 100644 index 5db6ffc..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/skbuff.c +++ /dev/null @@ -1,115 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM socket buffers - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include "pgm/skbuff.h" - - -void -pgm_skb_over_panic ( - const struct pgm_sk_buff_t*const skb, - const uint16_t len - ) -{ - pgm_fatal ("skput:over: %u put:%u", - skb->len, len); - pgm_assert_not_reached(); -} - -void -pgm_skb_under_panic ( - const struct pgm_sk_buff_t*const skb, - const uint16_t len - ) -{ - pgm_fatal ("skput:under: %u put:%u", - skb->len, len); - pgm_assert_not_reached(); -} - -#ifndef SKB_DEBUG -bool -pgm_skb_is_valid ( - PGM_GNUC_UNUSED const struct pgm_sk_buff_t*const skb - ) -{ - return TRUE; -} -#else -bool -pgm_skb_is_valid ( - const struct pgm_sk_buff_t*const skb - ) -{ - pgm_return_val_if_fail (skb, FALSE); -/* link_ */ -/* socket */ - pgm_return_val_if_fail (skb->sock, FALSE); -/* tstamp */ - pgm_return_val_if_fail (skb->tstamp > 0, FALSE); -/* tsi */ -/* sequence can be any value */ -/* cb can be any value */ -/* len can be any value */ -/* zero_padded can be any value */ -/* gpointers */ - pgm_return_val_if_fail (skb->head, FALSE); - pgm_return_val_if_fail ((const char*)skb->head > (const char*)&skb->users, FALSE); - pgm_return_val_if_fail (skb->data, FALSE); - pgm_return_val_if_fail ((const char*)skb->data >= (const char*)skb->head, FALSE); - pgm_return_val_if_fail (skb->tail, FALSE); - pgm_return_val_if_fail ((const char*)skb->tail >= (const char*)skb->data, FALSE); - pgm_return_val_if_fail (skb->len == (char*)skb->tail - (const char*)skb->data, FALSE); - pgm_return_val_if_fail (skb->end, FALSE); - pgm_return_val_if_fail ((const char*)skb->end >= (const char*)skb->tail, FALSE); -/* pgm_header */ - if (skb->pgm_header) { - pgm_return_val_if_fail ((const char*)skb->pgm_header >= (const char*)skb->head, FALSE); - pgm_return_val_if_fail ((const char*)skb->pgm_header + sizeof(struct pgm_header) <= (const char*)skb->tail, FALSE); - pgm_return_val_if_fail (skb->pgm_data, FALSE); - pgm_return_val_if_fail ((const char*)skb->pgm_data >= (const char*)skb->pgm_header + sizeof(struct pgm_header), FALSE); - pgm_return_val_if_fail ((const char*)skb->pgm_data <= (const char*)skb->tail, FALSE); - if (skb->pgm_opt_fragment) { - pgm_return_val_if_fail ((const char*)skb->pgm_opt_fragment > (const char*)skb->pgm_data, FALSE); - pgm_return_val_if_fail ((const char*)skb->pgm_opt_fragment + sizeof(struct pgm_opt_fragment) < (const char*)skb->tail, FALSE); -/* of_apdu_first_sqn can be any value */ -/* of_frag_offset */ - pgm_return_val_if_fail (ntohl (skb->of_frag_offset) < ntohl (skb->of_apdu_len), FALSE); -/* of_apdu_len can be any value */ - } - pgm_return_val_if_fail (PGM_ODATA == skb->pgm_header->pgm_type || PGM_RDATA == skb->pgm_header->pgm_type, FALSE); -/* FEC broken */ - pgm_return_val_if_fail (0 == (skb->pgm_header->pgm_options & PGM_OPT_PARITY), FALSE); - pgm_return_val_if_fail (0 == (skb->pgm_header->pgm_options & PGM_OPT_VAR_PKTLEN), FALSE); - } else { - pgm_return_val_if_fail (NULL == skb->pgm_data, FALSE); - pgm_return_val_if_fail (NULL == skb->pgm_opt_fragment, FALSE); - } -/* truesize */ - pgm_return_val_if_fail (skb->truesize >= sizeof(struct pgm_sk_buff_t*) + skb->len, FALSE); - pgm_return_val_if_fail (skb->truesize == ((const char*)skb->end - (const char*)skb), FALSE); -/* users */ - pgm_return_val_if_fail (pgm_atomic_read32 (&skb->users) > 0, FALSE); - return TRUE; -} -#endif /* SKB_DEBUG */ - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/slist.c b/3rdparty/openpgm-svn-r1085/pgm/slist.c deleted file mode 100644 index 9ba68ea..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/slist.c +++ /dev/null @@ -1,166 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable singly-linked list. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - - -//#define SLIST_DEBUG - -pgm_slist_t* -pgm_slist_append ( - pgm_slist_t* restrict list, - void* restrict data - ) -{ - pgm_slist_t* new_list; - pgm_slist_t* last; - - new_list = pgm_new (pgm_slist_t, 1); - new_list->data = data; - new_list->next = NULL; - - if (list) - { - last = pgm_slist_last (list); - last->next = new_list; - return list; - } - else - return new_list; -} - -pgm_slist_t* -pgm_slist_prepend ( - pgm_slist_t* restrict list, - void* restrict data - ) -{ - pgm_slist_t *new_list; - - new_list = pgm_new (pgm_slist_t, 1); - new_list->data = data; - new_list->next = list; - - return new_list; -} - -pgm_slist_t* -pgm_slist_prepend_link ( - pgm_slist_t* restrict list, - pgm_slist_t* restrict link_ - ) -{ - pgm_slist_t *new_list; - - new_list = link_; - new_list->next = list; - - return new_list; -} - -pgm_slist_t* -pgm_slist_remove ( - pgm_slist_t* restrict list, - const void* restrict data - ) -{ - pgm_slist_t *tmp = list, *prev = NULL; - - while (tmp) - { - if (tmp->data == data) - { - if (prev) - prev->next = tmp->next; - else - list = tmp->next; - pgm_free (tmp); - break; - } - prev = tmp; - tmp = prev->next; - } - - return list; -} - -pgm_slist_t* -pgm_slist_remove_first ( - pgm_slist_t* list - ) -{ - pgm_slist_t *tmp; - - if (PGM_LIKELY (NULL != list)) - { - tmp = list->next; - list->data = NULL; - list->next = NULL; - return tmp; - } - else - return NULL; -} - -void -pgm_slist_free ( - pgm_slist_t* list - ) -{ - while (list) - { - pgm_slist_t* current = list; - list = list->next; - pgm_free (current); - } -} - -pgm_slist_t* -pgm_slist_last ( - pgm_slist_t* list - ) -{ - if (PGM_LIKELY (NULL != list)) - { - while (list->next) - list = list->next; - } - - return list; -} - -unsigned -pgm_slist_length ( - pgm_slist_t* list - ) -{ - unsigned length = 0; - - while (list) - { - length++; - list = list->next; - } - - return length; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/snmp.c b/3rdparty/openpgm-svn-r1085/pgm/snmp.c deleted file mode 100644 index 5673878..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/snmp.c +++ /dev/null @@ -1,222 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * SNMP agent, single session. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include - -#include -#include -#include - -#include "pgm/snmp.h" -#include "impl/pgmMIB.h" - - -/* globals */ - -bool pgm_agentx_subagent = TRUE; -char* pgm_agentx_socket = NULL; -char* pgm_snmp_appname = "PGM"; - -/* locals */ - -#ifndef _WIN32 -static pthread_t snmp_thread; -static void* snmp_routine (void*); -#else -static HANDLE snmp_thread; -static unsigned __stdcall snmp_routine (void*); -#endif -static pgm_notify_t snmp_notify = PGM_NOTIFY_INIT; -static volatile uint32_t snmp_ref_count = 0; - - -/* Calling application needs to redirect SNMP logging before prior to this - * function. - */ - -bool -pgm_snmp_init ( - pgm_error_t** error - ) -{ - if (pgm_atomic_exchange_and_add32 (&snmp_ref_count, 1) > 0) - return TRUE; - - if (pgm_agentx_subagent) - { - pgm_minor (_("Configuring as SNMP AgentX sub-agent.")); - if (pgm_agentx_socket) - { - pgm_minor (_("Using AgentX socket %s."), pgm_agentx_socket); - netsnmp_ds_set_string (NETSNMP_DS_APPLICATION_ID, - NETSNMP_DS_AGENT_X_SOCKET, - pgm_agentx_socket); - } - netsnmp_ds_set_boolean (NETSNMP_DS_APPLICATION_ID, - NETSNMP_DS_AGENT_ROLE, - TRUE); - } - - pgm_minor (_("Initialising SNMP agent.")); - if (0 != init_agent (pgm_snmp_appname)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SNMP, - PGM_ERROR_FAILED, - _("Initialise SNMP agent: see SNMP log for further details.")); - goto err_cleanup; - } - - if (!pgm_mib_init (error)) { - goto err_cleanup; - } - -/* read config and parse mib */ - pgm_minor (_("Initialising SNMP.")); - init_snmp (pgm_snmp_appname); - - if (!pgm_agentx_subagent) - { - pgm_minor (_("Connecting to SNMP master agent.")); - if (0 != init_master_agent ()) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SNMP, - PGM_ERROR_FAILED, - _("Initialise SNMP master agent: see SNMP log for further details.")); - snmp_shutdown (pgm_snmp_appname); - goto err_cleanup; - } - } - -/* create notification channel */ - if (0 != pgm_notify_init (&snmp_notify)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SNMP, - pgm_error_from_errno (errno), - _("Creating SNMP notification channel: %s"), - strerror (errno)); - snmp_shutdown (pgm_snmp_appname); - goto err_cleanup; - } - -/* spawn thread to handle SNMP requests */ -#ifndef _WIN32 - const int status = pthread_create (&snmp_thread, NULL, &snmp_routine, NULL); - if (0 != status) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SNMP, - pgm_error_from_errno (errno), - _("Creating SNMP thread: %s"), - strerror (errno)); - snmp_shutdown (pgm_snmp_appname); - goto err_cleanup; - } -#else - snmp_thread = (HANDLE)_beginthreadex (NULL, 0, &snmp_routine, NULL, 0, NULL); - const int save_errno = errno; - if (0 == snmp_thread) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SNMP, - pgm_error_from_errno (save_errno), - _("Creating SNMP thread: %s"), - strerror (save_errno)); - snmp_shutdown (pgm_snmp_appname); - goto err_cleanup; - } -#endif /* _WIN32 */ - return TRUE; -err_cleanup: - if (pgm_notify_is_valid (&snmp_notify)) { - pgm_notify_destroy (&snmp_notify); - } - pgm_atomic_dec32 (&snmp_ref_count); - return FALSE; -} - -/* Terminate SNMP thread and free resources. - */ - -bool -pgm_snmp_shutdown (void) -{ - pgm_return_val_if_fail (pgm_atomic_read32 (&snmp_ref_count) > 0, FALSE); - - if (pgm_atomic_exchange_and_add32 (&snmp_ref_count, (uint32_t)-1) != 1) - return TRUE; - - pgm_notify_send (&snmp_notify); -#ifndef _WIN32 - pthread_join (snmp_thread, NULL); -#else - CloseHandle (snmp_thread); -#endif - pgm_notify_destroy (&snmp_notify); - snmp_shutdown (pgm_snmp_appname); - return TRUE; -} - -/* Thread routine for processing SNMP requests - */ - -static -#ifndef _WIN32 -void* -#else -unsigned -__stdcall -#endif -snmp_routine ( - PGM_GNUC_UNUSED void* arg - ) -{ - const int notify_fd = pgm_notify_get_fd (&snmp_notify); - - for (;;) - { - int fds = 0, block = 1; - fd_set fdset; - struct timeval timeout; - - FD_ZERO(&fdset); - snmp_select_info (&fds, &fdset, &timeout, &block); - FD_SET(notify_fd, &fdset); - if (notify_fd+1 > fds) - fds = notify_fd+1; - fds = select (fds, &fdset, NULL, NULL, block ? NULL : &timeout); - if (FD_ISSET(notify_fd, &fdset)) - break; - if (fds) - snmp_read (&fdset); - else - snmp_timeout(); - } - -/* cleanup */ -#ifndef _WIN32 - return NULL; -#else - _endthread(); - return 0; -#endif /* WIN32 */ -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/snmp_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/snmp_unittest.c deleted file mode 100644 index 9005a82..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/snmp_unittest.c +++ /dev/null @@ -1,184 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for SNMP. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include - -#include "pgm/transport.h" - - -/* mock state */ -static const guint mock_pgm_major_version = 0; -static const guint mock_pgm_minor_version = 0; -static const guint mock_pgm_micro_version = 0; -static GStaticRWLock mock_pgm_transport_list_lock = G_STATIC_RW_LOCK_INIT; -static GSList* mock_pgm_transport_list = NULL; - -static -gboolean -mock_pgm_tsi_equal ( - gconstpointer v1, - gconstpointer v2 - ) -{ - return memcmp (v1, v2, sizeof(struct pgm_tsi_t)) == 0; -} - -static -void -mock_pgm_time_since_epoch ( - pgm_time_t* pgm_time_t_time, - time_t* time_t_time - ) -{ - *time_t_time = pgm_to_secs (*pgm_time_t_time + 0); -} - -static -gboolean -mock_pgm_mib_init ( - GError** error - ) -{ - return TRUE; -} - -/* mock functions for external references */ - -#define pgm_major_version mock_pgm_major_version -#define pgm_minor_version mock_pgm_minor_version -#define pgm_micro_version mock_pgm_micro_version -#define pgm_transport_list_lock mock_pgm_transport_list_lock -#define pgm_transport_list mock_pgm_transport_list -#define pgm_tsi_equal mock_pgm_tsi_equal -#define pgm_time_since_epoch mock_pgm_time_since_epoch -#define pgm_mib_init mock_pgm_mib_init - - -#define SNMP_DEBUG -#include "snmp.c" - - -/* target: - * gboolean - * pgm_snmp_init ( - * GError** error - * ) - */ - -START_TEST (test_init_pass_001) -{ - GError* err = NULL; - fail_unless (TRUE == pgm_snmp_init (&err)); - fail_unless (NULL == err); -} -END_TEST - -/* duplicate servers */ -START_TEST (test_init_fail_001) -{ - GError* err = NULL; - fail_unless (TRUE == pgm_snmp_init (&err)); - fail_unless (FALSE == pgm_snmp_init (&err)); -} -END_TEST - -/* target: - * gboolean - * pgm_snmp_shutdown (void) - */ - -START_TEST (test_shutdown_pass_001) -{ - GError* err = NULL; - fail_unless (TRUE == pgm_snmp_init (&err)); - fail_unless (NULL == err); - fail_unless (TRUE == pgm_snmp_shutdown ()); -} -END_TEST - -/* repeatability - */ -START_TEST (test_shutdown_pass_002) -{ - GError* err = NULL; - fail_unless (TRUE == pgm_snmp_init (&err)); - fail_unless (NULL == err); - fail_unless (TRUE == pgm_snmp_shutdown ()); - fail_unless (TRUE == pgm_snmp_init (&err)); - fail_unless (NULL == err); - fail_unless (TRUE == pgm_snmp_shutdown ()); -} -END_TEST - -/* no running server */ -START_TEST (test_shutdown_fail_001) -{ - fail_unless (FALSE == pgm_snmp_shutdown ()); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_init = tcase_create ("init"); - suite_add_tcase (s, tc_init); - tcase_add_test (tc_init, test_init_pass_001); - tcase_add_test (tc_init, test_init_fail_001); - - TCase* tc_shutdown = tcase_create ("shutdown"); - suite_add_tcase (s, tc_shutdown); - tcase_add_test (tc_shutdown, test_shutdown_pass_001); - tcase_add_test (tc_shutdown, test_shutdown_pass_002); - tcase_add_test (tc_shutdown, test_shutdown_fail_001); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/sockaddr.c b/3rdparty/openpgm-svn-r1085/pgm/sockaddr.c deleted file mode 100644 index 9b8dcb9..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/sockaddr.c +++ /dev/null @@ -1,1193 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * struct sockaddr functions independent of in or in6. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#ifndef _WIN32 -# include -# include -#endif -#include - - -/* FreeBSD */ -#ifndef IPV6_ADD_MEMBERSHIP -# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP -# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP -#endif -/* OpenSolaris differences */ -#ifndef MCAST_MSFILTER -# include -#endif -#ifndef SOL_IP -# define SOL_IP IPPROTO_IP -#endif -#ifndef SOL_IPV6 -# define SOL_IPV6 IPPROTO_IPV6 -#endif -#ifndef IP_MAX_MEMBERSHIPS -# define IP_MAX_MEMBERSHIPS 20 -#endif - - -sa_family_t -pgm_sockaddr_family ( - const struct sockaddr* sa - ) -{ - return sa->sa_family; -} - -uint16_t -pgm_sockaddr_port ( - const struct sockaddr* sa - ) -{ - uint16_t sa_port; - switch (sa->sa_family) { - case AF_INET: { - struct sockaddr_in s4; - memcpy (&s4, sa, sizeof(s4)); - sa_port = s4.sin_port; - break; - } - - case AF_INET6: { - struct sockaddr_in6 s6; - memcpy (&s6, sa, sizeof(s6)); - sa_port = s6.sin6_port; - break; - } - - default: - sa_port = 0; - break; - } - return sa_port; -} - -socklen_t -pgm_sockaddr_len ( - const struct sockaddr* sa - ) -{ - socklen_t sa_len; - switch (sa->sa_family) { - case AF_INET: sa_len = sizeof(struct sockaddr_in); break; - case AF_INET6: sa_len = sizeof(struct sockaddr_in6); break; - default: sa_len = 0; break; - } - return sa_len; -} - -socklen_t -pgm_sockaddr_storage_len ( - const struct sockaddr_storage* ss - ) -{ - socklen_t ss_len; - switch (ss->ss_family) { - case AF_INET: ss_len = sizeof(struct sockaddr_in); break; - case AF_INET6: ss_len = sizeof(struct sockaddr_in6); break; - default: ss_len = 0; break; - } - return ss_len; -} - -uint32_t -pgm_sockaddr_scope_id ( - const struct sockaddr* sa - ) -{ - uint32_t scope_id; - if (AF_INET6 == sa->sa_family) { - struct sockaddr_in6 s6; - memcpy (&s6, sa, sizeof(s6)); - scope_id = s6.sin6_scope_id; - } else - scope_id = 0; - return scope_id; -} - -int -pgm_sockaddr_ntop ( - const struct sockaddr* restrict sa, - char* restrict host, - size_t hostlen - ) -{ - return getnameinfo (sa, pgm_sockaddr_len (sa), - host, hostlen, - NULL, 0, - NI_NUMERICHOST); -} - -int -pgm_sockaddr_pton ( - const char* restrict src, - struct sockaddr* restrict dst /* will error on wrong size */ - ) -{ - struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, /* not really */ - .ai_protocol = IPPROTO_TCP, /* not really */ - .ai_flags = AI_NUMERICHOST - }, *result = NULL; - const int status = getaddrinfo (src, NULL, &hints, &result); - if (PGM_LIKELY(0 == status)) { - memcpy (dst, result->ai_addr, result->ai_addrlen); - freeaddrinfo (result); - return 1; - } - return 0; -} - -/* returns tri-state value: 1 if sa is multicast, 0 if sa is not multicast, -1 on error - */ - -int -pgm_sockaddr_is_addr_multicast ( - const struct sockaddr* sa - ) -{ - int retval; - - switch (sa->sa_family) { - case AF_INET: { - struct sockaddr_in s4; - memcpy (&s4, sa, sizeof(s4)); - retval = IN_MULTICAST(ntohl( s4.sin_addr.s_addr )); - break; - } - - case AF_INET6: { - struct sockaddr_in6 s6; - memcpy (&s6, sa, sizeof(s6)); - retval = IN6_IS_ADDR_MULTICAST( &s6.sin6_addr ); - break; - } - - default: - retval = -1; - break; - } - return retval; -} - -/* returns 1 if sa is unspecified, 0 if specified. - */ - -int -pgm_sockaddr_is_addr_unspecified ( - const struct sockaddr* sa - ) -{ - int retval; - - switch (sa->sa_family) { - case AF_INET: { - struct sockaddr_in s4; - memcpy (&s4, sa, sizeof(s4)); - retval = (INADDR_ANY == s4.sin_addr.s_addr); - break; - } - - case AF_INET6: { - struct sockaddr_in6 s6; - memcpy (&s6, sa, sizeof(s6)); - retval = IN6_IS_ADDR_UNSPECIFIED( &s6.sin6_addr ); - break; - } - - default: - retval = -1; - break; - } - return retval; -} - -int -pgm_sockaddr_cmp ( - const struct sockaddr* restrict sa1, - const struct sockaddr* restrict sa2 - ) -{ - int retval = 0; - - if (sa1->sa_family != sa2->sa_family) - retval = sa1->sa_family < sa2->sa_family ? -1 : 1; - else { - switch (sa1->sa_family) { - case AF_INET: { - struct sockaddr_in sa1_in, sa2_in; - memcpy (&sa1_in, sa1, sizeof(sa1_in)); - memcpy (&sa2_in, sa2, sizeof(sa2_in)); - if (sa1_in.sin_addr.s_addr != sa2_in.sin_addr.s_addr) - retval = sa1_in.sin_addr.s_addr < sa2_in.sin_addr.s_addr ? -1 : 1; - break; - } - -/* IN6_ARE_ADDR_EQUAL(a,b) only returns true or false */ - case AF_INET6: { - struct sockaddr_in6 sa1_in6, sa2_in6; - memcpy (&sa1_in6, sa1, sizeof(sa1_in6)); - memcpy (&sa2_in6, sa2, sizeof(sa2_in6)); - retval = memcmp (&sa1_in6.sin6_addr, &sa2_in6.sin6_addr, sizeof(struct in6_addr)); - if (0 == retval && sa1_in6.sin6_scope_id != sa2_in6.sin6_scope_id) - retval = sa1_in6.sin6_scope_id < sa2_in6.sin6_scope_id ? -1 : 1; - break; - } - - default: - break; - } - } - return retval; -} - -/* IP header included with data. - * - * If no error occurs, pgm_sockaddr_hdrincl returns zero. Otherwise, a value - * of PGM_SOCKET_ERROR is returned, and a specific error code can be retrieved - * by calling pgm_sock_errno(). - */ - -int -pgm_sockaddr_hdrincl ( - const int s, - const sa_family_t sa_family, - const bool v - ) -{ - int retval = PGM_SOCKET_ERROR; - - switch (sa_family) { - case AF_INET: { -#ifndef _WIN32 -/* Solaris:ip(7P) Mentioned but not detailed. - * - * Linux:ip(7) "A boolean integer flag is zero when it is false, otherwise - * true. If enabled, the user supplies an IP header in front of the user - * data." Mentions only send-side, nothing about receive-side. - * Linux:raw(7) "For receiving the IP header is always included in the packet." - * - * FreeBSD,OS X:IP(4) provided by example "int hincl = 1;" - * - * Stevens: "IP_HDRINCL has datatype int." - */ - const int optval = v ? 1 : 0; -#else - const DWORD optval = v ? 1 : 0; -#endif - retval = setsockopt (s, IPPROTO_IP, IP_HDRINCL, (const char*)&optval, sizeof(optval)); - break; - } - - case AF_INET6: /* method only exists on Win32, just ignore */ - retval = 0; - break; - - default: break; - } - return retval; -} - -/* Return destination IP address. - * - * If no error occurs, pgm_sockaddr_pktinfo returns zero. Otherwise, a value - * of PGM_SOCKET_ERROR is returned, and a specific error code can be retrieved - * by calling pgm_sock_errno(). - */ - -int -pgm_sockaddr_pktinfo ( - const int s, - const sa_family_t sa_family, - const bool v - ) -{ - int retval = PGM_SOCKET_ERROR; -#ifndef _WIN32 -/* Solaris:ip(7P) "The following options take in_pktinfo_t as the parameter" - * Completely different, although ip6(7P) is a little better, "The following - * options are boolean switches controlling the reception of ancillary data" - * - * Linux:ip(7) "A boolean integer flag is zero when it is false, otherwise - * true. The argument is a flag that tells the socket whether the IP_PKTINFO - * message should be passed or not." - * Linux:ipv6(7) Not listed, however IPV6_PKTINFO is with "Argument is a pointer - * to a boolean value in an integer." - * - * Absent from FreeBSD & OS X, suggested replacement IP_RECVDSTADDR. - * OS X:IP6(4) "IPV6_PKTINFO int *" - * - * Stevens: "IP_RECVDSTADDR has datatype int." - */ - const int optval = v ? 1 : 0; -#else - const DWORD optval = v ? 1 : 0; -#endif - - switch (sa_family) { - case AF_INET: -#ifdef IP_RECVDSTADDR - retval = setsockopt (s, IPPROTO_IP, IP_RECVDSTADDR, (const char*)&optval, sizeof(optval)); -#else - retval = setsockopt (s, IPPROTO_IP, IP_PKTINFO, (const char*)&optval, sizeof(optval)); -#endif - break; - - case AF_INET6: -#ifdef IPV6_RECVPKTINFO - retval = setsockopt (s, IPPROTO_IPV6, IPV6_RECVPKTINFO, (const char*)&optval, sizeof(optval)); -#else - retval = setsockopt (s, IPPROTO_IPV6, IPV6_PKTINFO, (const char*)&optval, sizeof(optval)); -#endif - break; - - default: break; - } - return retval; -} - -/* Set IP Router Alert option for all outgoing packets. - * - * If no error occurs, pgm_sockaddr_router_alert returns zero. Otherwise, a - * value of PGM_SOCKET_ERROR is returned, and a specific error code can be - * retrieved by calling pgm_sock_errno(). - */ - -int -pgm_sockaddr_router_alert ( - const int s, - const sa_family_t sa_family, - const bool v - ) -{ - int retval = PGM_SOCKET_ERROR; -#ifdef CONFIG_IP_ROUTER_ALERT -/* Linux:ip(7) "A boolean integer flag is zero when it is false, otherwise - * true. Expects an integer flag." - * Linux:ipv6(7) "Argument is a pointer to an integer." - * - * Sent on special queue to rsvpd on Linux and so best avoided. - */ - const int optval = v ? 1 : 0; - - switch (sa_family) { - case AF_INET: - retval = setsockopt (s, IPPROTO_IP, IP_ROUTER_ALERT, (const char*)&optval, sizeof(optval)); - break; - - case AF_INET6: - retval = setsockopt (s, IPPROTO_IPV6, IPV6_ROUTER_ALERT, (const char*)&optval, sizeof(optval)); - break; - - default: break; - } -#else -# if defined(CONFIG_HAVE_IPOPTION) -/* NB: struct ipoption is not very portable and requires a lot of additional headers */ - const struct ipoption router_alert = { - .ipopt_dst = 0, - .ipopt_list = { PGM_IPOPT_RA, 0x04, 0x00, 0x00 } - }; - const int optlen = v ? sizeof(router_alert) : 0; -# else -/* manually set the IP option */ - const int ipopt_ra = (PGM_IPOPT_RA << 24) | (0x04 << 16); - const int router_alert = htonl (ipopt_ra); - const int optlen = v ? sizeof(router_alert) : 0; -# endif - - switch (sa_family) { - case AF_INET: -/* Linux:ip(7) "The maximum option size for IPv4 is 40 bytes." - */ - retval = setsockopt (s, IPPROTO_IP, IP_OPTIONS, (const char*)&router_alert, optlen); -retval = 0; - break; - - default: break; - } -#endif - return retval; -} - -/* Type-of-service and precedence. - * - * If no error occurs, pgm_sockaddr_tos returns zero. Otherwise, a value of - * PGM_SOCKET_ERROR is returned, and a specific error code can be retrieved by - * calling pgm_sock_errno(). - */ - -int -pgm_sockaddr_tos ( - const int s, - const sa_family_t sa_family, - const int tos - ) -{ - int retval = PGM_SOCKET_ERROR; - - switch (sa_family) { - case AF_INET: { -#ifndef _WIN32 -/* Solaris:ip(7P) "This option takes an integer argument as its input value." - * - * Linux:ip(7) "TOS is a byte." - * - * FreeBSD,OS X:IP(4) provided by example "int tos = IPTOS_LOWDELAY;" - * - * Stevens: "IP_TOS has datatype int." - */ - const int optval = tos; -#else -/* IP_TOS only works on Win32 with system override: - * http://support.microsoft.com/kb/248611 - * TODO: Implement GQoS (IPv4 only), qWAVE QOS is Vista+ only - */ - const DWORD optval = tos; -#endif - retval = setsockopt (s, IPPROTO_IP, IP_TOS, (const char*)&optval, sizeof(optval)); - break; - } - - case AF_INET6: /* TRAFFIC_CLASS not implemented */ - break; - - default: break; - } - return retval; -} - -/* Join multicast group. - * NB: IPV6_JOIN_GROUP == IPV6_ADD_MEMBERSHIP - * - * If no error occurs, pgm_sockaddr_join_group returns zero. Otherwise, a - * value of PGM_SOCKET_ERROR is returned, and a specific error code can be - * retrieved by calling pgm_sock_errno(). - */ - -int -pgm_sockaddr_join_group ( - const int s, - const sa_family_t sa_family, - const struct group_req* gr - ) -{ - int retval = PGM_SOCKET_ERROR; -#ifdef CONFIG_HAVE_MCAST_JOIN -/* Solaris:ip(7P) "The following options take a struct ip_mreq_source as the - * parameter." Presumably with source field zeroed out. - * Solaris:ip6(7P) "Takes a struct group_req as the parameter." - * Different type for each family, however group_req is protocol-independent. - * - * Stevens: "MCAST_JOIN_GROUP has datatype group_req{}." - * - * RFC3678: Argument type struct group_req - */ - const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; - retval = setsockopt (s, recv_level, MCAST_JOIN_GROUP, gr, sizeof(struct group_req)); -#else - switch (sa_family) { - case AF_INET: { -/* Solaris:ip(7P) Just mentions "Join a multicast group." - * No further details provided. - * - * Linux:ip(7) "Argument is an ip_mreqn structure. For compatibility, the old - * ip_mreq structure (present since Linux 1.2) is still supported." - * - * FreeBSD,OS X:IP(4) provided by example "struct ip_mreq mreq;" - * - * Windows can optionally abuse imt_interface to be 0.0.0. - * - * Stevens: "IP_ADD_MEMBERSHIP has datatype ip_mreq{}." - * - * RFC3678: Argument type struct ip_mreq - */ -#ifdef CONFIG_HAVE_IP_MREQN - struct ip_mreqn mreqn; - struct sockaddr_in ifaddr; - memset (&mreqn, 0, sizeof(mreqn)); - mreqn.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gr->gr_group)->sin_addr.s_addr; - if (!pgm_if_indextoaddr (gr->gr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL)) - return -1; - mreqn.imr_address.s_addr = ifaddr.sin_addr.s_addr; - mreqn.imr_ifindex = gr->gr_interface; - retval = setsockopt (s, SOL_IP, IP_ADD_MEMBERSHIP, (const char*)&mreqn, sizeof(mreqn)); -#else - struct ip_mreq mreq; - struct sockaddr_in ifaddr; - memset (&mreq, 0, sizeof(mreq)); - mreq.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gr->gr_group)->sin_addr.s_addr; - if (!pgm_if_indextoaddr (gr->gr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL)) - return -1; - mreq.imr_interface.s_addr = ifaddr.sin_addr.s_addr; - retval = setsockopt (s, SOL_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)); -#endif /* !CONFIG_HAVE_IP_MREQN */ - break; - } - - case AF_INET6: { -/* Solaris:ip6(7P) "Takes a struct ipv6_mreq as the parameter;" - * - * Linux:ipv6(7) "Argument is a pointer to a struct ipv6_mreq structure." - * - * OS X:IP6(4) "IPV6_JOIN_GROUP struct ipv6_mreq *" - * - * Stevens: "IPV6_JOIN_GROUP has datatype ipv6_mreq{}." - */ - struct ipv6_mreq mreq6; - memset (&mreq6, 0, sizeof(mreq6)); - mreq6.ipv6mr_multiaddr = ((const struct sockaddr_in6*)&gr->gr_group)->sin6_addr; - mreq6.ipv6mr_interface = gr->gr_interface; - retval = setsockopt (s, SOL_IPV6, IPV6_ADD_MEMBERSHIP, (const char*)&mreq6, sizeof(mreq6)); - break; - } - - default: break; - } -#endif /* CONFIG_HAVE_MCAST_JOIN */ - return retval; -} - -/* leave a joined group - */ - -int -pgm_sockaddr_leave_group ( - const int s, - const sa_family_t sa_family, - const struct group_req* gr - ) -{ - int retval = PGM_SOCKET_ERROR; -#ifdef CONFIG_HAVE_MCAST_JOIN - const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; - retval = setsockopt (s, recv_level, MCAST_LEAVE_GROUP, gr, sizeof(struct group_req)); -#else - switch (sa_family) { - case AF_INET: { -#ifdef CONFIG_HAVE_IP_MREQN - struct ip_mreqn mreqn; - struct sockaddr_in ifaddr; - memset (&mreqn, 0, sizeof(mreqn)); - mreqn.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gr->gr_group)->sin_addr.s_addr; - if (!pgm_if_indextoaddr (gr->gr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL)) - return -1; - mreqn.imr_address.s_addr = ifaddr.sin_addr.s_addr; - mreqn.imr_ifindex = gr->gr_interface; - retval = setsockopt (s, SOL_IP, IP_DROP_MEMBERSHIP, (const char*)&mreqn, sizeof(mreqn)); -#else - struct ip_mreq mreq; - struct sockaddr_in ifaddr; - memset (&mreq, 0, sizeof(mreq)); - mreq.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gr->gr_group)->sin_addr.s_addr; - if (!pgm_if_indextoaddr (gr->gr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL)) - return -1; - mreq.imr_interface.s_addr = ifaddr.sin_addr.s_addr; - retval = setsockopt (s, SOL_IP, IP_DROP_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)); -#endif /* !CONFIG_HAVE_IP_MREQN */ - break; - } - - case AF_INET6: { - struct ipv6_mreq mreq6; - memset (&mreq6, 0, sizeof(mreq6)); - mreq6.ipv6mr_multiaddr = ((const struct sockaddr_in6*)&gr->gr_group)->sin6_addr; - mreq6.ipv6mr_interface = gr->gr_interface; - retval = setsockopt (s, SOL_IPV6, IPV6_DROP_MEMBERSHIP, (const char*)&mreq6, sizeof(mreq6)); - break; - } - - default: break; - } -#endif /* CONFIG_HAVE_MCAST_JOIN */ - return retval; -} - -/* block either at the NIC or kernel, packets from a particular source - */ - -int -pgm_sockaddr_block_source ( - const int s, - const sa_family_t sa_family, - const struct group_source_req* gsr - ) -{ - int retval = PGM_SOCKET_ERROR; -#ifdef CONFIG_HAVE_MCAST_JOIN - const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; - retval = setsockopt (s, recv_level, MCAST_BLOCK_SOURCE, gsr, sizeof(struct group_source_req)); -#elif defined(IP_BLOCK_SOURCE) - switch (sa_family) { - case AF_INET: { - struct ip_mreq_source mreqs; - struct sockaddr_in ifaddr; - memset (&mreqs, 0, sizeof(mreqs)); - mreqs.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_group)->sin_addr.s_addr; - mreqs.imr_sourceaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_source)->sin_addr.s_addr; - pgm_if_indextoaddr (gsr->gsr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL); - mreqs.imr_interface.s_addr = ifaddr.sin_addr.s_addr; - retval = setsockopt (s, SOL_IP, IP_BLOCK_SOURCE, (const char*)&mreqs, sizeof(mreqs)); - break; - } - - case AF_INET6: -/* No IPv6 API implemented, MCAST_BLOCK_SOURCE should be available instead. - */ - break; - - default: break; - } -#endif /* CONFIG_HAVE_MCAST_JOIN */ - return retval; -} - -/* unblock a blocked multicast source. - */ - -int -pgm_sockaddr_unblock_source ( - const int s, - const sa_family_t sa_family, - const struct group_source_req* gsr - ) -{ - int retval = PGM_SOCKET_ERROR; -#ifdef CONFIG_HAVE_MCAST_JOIN - const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; - retval = setsockopt (s, recv_level, MCAST_UNBLOCK_SOURCE, gsr, sizeof(struct group_source_req)); -#elif defined(IP_UNBLOCK_SOURCE) - switch (sa_family) { - case AF_INET: { - struct ip_mreq_source mreqs; - struct sockaddr_in ifaddr; - memset (&mreqs, 0, sizeof(mreqs)); - mreqs.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_group)->sin_addr.s_addr; - mreqs.imr_sourceaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_source)->sin_addr.s_addr; - pgm_if_indextoaddr (gsr->gsr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL); - mreqs.imr_interface.s_addr = ifaddr.sin_addr.s_addr; - retval = setsockopt (s, SOL_IP, IP_UNBLOCK_SOURCE, (const char*)&mreqs, sizeof(mreqs)); - break; - } - - case AF_INET6: -/* No IPv6 API implemented, MCAST_UNBLOCK_SOURCE should be available instead. - */ - break; - - default: break; - } -#endif /* CONFIG_HAVE_MCAST_JOIN */ - return retval; -} - -/* Join source-specific multicast. - * NB: Silently reverts to ASM if SSM not supported. - * - * If no error occurs, pgm_sockaddr_join_source_group returns zero. - * Otherwise, a value of PGM_SOCKET_ERROR is returned, and a specific error - * code can be retrieved by calling pgm_sock_errno(). - */ - -int -pgm_sockaddr_join_source_group ( - const int s, - const sa_family_t sa_family, - const struct group_source_req* gsr - ) -{ - int retval = PGM_SOCKET_ERROR; -#ifdef CONFIG_HAVE_MCAST_JOIN -/* Solaris:ip(7P) "The following options take a struct ip_mreq_source as the - * parameter." - * Solaris:ip6(7P) "Takes a struct group_source_req as the parameter." - * Different type for each family, however group_source_req is protocol- - * independent. - * - * Stevens: "MCAST_JOIN_SOURCE_GROUP has datatype group_source_req{}." - * - * RFC3678: Argument type struct group_source_req - */ - const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; - retval = setsockopt (s, recv_level, MCAST_JOIN_SOURCE_GROUP, gsr, sizeof(struct group_source_req)); -#elif defined(IP_ADD_SOURCE_MEMBERSHIP) - switch (sa_family) { - case AF_INET: { -/* Solaris:ip(7P) "The following options take a struct ip_mreq as the - * parameter." Incorrect literature wrt RFC. - * - * Linux:ip(7) absent. - * - * OS X:IP(4) absent. - * - * Stevens: "IP_ADD_SOURCE_MEMBERSHIP has datatype ip_mreq_source{}." - * - * RFC3678: Argument type struct ip_mreq_source - */ - struct ip_mreq_source mreqs; - struct sockaddr_in ifaddr; - memset (&mreqs, 0, sizeof(mreqs)); - mreqs.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_group)->sin_addr.s_addr; - mreqs.imr_sourceaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_source)->sin_addr.s_addr; - pgm_if_indextoaddr (gsr->gsr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL); - mreqs.imr_interface.s_addr = ifaddr.sin_addr.s_addr; - retval = setsockopt (s, SOL_IP, IP_ADD_SOURCE_MEMBERSHIP, (const char*)&mreqs, sizeof(mreqs)); - break; - } - - case AF_INET6: -/* No IPv6 API implemented, MCAST_JOIN_SOURCE_GROUP should be available instead. - */ - retval = pgm_sockaddr_join_group (s, sa_family, (const struct group_req*)gsr); - break; - - default: break; - } -#else - retval = pgm_sockaddr_join_group (s, sa_family, (const struct group_req*)gsr); -#endif /* CONFIG_HAVE_MCAST_JOIN */ - return retval; -} - -/* drop a SSM source - */ - -int -pgm_sockaddr_leave_source_group ( - const int s, - const sa_family_t sa_family, - const struct group_source_req* gsr - ) -{ - int retval = PGM_SOCKET_ERROR; -#ifdef CONFIG_HAVE_MCAST_JOIN - const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; - retval = setsockopt (s, recv_level, MCAST_LEAVE_SOURCE_GROUP, gsr, sizeof(struct group_source_req)); -#elif defined(IP_ADD_SOURCE_MEMBERSHIP) - switch (sa_family) { - case AF_INET: { - struct ip_mreq_source mreqs; - struct sockaddr_in ifaddr; - memset (&mreqs, 0, sizeof(mreqs)); - mreqs.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_group)->sin_addr.s_addr; - mreqs.imr_sourceaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_source)->sin_addr.s_addr; - pgm_if_indextoaddr (gsr->gsr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL); - mreqs.imr_interface.s_addr = ifaddr.sin_addr.s_addr; - retval = setsockopt (s, SOL_IP, IP_DROP_SOURCE_MEMBERSHIP, (const char*)&mreqs, sizeof(mreqs)); - break; - } - - case AF_INET6: -/* No IPv6 API implemented, MCAST_LEAVE_SOURCE_GROUP should be available instead. - */ - retval = pgm_sockaddr_leave_group (s, sa_family, (const struct group_req*)gsr); - break; - - default: break; - } -#else - retval = pgm_sockaddr_leave_group (s, sa_family, (const struct group_req*)gsr); -#endif /* CONFIG_HAVE_MCAST_JOIN */ - return retval; -} - -#if defined(MCAST_MSFILTER) || defined(SIOCSMSFILTER) -/* Batch block and unblock sources. - */ - -int -pgm_sockaddr_msfilter ( - const int s, - const sa_family_t sa_family, - const struct group_filter* gf_list - ) -{ - int retval = PGM_SOCKET_ERROR; -#ifdef MCAST_MSFILTER - const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; - const socklen_t len = GROUP_FILTER_SIZE(gf_list->gf_numsrc); - retval = setsockopt (s, recv_level, MCAST_MSFILTER, (const char*)gf_list, len); -#elif defined(SIOCSMSFILTER) - retval = ioctl (s, SIOCSMSFILTER, (const char*)gf_list); -#endif - return retval; -} -#endif /* MCAST_MSFILTER || SIOCSMSFILTER */ - -/* Specify outgoing interface. - * - * If no error occurs, pgm_sockaddr_multicast_if returns zero. Otherwise, a - * value of PGM_SOCKET_ERROR is returned, and a specific error code can be - * retrieved by calling pgm_sock_errno(). - */ - -int -pgm_sockaddr_multicast_if ( - int s, - const struct sockaddr* address, - unsigned ifindex - ) -{ - int retval = PGM_SOCKET_ERROR; - - switch (address->sa_family) { - case AF_INET: { -/* Solaris:ip(7P) "This option takes a struct in_addr as an argument, and it - * selects that interface for outgoing IP multicast packets." - * - * Linux:ip(7) "Argument is an ip_mreqn or ip_mreq structure similar to - * IP_ADD_MEMBERSHIP." - * - * OS X:IP(4) provided by example "struct in_addr addr;" - * - * Stevens: "IP_MULTICAST_IF has datatype struct in_addr{}." - */ - struct sockaddr_in s4; - memcpy (&s4, address, sizeof(s4)); - retval = setsockopt (s, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&s4.sin_addr, sizeof(s4.sin_addr)); - break; - } - - case AF_INET6: { -#ifndef _WIN32 -/* Solaris:ip6(7P) "This option takes an integer as an argument; the integer - * is the interface index of the selected interface." - * - * Linux:ipv6(7) "The argument is a pointer to an interface index (see - * netdevice(7)) in an integer." - * - * OS X:IP6(4) "IPV6_MULTICAST_IF u_int *" - * - * Stevens: "IPV6_MULTICAST_IF has datatype u_int." - */ - const unsigned int optval = ifindex; -#else - const DWORD optval = ifindex; -#endif - retval = setsockopt (s, IPPROTO_IPV6, IPV6_MULTICAST_IF, (const char*)&optval, sizeof(optval)); - break; - } - - default: break; - } - return retval; -} - -/* Specify multicast loop, other applications on the same host may receive - * outgoing packets. This does not affect unicast packets such as NAKs. - * - * If no error occurs, pgm_sockaddr_multicast_loop returns zero. Otherwise, a - * value of PGM_SOCKET_ERROR is returned, and a specific error code can be - * retrieved by calling pgm_sock_errno(). - */ - -int -pgm_sockaddr_multicast_loop ( - const int s, - const sa_family_t sa_family, - const bool v - ) -{ - int retval = PGM_SOCKET_ERROR; - - switch (sa_family) { - case AF_INET: { -#ifndef _WIN32 -/* Solaris:ip(7P) "Setting the unsigned character argument to 0 causes the - * opposite behavior, meaning that when multiple zones are present, the - * datagrams are delivered to all zones except the sending zone." - * - * Linux:ip(7) "Sets or reads a boolean integer argument" - * - * OS X:IP(4) provided by example "u_char loop;" - * - * Stevens: "IP_MULTICAST_LOOP has datatype u_char." - */ - const unsigned char optval = v ? 1 : 0; -#else - const DWORD optval = v ? 1 : 0; -#endif - retval = setsockopt (s, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&optval, sizeof(optval)); - break; - } - - case AF_INET6: { -#ifndef _WIN32 -/* Solaris:ip(7P) "Setting the unsigned character argument to 0 will cause the opposite behavior." - * - * Linux:ipv6(7) "Argument is a pointer to boolean." - * - * OS X:IP6(7) "IPV6_MULTICAST_LOOP u_int *" - * - * Stevens: "IPV6_MULTICAST_LOOP has datatype u_int." - */ - const unsigned int optval = v ? 1 : 0; -#else - const DWORD optval = v ? 1 : 0; -#endif - retval = setsockopt (s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const char*)&optval, sizeof(optval)); - break; - } - - default: break; - } - return retval; -} - -/* Specify TTL or outgoing hop limit. - * NB: Only affects multicast hops, unicast hop-limit is not changed. - * - * If no error occurs, pgm_sockaddr_multicast_hops returns zero. Otherwise, a - * value of PGM_SOCKET_ERROR is returned, and a specific error code can be - * retrieved by calling pgm_sock_errno(). - */ - -int -pgm_sockaddr_multicast_hops ( - const int s, - const sa_family_t sa_family, - const unsigned hops - ) -{ - int retval = PGM_SOCKET_ERROR; - - switch (sa_family) { - case AF_INET: { -#ifndef _WIN32 -/* Solaris:ip(7P) "This option takes an unsigned character as an argument." - * - * Linux:ip(7) "Argument is an integer." - * - * OS X:IP(4) provided by example for SOCK_DGRAM with IP_TTL: "int ttl = 60;", - * or for SOCK_RAW & SOCK_DGRAM with IP_MULTICAST_TTL: "u_char ttl;" - * - * Stevens: "IP_MULTICAST_TTL has datatype u_char." - */ - const unsigned char optval = hops; -#else - const DWORD optval = hops; -#endif - retval = setsockopt (s, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&optval, sizeof(optval)); - break; - } - - case AF_INET6: { -#ifndef _WIN32 -/* Solaris:ip6(7P) "This option takes an integer as an argument." - * - * Linux:ipv6(7) "Argument is a pointer to an integer." - * - * OS X:IP6(7) "IPV6_MULTICAST_HOPS int *" - * - * Stevens: "IPV6_MULTICAST_HOPS has datatype int." - */ - const int optval = hops; -#else - const DWORD optval = hops; -#endif - retval = setsockopt (s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&optval, sizeof(optval)); - break; - } - - default: break; - } - return retval; -} - -void -pgm_sockaddr_nonblocking ( - const int s, - const bool v - ) -{ -#ifndef _WIN32 - int flags = fcntl (s, F_GETFL); - if (!v) flags &= ~O_NONBLOCK; - else flags |= O_NONBLOCK; - fcntl (s, F_SETFL, flags); -#else - u_long mode = v; - ioctlsocket (s, FIONBIO, &mode); -#endif -} - -/* Note that are sockaddr structure is not passed these functions inherently - * cannot support IPv6 Zone Indices and hence are rather limited for the - * link-local scope. - */ -const char* -pgm_inet_ntop ( - int af, - const void* restrict src, - char* restrict dst, - socklen_t size - ) -{ - pgm_assert (AF_INET == af || AF_INET6 == af); - pgm_assert (NULL != src); - pgm_assert (NULL != dst); - pgm_assert (size > 0); - - switch (af) { - case AF_INET: - { - struct sockaddr_in sin; - memset (&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr = *(const struct in_addr*)src; - getnameinfo ((struct sockaddr*)&sin, sizeof(sin), - dst, size, - NULL, 0, - NI_NUMERICHOST); - return dst; - } - case AF_INET6: - { - struct sockaddr_in6 sin6; - memset (&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = *(const struct in6_addr*)src; - getnameinfo ((struct sockaddr*)&sin6, sizeof(sin6), - dst, size, - NULL, 0, - NI_NUMERICHOST); - return dst; - } - } - - errno = EAFNOSUPPORT; - return NULL; -} - -int -pgm_inet_pton ( - int af, - const char* restrict src, - void* restrict dst - ) -{ - pgm_assert (AF_INET == af || AF_INET6 == af); - pgm_assert (NULL != src); - pgm_assert (NULL != dst); - - struct addrinfo hints = { - .ai_family = af, - .ai_socktype = SOCK_STREAM, /* not really */ - .ai_protocol = IPPROTO_TCP, /* not really */ - .ai_flags = AI_NUMERICHOST - }, *result = NULL; - - const int e = getaddrinfo (src, NULL, &hints, &result); - if (0 != e) { - return 0; /* error */ - } - - pgm_assert (NULL != result->ai_addr); - pgm_assert (0 != result->ai_addrlen); - - switch (result->ai_addr->sa_family) { - case AF_INET: { - struct sockaddr_in s4; - memcpy (&s4, result->ai_addr, sizeof(s4)); - memcpy (dst, &s4.sin_addr.s_addr, sizeof(struct in_addr)); - break; - } - - case AF_INET6: { - struct sockaddr_in6 s6; - memcpy (&s6, result->ai_addr, sizeof(s6)); - memcpy (dst, &s6.sin6_addr, sizeof(struct in6_addr)); - break; - } - - default: - pgm_assert_not_reached(); - break; - } - - freeaddrinfo (result); - return 1; /* success */ -} - -int -pgm_nla_to_sockaddr ( - const void* restrict nla, - struct sockaddr* restrict sa - ) -{ - uint16_t nla_family; - int retval = 0; - - memcpy (&nla_family, nla, sizeof(nla_family)); - sa->sa_family = ntohs (nla_family); - switch (sa->sa_family) { - case AFI_IP: - sa->sa_family = AF_INET; - ((struct sockaddr_in*)sa)->sin_addr.s_addr = ((const struct in_addr*)((const char*)nla + sizeof(uint32_t)))->s_addr; - break; - - case AFI_IP6: - sa->sa_family = AF_INET6; - memcpy (&((struct sockaddr_in6*)sa)->sin6_addr, (const struct in6_addr*)((const char*)nla + sizeof(uint32_t)), sizeof(struct in6_addr)); - break; - - default: - retval = -EINVAL; - break; - } - - return retval; -} - -int -pgm_sockaddr_to_nla ( - const struct sockaddr* restrict sa, - void* restrict nla - ) -{ - int retval = 0; - - *(uint16_t*)nla = sa->sa_family; - *(uint16_t*)((char*)nla + sizeof(uint16_t)) = 0; /* reserved 16bit space */ - switch (sa->sa_family) { - case AF_INET: - *(uint16_t*)nla = htons (AFI_IP); - ((struct in_addr*)((char*)nla + sizeof(uint32_t)))->s_addr = ((const struct sockaddr_in*)sa)->sin_addr.s_addr; - break; - - case AF_INET6: - *(uint16_t*)nla = htons (AFI_IP6); - memcpy ((struct in6_addr*)((char*)nla + sizeof(uint32_t)), &((const struct sockaddr_in6*)sa)->sin6_addr, sizeof(struct in6_addr)); - break; - - default: - retval = -EINVAL; - break; - } - - return retval; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/socket.c b/3rdparty/openpgm-svn-r1085/pgm/socket.c deleted file mode 100644 index 1338085..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/socket.c +++ /dev/null @@ -1,2046 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM socket: manage incoming & outgoing sockets with ambient SPMs, - * transmit & receive windows. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#ifdef CONFIG_HAVE_POLL -# include -#endif -#ifdef CONFIG_HAVE_EPOLL -# include -#endif -#include -#include -#include -#include -#include -#include -#include - - -//#define SOCK_DEBUG -//#define SOCK_SPM_DEBUG - - -/* global locals */ -pgm_rwlock_t pgm_sock_list_lock; /* list of all sockets for admin interfaces */ -pgm_slist_t* pgm_sock_list = NULL; - - -static const char* pgm_family_string (const int) PGM_GNUC_CONST; -static const char* pgm_sock_type_string (const int) PGM_GNUC_CONST; -static const char* pgm_protocol_string (const int) PGM_GNUC_CONST; - - -size_t -pgm_pkt_offset ( - bool can_fragment, - sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - static const size_t data_size = sizeof(struct pgm_header) + sizeof(struct pgm_data); - size_t pkt_size = data_size; - if (can_fragment || 0 != pgmcc_family) - pkt_size += sizeof(struct pgm_opt_length) + sizeof(struct pgm_opt_header); - if (can_fragment) - pkt_size += sizeof(struct pgm_opt_fragment); - if (AF_INET == pgmcc_family) - pkt_size += sizeof(struct pgm_opt_pgmcc_data); - else if (AF_INET6 == pgmcc_family) - pkt_size += sizeof(struct pgm_opt6_pgmcc_data); - return pkt_size; -} - -/* destroy a pgm_sock object and contents, if last sock also destroy - * associated event loop - * - * outstanding locks: - * 1) pgm_sock_t::lock - * 2) pgm_sock_t::receiver_mutex - * 3) pgm_sock_t::source_mutex - * 4) pgm_sock_t::txw_spinlock - * 5) pgm_sock_t::timer_mutex - * - * If application calls a function on the sock after destroy() it is a - * programmer error: segv likely to occur on unlock. - * - * on success, returns TRUE, on failure returns FALSE. - */ - -bool -pgm_close ( - pgm_sock_t* sock, - bool flush - ) -{ - pgm_return_val_if_fail (sock != NULL, FALSE); - if (!pgm_rwlock_reader_trylock (&sock->lock)) - pgm_return_val_if_reached (FALSE); - pgm_return_val_if_fail (!sock->is_destroyed, FALSE); - pgm_debug ("pgm_sock_destroy (sock:%p flush:%s)", - (const void*)sock, - flush ? "TRUE":"FALSE"); -/* flag existing calls */ - sock->is_destroyed = TRUE; -/* cancel running blocking operations */ - if (PGM_INVALID_SOCKET != sock->recv_sock) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Closing receive socket.")); - pgm_closesocket (sock->recv_sock); - sock->recv_sock = PGM_INVALID_SOCKET; - } - if (PGM_INVALID_SOCKET != sock->send_sock) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Closing send socket.")); - pgm_closesocket (sock->send_sock); - sock->send_sock = PGM_INVALID_SOCKET; - } - pgm_rwlock_reader_unlock (&sock->lock); - pgm_debug ("blocking on destroy lock ..."); - pgm_rwlock_writer_lock (&sock->lock); - - pgm_debug ("removing sock from inventory."); - pgm_rwlock_writer_lock (&pgm_sock_list_lock); - pgm_sock_list = pgm_slist_remove (pgm_sock_list, sock); - pgm_rwlock_writer_unlock (&pgm_sock_list_lock); - -/* flush source side by sending heartbeat SPMs */ - if (sock->can_send_data && - sock->is_connected && - flush) - { - pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Flushing PGM source with session finish option broadcast SPMs.")); - if (!pgm_send_spm (sock, PGM_OPT_FIN) || - !pgm_send_spm (sock, PGM_OPT_FIN) || - !pgm_send_spm (sock, PGM_OPT_FIN)) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Failed to send flushing SPMs.")); - } - } - - if (sock->peers_hashtable) { - pgm_debug ("destroying peer lookup table."); - pgm_hashtable_destroy (sock->peers_hashtable); - sock->peers_hashtable = NULL; - } - if (sock->peers_list) { - pgm_debug ("destroying peer list."); - do { - pgm_list_t* next = sock->peers_list->next; - pgm_peer_unref ((pgm_peer_t*)sock->peers_list->data); - - sock->peers_list = next; - } while (sock->peers_list); - } - - if (sock->window) { - pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Destroying transmit window.")); - pgm_txw_shutdown (sock->window); - sock->window = NULL; - } - pgm_trace (PGM_LOG_ROLE_RATE_CONTROL,_("Destroying rate control.")); - pgm_rate_destroy (&sock->rate_control); - if (PGM_INVALID_SOCKET != sock->send_with_router_alert_sock) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Closing send with router alert socket.")); - pgm_closesocket (sock->send_with_router_alert_sock); - sock->send_with_router_alert_sock = PGM_INVALID_SOCKET; - } - if (sock->spm_heartbeat_interval) { - pgm_debug ("freeing SPM heartbeat interval data."); - pgm_free (sock->spm_heartbeat_interval); - sock->spm_heartbeat_interval = NULL; - } - if (sock->rx_buffer) { - pgm_debug ("freeing receive buffer."); - pgm_free_skb (sock->rx_buffer); - sock->rx_buffer = NULL; - } - pgm_debug ("destroying notification channels."); - if (sock->can_send_data) { - if (sock->use_pgmcc) { - pgm_notify_destroy (&sock->ack_notify); - } - pgm_notify_destroy (&sock->rdata_notify); - } - pgm_notify_destroy (&sock->pending_notify); - pgm_debug ("freeing sock locks."); - pgm_rwlock_free (&sock->peers_lock); - pgm_spinlock_free (&sock->txw_spinlock); - pgm_mutex_free (&sock->send_mutex); - pgm_mutex_free (&sock->timer_mutex); - pgm_mutex_free (&sock->source_mutex); - pgm_mutex_free (&sock->receiver_mutex); - pgm_rwlock_writer_unlock (&sock->lock); - pgm_rwlock_free (&sock->lock); - pgm_debug ("freeing sock data."); - pgm_free (sock); - pgm_debug ("finished."); - return TRUE; -} - -/* Create a pgm_sock object. Create sockets that require superuser - * priviledges. If interface ports are specified then UDP encapsulation will - * be used instead of raw protocol. - * - * If send == recv only two sockets need to be created iff ip headers are not - * required (IPv6). - * - * All receiver addresses must be the same family. - * interface and multiaddr must be the same family. - * family cannot be AF_UNSPEC! - * - * returns TRUE on success, or FALSE on error and sets error appropriately. - */ - -#if ( AF_INET != PF_INET ) || ( AF_INET6 != PF_INET6 ) -#error AF_INET and PF_INET are different values, the bananas are jumping in their pyjamas! -#endif - -bool -pgm_socket ( - pgm_sock_t** restrict sock, - const sa_family_t family, /* communications domain */ - const int pgm_sock_type, - const int protocol, - pgm_error_t** restrict error - ) -{ - pgm_sock_t* new_sock; - - pgm_return_val_if_fail (NULL != sock, FALSE); - pgm_return_val_if_fail (AF_INET == family || AF_INET6 == family, FALSE); - pgm_return_val_if_fail (SOCK_SEQPACKET == pgm_sock_type, FALSE); - pgm_return_val_if_fail (IPPROTO_UDP == protocol || IPPROTO_PGM == protocol, FALSE); - - pgm_debug ("socket (sock:%p family:%s sock-type:%s protocol:%s error:%p)", - (const void*)sock, pgm_family_string(family), pgm_sock_type_string(pgm_sock_type), pgm_protocol_string(protocol), (const void*)error); - - new_sock = pgm_new0 (pgm_sock_t, 1); - new_sock->family = family; - new_sock->socket_type = pgm_sock_type; - new_sock->protocol = protocol; - new_sock->can_send_data = TRUE; - new_sock->can_send_nak = TRUE; - new_sock->can_recv_data = TRUE; - new_sock->dport = DEFAULT_DATA_DESTINATION_PORT; - new_sock->tsi.sport = DEFAULT_DATA_SOURCE_PORT; - new_sock->adv_mode = 0; /* advance with time */ - -/* PGMCC */ - new_sock->acker_nla.ss_family = family; - -/* source-side */ - pgm_mutex_init (&new_sock->source_mutex); -/* transmit window */ - pgm_spinlock_init (&new_sock->txw_spinlock); -/* send socket */ - pgm_mutex_init (&new_sock->send_mutex); -/* next timer & spm expiration */ - pgm_mutex_init (&new_sock->timer_mutex); -/* receiver-side */ - pgm_mutex_init (&new_sock->receiver_mutex); -/* peer hash map & list lock */ - pgm_rwlock_init (&new_sock->peers_lock); -/* destroy lock */ - pgm_rwlock_init (&new_sock->lock); - -/* open sockets to implement PGM */ - int socket_type; - if (IPPROTO_UDP == new_sock->protocol) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Opening UDP encapsulated sockets.")); - socket_type = SOCK_DGRAM; - new_sock->udp_encap_ucast_port = DEFAULT_UDP_ENCAP_UCAST_PORT; - new_sock->udp_encap_mcast_port = DEFAULT_UDP_ENCAP_MCAST_PORT; - } else { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Opening raw sockets.")); - socket_type = SOCK_RAW; - } - - if ((new_sock->recv_sock = socket (new_sock->family, - socket_type, - new_sock->protocol)) == PGM_INVALID_SOCKET) - { - const int save_errno = pgm_sock_errno(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_sock_errno (save_errno), - _("Creating receive socket: %s"), - pgm_sock_strerror (save_errno)); -#ifndef _WIN32 - if (EPERM == save_errno) { - pgm_error (_("PGM protocol requires CAP_NET_RAW capability, e.g. sudo execcap 'cap_net_raw=ep'")); - } -#endif - goto err_destroy; - } - - if ((new_sock->send_sock = socket (new_sock->family, - socket_type, - new_sock->protocol)) == PGM_INVALID_SOCKET) - { - const int save_errno = pgm_sock_errno(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_sock_errno (save_errno), - _("Creating send socket: %s"), - pgm_sock_strerror (save_errno)); - goto err_destroy; - } - - if ((new_sock->send_with_router_alert_sock = socket (new_sock->family, - socket_type, - new_sock->protocol)) == PGM_INVALID_SOCKET) - { - const int save_errno = pgm_sock_errno(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_sock_errno (save_errno), - _("Creating IP Router Alert (RFC 2113) send socket: %s"), - pgm_sock_strerror (save_errno)); - goto err_destroy; - } - - *sock = new_sock; - - pgm_rwlock_writer_lock (&pgm_sock_list_lock); - pgm_sock_list = pgm_slist_append (pgm_sock_list, *sock); - pgm_rwlock_writer_unlock (&pgm_sock_list_lock); - pgm_debug ("PGM socket successfully created."); - return TRUE; - -err_destroy: - if (PGM_INVALID_SOCKET != new_sock->recv_sock) { - if (PGM_SOCKET_ERROR == pgm_closesocket (new_sock->recv_sock)) { - const int save_errno = pgm_sock_errno(); - pgm_warn (_("Close on receive socket failed: %s"), - pgm_sock_strerror (save_errno)); - } - new_sock->recv_sock = PGM_INVALID_SOCKET; - } - if (PGM_INVALID_SOCKET != new_sock->send_sock) { - if (PGM_SOCKET_ERROR == pgm_closesocket (new_sock->send_sock)) { - const int save_errno = pgm_sock_errno(); - pgm_warn (_("Close on send socket failed: %s"), - pgm_sock_strerror (save_errno)); - } - new_sock->send_sock = PGM_INVALID_SOCKET; - } - if (PGM_INVALID_SOCKET != new_sock->send_with_router_alert_sock) { - if (PGM_SOCKET_ERROR == pgm_closesocket (new_sock->send_with_router_alert_sock)) { - const int save_errno = pgm_sock_errno(); - pgm_warn (_("Close on IP Router Alert (RFC 2113) send socket failed: %s"), - pgm_sock_strerror (save_errno)); - } - new_sock->send_with_router_alert_sock = PGM_INVALID_SOCKET; - } - pgm_free (new_sock); - return FALSE; -} - -bool -pgm_getsockopt ( - pgm_sock_t* const restrict sock, - const int optname, - void* restrict optval, - socklen_t* restrict optlen /* required */ - ) -{ - bool status = FALSE; - pgm_return_val_if_fail (sock != NULL, status); - pgm_return_val_if_fail (optval != NULL, status); - pgm_return_val_if_fail (optlen != NULL, status); - if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) - pgm_return_val_if_reached (status); - if (PGM_UNLIKELY(sock->is_destroyed)) { - pgm_rwlock_reader_unlock (&sock->lock); - return status; - } - switch (optname) { -/* maximum TPDU size */ - case PGM_MTU: - if (PGM_UNLIKELY(*optlen != sizeof (int))) - break; - *(int*restrict)optval = sock->max_tpdu; - status = TRUE; - break; - -/* receive socket */ - case PGM_RECV_SOCK: - if (PGM_UNLIKELY(!sock->is_connected)) - break; - if (PGM_UNLIKELY(*optlen != sizeof (int))) - break; - *(int*)optval = sock->recv_sock; - status = TRUE; - break; - -/* repair socket */ - case PGM_REPAIR_SOCK: - if (PGM_UNLIKELY(!sock->is_connected)) - break; - if (PGM_UNLIKELY(*optlen != sizeof (int))) - break; - *(int*)optval = pgm_notify_get_fd (&sock->rdata_notify); - status = TRUE; - break; - -/* pending socket */ - case PGM_PENDING_SOCK: - if (PGM_UNLIKELY(!sock->is_connected)) - break; - if (PGM_UNLIKELY(*optlen != sizeof (int))) - break; - *(int*)optval = pgm_notify_get_fd (&sock->pending_notify); - status = TRUE; - break; - -/* ACK or congestion socket */ - case PGM_ACK_SOCK: - if (PGM_UNLIKELY(!sock->is_connected)) - break; - if (PGM_UNLIKELY(*optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(!sock->use_pgmcc)) - break; - *(int*)optval = pgm_notify_get_fd (&sock->ack_notify); - status = TRUE; - break; - - -/* timeout for pending timer */ - case PGM_TIME_REMAIN: - if (PGM_UNLIKELY(!sock->is_connected)) - break; - if (PGM_UNLIKELY(*optlen != sizeof (struct timeval))) - break; - { - struct timeval* tv = optval; - const pgm_time_t usecs = pgm_timer_expiration (sock); - tv->tv_sec = usecs / 1000000UL; - tv->tv_usec = usecs % 1000000UL; - } - status = TRUE; - break; - -/* timeout for blocking sends */ - case PGM_RATE_REMAIN: - if (PGM_UNLIKELY(!sock->is_connected)) - break; - if (PGM_UNLIKELY(*optlen != sizeof (struct timeval))) - break; - { - struct timeval* tv = optval; - const pgm_time_t usecs = pgm_rate_remaining (&sock->rate_control, sock->blocklen); - tv->tv_sec = usecs / 1000000UL; - tv->tv_usec = usecs % 1000000UL; - } - status = TRUE; - break; - - - } - pgm_rwlock_reader_unlock (&sock->lock); - return status; -} - -bool -pgm_setsockopt ( - pgm_sock_t* const sock, - const int optname, - const void* optval, - const socklen_t optlen - ) -{ - bool status = FALSE; - pgm_return_val_if_fail (sock != NULL, status); - if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) - pgm_return_val_if_reached (status); - if (PGM_UNLIKELY(sock->is_connected || sock->is_destroyed)) { - pgm_rwlock_reader_unlock (&sock->lock); - return status; - } - switch (optname) { - -/* RFC2113 IP Router Alert - */ - case PGM_IP_ROUTER_ALERT: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - { - const bool v = (0 != *(const int*)optval); - if (PGM_SOCKET_ERROR == pgm_sockaddr_router_alert (sock->send_with_router_alert_sock, sock->family, v)) - break; - } - status = TRUE; - break; - -/* IPv4: 68 <= tpdu < 65536 (RFC 2765) - * IPv6: 1280 <= tpdu < 65536 (RFC 2460) - */ - case PGM_MTU: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval < (sizeof(struct pgm_ip) + sizeof(struct pgm_header)))) - break; - if (PGM_UNLIKELY(*(const int*)optval > UINT16_MAX)) - break; - sock->max_tpdu = *(const int*)optval; - status = TRUE; - break; - -/* 1 = enable multicast loopback. - * 0 = default, to disable. - */ - case PGM_MULTICAST_LOOP: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - { - const bool v = (0 != *(const int*)optval); -#ifndef _WIN32 /* loop on send */ - if (PGM_SOCKET_ERROR == pgm_sockaddr_multicast_loop (sock->send_sock, sock->family, v) || - PGM_SOCKET_ERROR == pgm_sockaddr_multicast_loop (sock->send_with_router_alert_sock, sock->family, v)) - break; -#else /* loop on receive */ - if (PGM_SOCKET_ERROR == pgm_sockaddr_multicast_loop (sock->recv_sock, sock->family, v)) - break; -#endif - } - status = TRUE; - break; - -/* 0 < hops < 256, hops == -1 use kernel default (ignored). - */ - case PGM_MULTICAST_HOPS: -#ifndef CONFIG_TARGET_WINE - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - if (PGM_UNLIKELY(*(const int*)optval > UINT8_MAX)) - break; - { - const unsigned hops = *(const int*)optval; - if (PGM_SOCKET_ERROR == pgm_sockaddr_multicast_hops (sock->send_sock, sock->family, hops) || - PGM_SOCKET_ERROR == pgm_sockaddr_multicast_hops (sock->send_with_router_alert_sock, sock->family, hops)) - break; - } -#endif - status = TRUE; - break; - -/* IP Type of Service (ToS) or RFC 3246, differentiated services (DSCP) - */ - case PGM_TOS: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_SOCKET_ERROR == pgm_sockaddr_tos (sock->send_sock, sock->family, *(const int*)optval) || - PGM_SOCKET_ERROR == pgm_sockaddr_tos (sock->send_with_router_alert_sock, sock->family, *(const int*)optval)) - { - pgm_warn (_("ToS/DSCP setting requires CAP_NET_ADMIN or ADMIN capability.")); - break; - } - status = TRUE; - break; - -/* 0 < wmem < wmem_max (user) - * - * operating system and sysctl dependent maximum, minimum on Linux 256 (doubled). - */ - case PGM_SNDBUF: - if (PGM_SOCKET_ERROR == setsockopt (sock->send_sock, SOL_SOCKET, SO_SNDBUF, (const char*)optval, optlen) || - PGM_SOCKET_ERROR == setsockopt (sock->send_with_router_alert_sock, SOL_SOCKET, SO_SNDBUF, (const char*)optval, optlen)) - break; - status = TRUE; - break; - -/* 0 < rmem < rmem_max (user) - * - * minimum on Linux is 2048 (doubled). - */ - case PGM_RCVBUF: - if (PGM_SOCKET_ERROR == setsockopt (sock->recv_sock, SOL_SOCKET, SO_RCVBUF, (const char*)optval, optlen)) - break; - status = TRUE; - break; - -/* periodic ambient broadcast SPM interval in milliseconds. - */ - case PGM_AMBIENT_SPM: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - sock->spm_ambient_interval = *(const int*)optval; - status = TRUE; - break; - -/* sequence of heartbeat broadcast SPMS to flush out original - */ - case PGM_HEARTBEAT_SPM: - if (PGM_UNLIKELY(0 != optlen % sizeof (int))) - break; - { - sock->spm_heartbeat_len = optlen / sizeof (int); - sock->spm_heartbeat_interval = pgm_new (unsigned, sock->spm_heartbeat_len + 1); - sock->spm_heartbeat_interval[0] = 0; - for (unsigned i = 0; i < sock->spm_heartbeat_len; i++) - sock->spm_heartbeat_interval[i + 1] = ((const int*)optval)[i]; - } - status = TRUE; - break; - -/* size of transmit window in sequence numbers. - * 0 < txw_sqns < one less than half sequence space - */ - case PGM_TXW_SQNS: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - if (PGM_UNLIKELY(*(const int*)optval >= ((UINT32_MAX/2)-1))) - break; - sock->txw_sqns = *(const int*)optval; - status = TRUE; - break; - -/* size of transmit window in seconds. - * 0 < secs < ( txw_sqns / txw_max_rte ) - */ - case PGM_TXW_SECS: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - sock->txw_secs = *(const int*)optval; - status = TRUE; - break; - -/* maximum transmit rate. - * 0 < txw_max_rte < interface capacity - * 10mb : 1250000 - * 100mb : 12500000 - * 1gb : 125000000 - */ - case PGM_TXW_MAX_RTE: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - sock->txw_max_rte = *(const int*)optval; - status = TRUE; - break; - -/* timeout for peers. - * 0 < 2 * spm_ambient_interval <= peer_expiry - */ - case PGM_PEER_EXPIRY: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - sock->peer_expiry = *(const int*)optval; - status = TRUE; - break; - -/* maximum back off range for listening for multicast SPMR. - * 0 < spmr_expiry < spm_ambient_interval - */ - case PGM_SPMR_EXPIRY: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - sock->spmr_expiry = *(const int*)optval; - status = TRUE; - break; - -/* size of receive window in sequence numbers. - * 0 < rxw_sqns < one less than half sequence space - */ - case PGM_RXW_SQNS: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - if (PGM_UNLIKELY(*(const int*)optval >= ((UINT32_MAX/2)-1))) - break; - sock->rxw_sqns = *(const int*)optval; - status = TRUE; - break; - -/* size of receive window in seconds. - * 0 < secs < ( rxw_sqns / rxw_max_rte ) - */ - case PGM_RXW_SECS: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - sock->rxw_secs = *(const int*)optval; - status = TRUE; - break; - -/* maximum receive rate, for determining window size with txw_secs. - * 0 < rxw_max_rte < interface capacity - */ - case PGM_RXW_MAX_RTE: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - sock->rxw_max_rte = *(const int*)optval; - status = TRUE; - break; - -/* maximum NAK back-off value nak_rb_ivl in milliseconds. - * 0 < nak_rb_ivl <= nak_bo_ivl - */ - case PGM_NAK_BO_IVL: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - sock->nak_bo_ivl = *(const int*)optval; - status = TRUE; - break; - -/* repeat interval prior to re-sending a NAK, in milliseconds. - */ - case PGM_NAK_RPT_IVL: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - sock->nak_rpt_ivl = *(const int*)optval; - status = TRUE; - break; - -/* interval waiting for repair data, in milliseconds. - */ - case PGM_NAK_RDATA_IVL: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - sock->nak_rdata_ivl = *(const int*)optval; - status = TRUE; - break; - -/* limit for data. - * 0 < nak_data_retries < 256 - */ - case PGM_NAK_DATA_RETRIES: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - if (PGM_UNLIKELY(*(const int*)optval > UINT8_MAX)) - break; - sock->nak_data_retries = *(const int*)optval; - status = TRUE; - break; - -/* limit for NAK confirms. - * 0 < nak_ncf_retries < 256 - */ - case PGM_NAK_NCF_RETRIES: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - if (PGM_UNLIKELY(*(const int*)optval > UINT8_MAX)) - break; - sock->nak_ncf_retries = *(const int*)optval; - status = TRUE; - break; - -/* Enable FEC for this sock, specifically Reed Solmon encoding RS(n,k), common - * setting is RS(255, 223). - * - * inputs: - * - * n = FEC Block size = [k+1, 255] - * k = original data packets == transmission group size = [2, 4, 8, 16, 32, 64, 128] - * m = symbol size = 8 bits - * - * outputs: - * - * h = 2t = n - k = parity packets - * - * when h > k parity packets can be lost. - */ - case PGM_USE_FEC: - if (PGM_UNLIKELY(optlen != sizeof (struct pgm_fecinfo_t))) - break; - { - const struct pgm_fecinfo_t* fecinfo = optval; - if (PGM_UNLIKELY(0 != (fecinfo->group_size & (fecinfo->group_size - 1)))) - break; - if (PGM_UNLIKELY(fecinfo->group_size < 2 || fecinfo->group_size > 128)) - break; - if (PGM_UNLIKELY(fecinfo->group_size > fecinfo->block_size)) - break; - const uint8_t parity_packets = fecinfo->block_size - fecinfo->group_size; -/* technically could re-send previous packets */ - if (PGM_UNLIKELY(fecinfo->proactive_packets > parity_packets)) - break; -/* check validity of parameters */ - if (PGM_UNLIKELY(fecinfo->group_size > 223 && ((parity_packets * 223.0) / fecinfo->group_size) < 1.0)) - { - pgm_error (_("k/h ratio too low to generate parity data.")); - break; - } - sock->use_proactive_parity = (fecinfo->proactive_packets > 0); - sock->use_ondemand_parity = fecinfo->ondemand_parity_enabled; - sock->use_var_pktlen = fecinfo->var_pktlen_enabled; - sock->rs_n = fecinfo->block_size; - sock->rs_k = fecinfo->group_size; - sock->rs_proactive_h = fecinfo->proactive_packets; - } - status = TRUE; - break; - -/* congestion reporting */ - case PGM_USE_CR: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - if (PGM_UNLIKELY(*(const int*)optval <= 0)) - break; - sock->crqst_ivl = *(const int*)optval; - sock->use_cr = (sock->crqst_ivl > 0); - status = TRUE; - break; - -/* congestion control */ - case PGM_USE_PGMCC: - if (PGM_UNLIKELY(optlen != sizeof (struct pgm_pgmccinfo_t))) - break; - { - const struct pgm_pgmccinfo_t* pgmccinfo = optval; - sock->ack_bo_ivl = pgmccinfo->ack_bo_ivl; - sock->ack_c = pgmccinfo->ack_c; - sock->ack_c_p = pgmccinfo->ack_c_p; - sock->use_pgmcc = (sock->ack_c > 0); - } - status = TRUE; - break; - -/* declare socket only for sending, discard any incoming SPM, ODATA, - * RDATA, etc, packets. - */ - case PGM_SEND_ONLY: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - sock->can_recv_data = (0 == *(const int*)optval); - status = TRUE; - break; - -/* declare socket only for receiving, no transmit window will be created - * and no SPM broadcasts sent. - */ - case PGM_RECV_ONLY: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - sock->can_send_data = (0 == *(const int*)optval); - status = TRUE; - break; - -/* passive receiving socket, i.e. no back channel to source - */ - case PGM_PASSIVE: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - sock->can_send_nak = (0 == *(const int*)optval); - status = TRUE; - break; - -/* on unrecoverable data loss stop socket from further transmission and - * receiving. - */ - case PGM_ABORT_ON_RESET: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - sock->is_abort_on_reset = (0 != *(const int*)optval); - status = TRUE; - break; - -/* default non-blocking operation on send and receive sockets. - */ - case PGM_NOBLOCK: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - sock->is_nonblocking = (0 != *(const int*)optval); - pgm_sockaddr_nonblocking (sock->recv_sock, sock->is_nonblocking); - pgm_sockaddr_nonblocking (sock->send_sock, sock->is_nonblocking); - pgm_sockaddr_nonblocking (sock->send_with_router_alert_sock, sock->is_nonblocking); - status = TRUE; - break; - -/* sending group, singular. - */ - case PGM_SEND_GROUP: - if (PGM_UNLIKELY(optlen != sizeof(struct group_req))) - break; - memcpy (&sock->send_gsr, optval, optlen); - ((struct sockaddr_in*)&sock->send_gsr.gsr_group)->sin_port = htons (sock->udp_encap_mcast_port); - if (PGM_UNLIKELY(sock->family != sock->send_gsr.gsr_group.ss_family)) - break; - if (PGM_SOCKET_ERROR == pgm_sockaddr_multicast_if (sock->send_sock, (const struct sockaddr*)&sock->send_gsr.gsr_group, sock->send_gsr.gsr_interface) || - PGM_SOCKET_ERROR == pgm_sockaddr_multicast_if (sock->send_with_router_alert_sock, (const struct sockaddr*)&sock->send_gsr.gsr_group, sock->send_gsr.gsr_interface)) - break; - status = TRUE; - break; - -/* for any-source applications (ASM), join a new group - */ - case PGM_JOIN_GROUP: - if (PGM_UNLIKELY(optlen != sizeof(struct group_req))) - break; - if (PGM_UNLIKELY(sock->recv_gsr_len >= IP_MAX_MEMBERSHIPS)) - break; - { - const struct group_req* gr = optval; -/* verify not duplicate group/interface pairing */ - for (unsigned i = 0; i < sock->recv_gsr_len; i++) - { - if (pgm_sockaddr_cmp ((const struct sockaddr*)&gr->gr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0 && - pgm_sockaddr_cmp ((const struct sockaddr*)&gr->gr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_source) == 0 && - (gr->gr_interface == sock->recv_gsr[i].gsr_interface || - 0 == sock->recv_gsr[i].gsr_interface )) - { -#ifdef SOCKET_DEBUG - char s[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((const struct sockaddr*)&gr->gr_group, s, sizeof(s)); - if (sock->recv_gsr[i].gsr_interface) { - pgm_warn(_("Socket has already joined group %s on interface %u"), s, gr->gr_interface); - } else { - pgm_warn(_("Socket has already joined group %s on all interfaces."), s); - } -#endif - break; - } - } - if (PGM_UNLIKELY(sock->family != gr->gr_group.ss_family)) - break; - if (PGM_SOCKET_ERROR == pgm_sockaddr_join_group (sock->recv_sock, sock->family, gr)) - break; - sock->recv_gsr[sock->recv_gsr_len].gsr_interface = gr->gr_interface; - memcpy (&sock->recv_gsr[sock->recv_gsr_len].gsr_group, &gr->gr_group, pgm_sockaddr_len ((const struct sockaddr*)&gr->gr_group)); - memcpy (&sock->recv_gsr[sock->recv_gsr_len].gsr_source, &gr->gr_group, pgm_sockaddr_len ((const struct sockaddr*)&gr->gr_group)); - sock->recv_gsr_len++; - } - status = TRUE; - break; - -/* for any-source applications (ASM), leave a joined group. - */ - case PGM_LEAVE_GROUP: - if (PGM_UNLIKELY(optlen != sizeof(struct group_req))) - break; - if (PGM_UNLIKELY(0 == sock->recv_gsr_len)) - break; - { - const struct group_req* gr = optval; - for (unsigned i = 0; i < sock->recv_gsr_len;) - { - if ((pgm_sockaddr_cmp ((const struct sockaddr*)&gr->gr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0) && -/* drop all matching receiver entries */ - (gr->gr_interface == 0 || -/* drop all sources with matching interface */ - gr->gr_interface == sock->recv_gsr[i].gsr_interface) ) - { - sock->recv_gsr_len--; - if (i < (IP_MAX_MEMBERSHIPS - 1)) - { - memmove (&sock->recv_gsr[i], &sock->recv_gsr[i+1], (sock->recv_gsr_len - i) * sizeof(struct group_source_req)); - continue; - } - } - i++; - } - if (PGM_UNLIKELY(sock->family != gr->gr_group.ss_family)) - break; - if (PGM_SOCKET_ERROR == pgm_sockaddr_leave_group (sock->recv_sock, sock->family, gr)) - break; - } - status = TRUE; - break; - -/* for any-source applications (ASM), turn off a given source - */ - case PGM_BLOCK_SOURCE: - if (PGM_UNLIKELY(optlen != sizeof(struct group_source_req))) - break; - { - const struct group_source_req* gsr = optval; - if (PGM_UNLIKELY(sock->family != gsr->gsr_group.ss_family)) - break; - if (PGM_SOCKET_ERROR == pgm_sockaddr_block_source (sock->recv_sock, sock->family, gsr)) - break; - } - status = TRUE; - break; - -/* for any-source applications (ASM), re-allow a blocked source - */ - case PGM_UNBLOCK_SOURCE: - if (PGM_UNLIKELY(optlen != sizeof(struct group_source_req))) - break; - { - const struct group_source_req* gsr = optval; - if (PGM_UNLIKELY(sock->family != gsr->gsr_group.ss_family)) - break; - if (PGM_SOCKET_ERROR == pgm_sockaddr_unblock_source (sock->recv_sock, sock->family, gsr)) - break; - } - status = TRUE; - break; - -/* for controlled-source applications (SSM), join each group/source pair. - * - * SSM joins are allowed on top of ASM in order to merge a remote source onto the local segment. - */ - case PGM_JOIN_SOURCE_GROUP: - if (PGM_UNLIKELY(optlen != sizeof(struct group_source_req))) - break; - if (PGM_UNLIKELY(sock->recv_gsr_len >= IP_MAX_MEMBERSHIPS)) - break; - { - const struct group_source_req* gsr = optval; -/* verify if existing group/interface pairing */ - for (unsigned i = 0; i < sock->recv_gsr_len; i++) - { - if (pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0 && - (gsr->gsr_interface == sock->recv_gsr[i].gsr_interface || - 0 == sock->recv_gsr[i].gsr_interface )) - { - if (pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_source, (struct sockaddr*)&sock->recv_gsr[i].gsr_source) == 0) - { -#ifdef SOCKET_DEBUG - char s1[INET6_ADDRSTRLEN], s2[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((const struct sockaddr*)&gsr->gsr_group, s1, sizeof(s1)); - pgm_sockaddr_ntop ((const struct sockaddr*)&gsr->gsr_source, s2, sizeof(s2)); - if (sock->recv_gsr[i].gsr_interface) { - pgm_warn(_("Socket has already joined group %s from source %s on interface %d"), - s1, s2, (unsigned)gsr->gsr_interface); - } else { - pgm_warn(_("Socket has already joined group %s from source %s on all interfaces"), - s1, s2); - } -#endif - break; - } - break; - } - } - if (PGM_UNLIKELY(sock->family != gsr->gsr_group.ss_family)) - break; - if (PGM_UNLIKELY(sock->family != gsr->gsr_source.ss_family)) - break; - if (PGM_SOCKET_ERROR == pgm_sockaddr_join_source_group (sock->recv_sock, sock->family, gsr)) - break; - memcpy (&sock->recv_gsr[sock->recv_gsr_len], gsr, sizeof(struct group_source_req)); - sock->recv_gsr_len++; - } - status = TRUE; - break; - -/* for controlled-source applications (SSM), leave each group/source pair - */ - case PGM_LEAVE_SOURCE_GROUP: - if (PGM_UNLIKELY(optlen != sizeof(struct group_source_req))) - break; - if (PGM_UNLIKELY(0 == sock->recv_gsr_len)) - break; - { - const struct group_source_req* gsr = optval; -/* verify if existing group/interface pairing */ - for (unsigned i = 0; i < sock->recv_gsr_len; i++) - { - if (pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0 && - pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_source, (struct sockaddr*)&sock->recv_gsr[i].gsr_source) == 0 && - gsr->gsr_interface == sock->recv_gsr[i].gsr_interface) - { - sock->recv_gsr_len--; - if (i < (IP_MAX_MEMBERSHIPS - 1)) - { - memmove (&sock->recv_gsr[i], &sock->recv_gsr[i+1], (sock->recv_gsr_len - i) * sizeof(struct group_source_req)); - break; - } - } - } - if (PGM_UNLIKELY(sock->family != gsr->gsr_group.ss_family)) - break; - if (PGM_UNLIKELY(sock->family != gsr->gsr_source.ss_family)) - break; - if (PGM_SOCKET_ERROR == pgm_sockaddr_leave_source_group (sock->recv_sock, sock->family, gsr)) - break; - } - status = TRUE; - break; - -/* batch block and unblock sources */ - case PGM_MSFILTER: -#if defined(MCAST_MSFILTER) || defined(SIOCSMSFILTER) - if (PGM_UNLIKELY(optlen < sizeof(struct group_filter))) - break; - { - const struct group_filter* gf_list = optval; - if (GROUP_FILTER_SIZE( gf_list->gf_numsrc ) != optlen) - break; - if (PGM_UNLIKELY(sock->family != gf_list->gf_group.ss_family)) - break; -/* check only first */ - if (PGM_UNLIKELY(sock->family != gf_list->gf_slist[0].ss_family)) - break; - if (PGM_SOCKET_ERROR == pgm_sockaddr_msfilter (sock->recv_sock, sock->family, gf_list)) - break; - } - status = TRUE; -#endif - break; - -/* UDP encapsulation ports */ - case PGM_UDP_ENCAP_UCAST_PORT: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - sock->udp_encap_ucast_port = *(const int*)optval; - status = TRUE; - break; - - case PGM_UDP_ENCAP_MCAST_PORT: - if (PGM_UNLIKELY(optlen != sizeof (int))) - break; - sock->udp_encap_mcast_port = *(const int*)optval; - status = TRUE; - break; - - } - - pgm_rwlock_reader_unlock (&sock->lock); - return status; -} - -bool -pgm_bind ( - pgm_sock_t* restrict sock, - const struct pgm_sockaddr_t*const restrict sockaddr, - const socklen_t sockaddrlen, - pgm_error_t** restrict error - ) -{ - struct pgm_interface_req_t null_req; - memset (&null_req, 0, sizeof(null_req)); - return pgm_bind3 (sock, sockaddr, sockaddrlen, &null_req, sizeof(null_req), &null_req, sizeof(null_req), error); -} - -/* bind the sockets to the link layer to start receiving data. - * - * returns TRUE on success, or FALSE on error and sets error appropriately, - */ - -bool -pgm_bind3 ( - pgm_sock_t* restrict sock, - const struct pgm_sockaddr_t* restrict sockaddr, - const socklen_t sockaddrlen, - const struct pgm_interface_req_t* send_req, /* only use gr_interface and gr_group::sin6_scope */ - const socklen_t send_req_len, - const struct pgm_interface_req_t* recv_req, - const socklen_t recv_req_len, - pgm_error_t** restrict error /* maybe NULL */ - ) -{ - pgm_return_val_if_fail (NULL != sock, FALSE); - pgm_return_val_if_fail (NULL != sockaddr, FALSE); - pgm_return_val_if_fail (0 != sockaddrlen, FALSE); - if (sockaddr->sa_addr.sport) pgm_return_val_if_fail (sockaddr->sa_addr.sport != sockaddr->sa_port, FALSE); - pgm_return_val_if_fail (NULL != send_req, FALSE); - pgm_return_val_if_fail (sizeof(struct pgm_interface_req_t) == send_req_len, FALSE); - pgm_return_val_if_fail (NULL != recv_req, FALSE); - pgm_return_val_if_fail (sizeof(struct pgm_interface_req_t) == recv_req_len, FALSE); - - if (!pgm_rwlock_writer_trylock (&sock->lock)) - pgm_return_val_if_reached (FALSE); - if (sock->is_bound || - sock->is_destroyed) - { - pgm_rwlock_writer_unlock (&sock->lock); - pgm_return_val_if_reached (FALSE); - } - -/* sanity checks on state */ - if (sock->max_tpdu < (sizeof(struct pgm_ip) + sizeof(struct pgm_header))) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("Invalid maximum TPDU size.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (sock->can_send_data) { - if (PGM_UNLIKELY(0 == sock->spm_ambient_interval)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("SPM ambient interval not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (PGM_UNLIKELY(0 == sock->spm_heartbeat_len)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("SPM heartbeat interval not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (PGM_UNLIKELY(0 == sock->txw_sqns && 0 == sock->txw_secs)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("TXW_SQNS not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (PGM_UNLIKELY(0 == sock->txw_sqns && 0 == sock->txw_max_rte)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("TXW_MAX_RTE not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - } - if (sock->can_recv_data) { - if (PGM_UNLIKELY(0 == sock->rxw_sqns && 0 == sock->rxw_secs)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("RXW_SQNS not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (PGM_UNLIKELY(0 == sock->rxw_sqns && 0 == sock->rxw_max_rte)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("RXW_MAX_RTE not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (PGM_UNLIKELY(0 == sock->peer_expiry)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("Peer timeout not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (PGM_UNLIKELY(0 == sock->spmr_expiry)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("SPM-Request timeout not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (PGM_UNLIKELY(0 == sock->nak_bo_ivl)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("NAK_BO_IVL not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (PGM_UNLIKELY(0 == sock->nak_rpt_ivl)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("NAK_RPT_IVL not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (PGM_UNLIKELY(0 == sock->nak_rdata_ivl)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("NAK_RDATA_IVL not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (PGM_UNLIKELY(0 == sock->nak_data_retries)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("NAK_DATA_RETRIES not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (PGM_UNLIKELY(0 == sock->nak_ncf_retries)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - PGM_ERROR_FAILED, - _("NAK_NCF_RETRIES not configured.")); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - } - - pgm_debug ("bind3 (sock:%p sockaddr:%p sockaddrlen:%u send-req:%p send-req-len:%u recv-req:%p recv-req-len:%u error:%p)", - (const void*)sock, (const void*)sockaddr, (unsigned)sockaddrlen, (const void*)send_req, (unsigned)send_req_len, (const void*)recv_req, (unsigned)recv_req_len, (const void*)error); - - memcpy (&sock->tsi, &sockaddr->sa_addr, sizeof(pgm_tsi_t)); - sock->dport = htons (sockaddr->sa_port); - if (sock->tsi.sport) { - sock->tsi.sport = htons (sock->tsi.sport); - } else { - do { - sock->tsi.sport = htons (pgm_random_int_range (0, UINT16_MAX)); - } while (sock->tsi.sport == sock->dport); - } - -/* UDP encapsulation port */ - if (sock->udp_encap_mcast_port) { - ((struct sockaddr_in*)&sock->send_gsr.gsr_group)->sin_port = htons (sock->udp_encap_mcast_port); - } - -/* pseudo-random number generator for back-off intervals */ - pgm_rand_create (&sock->rand_); - -/* PGM Children support of POLLs requires 32-bit random node identifier RAND_NODE_ID */ - if (sock->can_recv_data) { - sock->rand_node_id = pgm_rand_int (&sock->rand_); - } - - if (sock->can_send_data) - { -/* Windows notify call will raise an assertion on error, only Unix versions will return - * a valid error. - */ - if (sock->use_pgmcc && - 0 != pgm_notify_init (&sock->ack_notify)) - { - const int save_errno = errno; - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_errno (save_errno), - _("Creating ACK notification channel: %s"), - strerror (save_errno)); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - if (0 != pgm_notify_init (&sock->rdata_notify)) - { - const int save_errno = errno; - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_errno (save_errno), - _("Creating RDATA notification channel: %s"), - strerror (save_errno)); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - } - if (0 != pgm_notify_init (&sock->pending_notify)) - { - const int save_errno = errno; - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_errno (save_errno), - _("Creating waiting peer notification channel: %s"), - strerror (save_errno)); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - -/* determine IP header size for rate regulation engine & stats */ - sock->iphdr_len = (AF_INET == sock->family) ? sizeof(struct pgm_ip) : sizeof(struct pgm_ip6_hdr); - pgm_trace (PGM_LOG_ROLE_NETWORK,"Assuming IP header size of %zu bytes", sock->iphdr_len); - - if (sock->udp_encap_ucast_port) { - const size_t udphdr_len = sizeof(struct pgm_udphdr); - pgm_trace (PGM_LOG_ROLE_NETWORK,"Assuming UDP header size of %zu bytes", udphdr_len); - sock->iphdr_len += udphdr_len; - } - - const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; - sock->max_tsdu = sock->max_tpdu - sock->iphdr_len - pgm_pkt_offset (FALSE, pgmcc_family); - sock->max_tsdu_fragment = sock->max_tpdu - sock->iphdr_len - pgm_pkt_offset (TRUE, pgmcc_family); - const unsigned max_fragments = sock->txw_sqns ? MIN( PGM_MAX_FRAGMENTS, sock->txw_sqns ) : PGM_MAX_FRAGMENTS; - sock->max_apdu = MIN( PGM_MAX_APDU, max_fragments * sock->max_tsdu_fragment ); - - if (sock->can_send_data) - { - pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Create transmit window.")); - sock->window = sock->txw_sqns ? - pgm_txw_create (&sock->tsi, - 0, /* MAX_TPDU */ - sock->txw_sqns, /* TXW_SQNS */ - 0, /* TXW_SECS */ - 0, /* TXW_MAX_RTE */ - sock->use_ondemand_parity || sock->use_proactive_parity, - sock->rs_n, - sock->rs_k) : - pgm_txw_create (&sock->tsi, - sock->max_tpdu, /* MAX_TPDU */ - 0, /* TXW_SQNS */ - sock->txw_secs, /* TXW_SECS */ - sock->txw_max_rte, /* TXW_MAX_RTE */ - sock->use_ondemand_parity || sock->use_proactive_parity, - sock->rs_n, - sock->rs_k); - pgm_assert (NULL != sock->window); - } - -/* create peer list */ - if (sock->can_recv_data) { - sock->peers_hashtable = pgm_hashtable_new (pgm_tsi_hash, pgm_tsi_equal); - pgm_assert (NULL != sock->peers_hashtable); - } - - if (IPPROTO_UDP == sock->protocol) - { -/* Stevens: "SO_REUSEADDR has datatype int." - */ - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Set socket sharing.")); - const int v = 1; - if (PGM_SOCKET_ERROR == setsockopt (sock->recv_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&v, sizeof(v)) || - PGM_SOCKET_ERROR == setsockopt (sock->send_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&v, sizeof(v)) || - PGM_SOCKET_ERROR == setsockopt (sock->send_with_router_alert_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&v, sizeof(v))) - { - const int save_errno = pgm_sock_errno(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_sock_errno (save_errno), - _("Enabling reuse of socket local address: %s"), - pgm_sock_strerror (save_errno)); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - -/* request extra packet information to determine destination address on each packet */ -#ifndef CONFIG_TARGET_WINE - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Request socket packet-info.")); - const sa_family_t recv_family = sock->family; - if (PGM_SOCKET_ERROR == pgm_sockaddr_pktinfo (sock->recv_sock, recv_family, TRUE)) - { - const int save_errno = pgm_sock_errno(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_sock_errno (save_errno), - _("Enabling receipt of ancillary information per incoming packet: %s"), - pgm_sock_strerror (save_errno)); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } -#endif - } - else - { - const sa_family_t recv_family = sock->family; - if (AF_INET == recv_family) - { -/* include IP header only for incoming data, only works for IPv4 */ - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Request IP headers.")); - if (PGM_SOCKET_ERROR == pgm_sockaddr_hdrincl (sock->recv_sock, recv_family, TRUE)) - { - const int save_errno = pgm_sock_errno(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_sock_errno (save_errno), - _("Enabling IP header in front of user data: %s"), - pgm_sock_strerror (save_errno)); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - } - else - { - pgm_assert (AF_INET6 == recv_family); - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Request socket packet-info.")); - if (PGM_SOCKET_ERROR == pgm_sockaddr_pktinfo (sock->recv_sock, recv_family, TRUE)) - { - const int save_errno = pgm_sock_errno(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_sock_errno (save_errno), - _("Enabling receipt of control message per incoming datagram: %s"), - pgm_sock_strerror (save_errno)); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - } - } - -/* Bind UDP sockets to interfaces, note multicast on a bound interface is - * fruity on some platforms. Roughly, binding to INADDR_ANY provides all - * data, binding to the multicast group provides only multicast traffic, - * and binding to the interface address provides only unicast traffic. - * - * Multicast routing, IGMP & MLD require a link local address, for IPv4 - * this is provided through MULTICAST_IF and IPv6 through bind, and these - * may be overridden by per packet scopes. - * - * After binding, default interfaces (0.0.0.0) are resolved. - */ -/* TODO: different ports requires a new bound socket */ - - union { - struct sockaddr sa; - struct sockaddr_in s4; - struct sockaddr_in6 s6; - struct sockaddr_storage ss; - } recv_addr, recv_addr2, send_addr, send_with_router_alert_addr; - -#ifdef CONFIG_BIND_INADDR_ANY -/* force default interface for bind-only, source address is still valid for multicast membership. - * effectively same as running getaddrinfo(hints = {ai_flags = AI_PASSIVE}) - */ - if (AF_INET == sock->family) { - memset (&recv_addr.s4, 0, sizeof(struct sockaddr_in)); - recv_addr.s4.sin_family = AF_INET; - recv_addr.s4.sin_addr.s_addr = INADDR_ANY; - } else { - memset (&recv_addr.s6, 0, sizeof(struct sockaddr_in6)); - recv_addr.s6.sin6_family = AF_INET6; - recv_addr.s6.sin6_addr = in6addr_any; - } - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Binding receive socket to INADDR_ANY.")); -#else - if (!pgm_if_indextoaddr (recv_req->ir_interface, - sock->family, - recv_req->ir_scope_id, - &recv_addr.sa, - error)) - { - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Binding receive socket to interface index %u scope %u"), - recv_req->ir_interface, - recv_req->ir_scope_id); - -#endif /* CONFIG_BIND_INADDR_ANY */ - - memcpy (&recv_addr2.sa, &recv_addr.sa, pgm_sockaddr_len (&recv_addr.sa)); - ((struct sockaddr_in*)&recv_addr)->sin_port = htons (sock->udp_encap_mcast_port); - if (PGM_SOCKET_ERROR == bind (sock->recv_sock, - &recv_addr.sa, - pgm_sockaddr_len (&recv_addr.sa))) - { - char addr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&recv_addr, addr, sizeof(addr)); - const int save_errno = pgm_sock_errno(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_sock_errno (save_errno), - _("Binding receive socket to address %s: %s"), - addr, - pgm_sock_strerror (save_errno)); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - - if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) - { - char s[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&recv_addr, s, sizeof(s)); - pgm_debug ("bind succeeded on recv_gsr[0] interface %s", s); - } - -/* keep a copy of the original address source to re-use for router alert bind */ - memset (&send_addr, 0, sizeof(send_addr)); - - if (!pgm_if_indextoaddr (send_req->ir_interface, - sock->family, - send_req->ir_scope_id, - (struct sockaddr*)&send_addr, - error)) - { - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - else if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) - { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Binding send socket to interface index %u scope %u"), - send_req->ir_interface, - send_req->ir_scope_id); - } - - memcpy (&send_with_router_alert_addr, &send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)); - if (PGM_SOCKET_ERROR == bind (sock->send_sock, - (struct sockaddr*)&send_addr, - pgm_sockaddr_len ((struct sockaddr*)&send_addr))) - { - char addr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&send_addr, addr, sizeof(addr)); - const int save_errno = pgm_sock_errno(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_sock_errno (save_errno), - _("Binding send socket to address %s: %s"), - addr, - pgm_sock_strerror (save_errno)); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - -/* resolve bound address if 0.0.0.0 */ - if (AF_INET == send_addr.ss.ss_family) - { - if ((INADDR_ANY == ((struct sockaddr_in*)&send_addr)->sin_addr.s_addr) && - !pgm_if_getnodeaddr (AF_INET, (struct sockaddr*)&send_addr, sizeof(send_addr), error)) - { - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - } - else if ((memcmp (&in6addr_any, &((struct sockaddr_in6*)&send_addr)->sin6_addr, sizeof(in6addr_any)) == 0) && - !pgm_if_getnodeaddr (AF_INET6, (struct sockaddr*)&send_addr, sizeof(send_addr), error)) - { - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - - if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) - { - char s[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&send_addr, s, sizeof(s)); - pgm_debug ("bind succeeded on send_gsr interface %s", s); - } - - if (PGM_SOCKET_ERROR == bind (sock->send_with_router_alert_sock, - (struct sockaddr*)&send_with_router_alert_addr, - pgm_sockaddr_len((struct sockaddr*)&send_with_router_alert_addr))) - { - char addr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&send_with_router_alert_addr, addr, sizeof(addr)); - const int save_errno = pgm_sock_errno(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_sock_errno (save_errno), - _("Binding IP Router Alert (RFC 2113) send socket to address %s: %s"), - addr, - pgm_sock_strerror (save_errno)); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - - if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) - { - char s[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&send_with_router_alert_addr, s, sizeof(s)); - pgm_debug ("bind (router alert) succeeded on send_gsr interface %s", s); - } - -/* save send side address for broadcasting as source nla */ - memcpy (&sock->send_addr, &send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)); - -/* rx to nak processor notify channel */ - if (sock->can_send_data) - { -/* setup rate control */ - if (sock->txw_max_rte) - { - pgm_trace (PGM_LOG_ROLE_RATE_CONTROL,_("Setting rate regulation to %zd bytes per second."), - sock->txw_max_rte); - - pgm_rate_create (&sock->rate_control, sock->txw_max_rte, sock->iphdr_len, sock->max_tpdu); - sock->is_controlled_spm = TRUE; /* must always be set */ - sock->is_controlled_odata = TRUE; - sock->is_controlled_rdata = TRUE; - } - else - { - sock->is_controlled_spm = FALSE; - sock->is_controlled_odata = FALSE; - sock->is_controlled_rdata = FALSE; - } - } - -/* allocate first incoming packet buffer */ - sock->rx_buffer = pgm_alloc_skb (sock->max_tpdu); - -/* bind complete */ - sock->is_bound = TRUE; - -/* cleanup */ - pgm_rwlock_writer_unlock (&sock->lock); - pgm_debug ("PGM socket successfully bound."); - return TRUE; -} - -bool -pgm_connect ( - pgm_sock_t* restrict sock, - pgm_error_t** restrict error /* maybe NULL */ - ) -{ - pgm_return_val_if_fail (sock != NULL, FALSE); - pgm_return_val_if_fail (sock->recv_gsr_len > 0, FALSE); -#ifdef CONFIG_TARGET_WINE - pgm_return_val_if_fail (sock->recv_gsr_len == 1, FALSE); -#endif - for (unsigned i = 0; i < sock->recv_gsr_len; i++) - { - pgm_return_val_if_fail (sock->recv_gsr[i].gsr_group.ss_family == sock->recv_gsr[0].gsr_group.ss_family, FALSE); - pgm_return_val_if_fail (sock->recv_gsr[i].gsr_group.ss_family == sock->recv_gsr[i].gsr_source.ss_family, FALSE); - } - pgm_return_val_if_fail (sock->send_gsr.gsr_group.ss_family == sock->recv_gsr[0].gsr_group.ss_family, FALSE); -/* shutdown */ - if (PGM_UNLIKELY(!pgm_rwlock_writer_trylock (&sock->lock))) - pgm_return_val_if_reached (FALSE); -/* state */ - if (PGM_UNLIKELY(sock->is_connected || !sock->is_bound || sock->is_destroyed)) { - pgm_rwlock_writer_unlock (&sock->lock); - pgm_return_val_if_reached (FALSE); - } - - pgm_debug ("connect (sock:%p error:%p)", - (const void*)sock, (const void*)error); - -/* rx to nak processor notify channel */ - if (sock->can_send_data) - { -/* announce new sock by sending out SPMs */ - if (!pgm_send_spm (sock, PGM_OPT_SYN) || - !pgm_send_spm (sock, PGM_OPT_SYN) || - !pgm_send_spm (sock, PGM_OPT_SYN)) - { - const int save_errno = pgm_sock_errno(); - pgm_set_error (error, - PGM_ERROR_DOMAIN_SOCKET, - pgm_error_from_sock_errno (save_errno), - _("Sending SPM broadcast: %s"), - pgm_sock_strerror (save_errno)); - pgm_rwlock_writer_unlock (&sock->lock); - return FALSE; - } - - sock->next_poll = sock->next_ambient_spm = pgm_time_update_now() + sock->spm_ambient_interval; - -/* start PGMCC with one token */ - sock->tokens = sock->cwnd_size = pgm_fp8 (1); - -/* slow start threshold */ - sock->ssthresh = pgm_fp8 (4); - -/* ACK timeout, should be greater than first SPM heartbeat interval in order to be scheduled correctly */ - sock->ack_expiry_ivl = pgm_secs (3); - -/* start full history */ - sock->ack_bitmap = 0xffffffff; - } - else - { - pgm_assert (sock->can_recv_data); - sock->next_poll = pgm_time_update_now() + pgm_secs( 30 ); - } - - sock->is_connected = TRUE; - -/* cleanup */ - pgm_rwlock_writer_unlock (&sock->lock); - pgm_debug ("PGM socket successfully connected."); - return TRUE; -} - -/* return local endpoint address - */ - -bool -pgm_getsockname ( - pgm_sock_t* const restrict sock, - struct pgm_sockaddr_t* restrict addr, - socklen_t* restrict addrlen - ) -{ - pgm_assert (NULL != sock); - pgm_assert (NULL != addr); - pgm_assert (NULL != addrlen); - pgm_assert (sizeof(struct pgm_sockaddr_t) == *addrlen); - - if (!sock->is_bound) { - errno = EBADF; - return FALSE; - } - - addr->sa_port = sock->dport; - memcpy (&addr->sa_addr, &sock->tsi, sizeof(pgm_tsi_t)); - return TRUE; -} - -/* add select parameters for the receive socket(s) - * - * returns highest file descriptor used plus one. - */ - -int -pgm_select_info ( - pgm_sock_t* const restrict sock, - fd_set* const restrict readfds, /* blocking recv fds */ - fd_set* const restrict writefds, /* blocking send fds */ - int* const restrict n_fds /* in: max fds, out: max (in:fds, sock:fds) */ - ) -{ - int fds = 0; - - pgm_assert (NULL != sock); - pgm_assert (NULL != n_fds); - - if (!sock->is_bound || sock->is_destroyed) - { - errno = EBADF; - return -1; - } - - const bool is_congested = (sock->use_pgmcc && sock->tokens < pgm_fp8 (1)) ? TRUE : FALSE; - - if (readfds) - { - FD_SET(sock->recv_sock, readfds); - fds = sock->recv_sock + 1; - if (sock->can_send_data) { - const int rdata_fd = pgm_notify_get_fd (&sock->rdata_notify); - FD_SET(rdata_fd, readfds); - fds = MAX(fds, rdata_fd + 1); - if (is_congested) { - const int ack_fd = pgm_notify_get_fd (&sock->ack_notify); - FD_SET(ack_fd, readfds); - fds = MAX(fds, ack_fd + 1); - } - } - const int pending_fd = pgm_notify_get_fd (&sock->pending_notify); - FD_SET(pending_fd, readfds); - fds = MAX(fds, pending_fd + 1); - } - - if (sock->can_send_data && writefds && !is_congested) - { - FD_SET(sock->send_sock, writefds); - fds = MAX(sock->send_sock + 1, fds); - } - - return *n_fds = MAX(fds, *n_fds); -} - -#ifdef CONFIG_HAVE_POLL -/* add poll parameters for the receive socket(s) - * - * returns number of pollfd structures filled. - */ - -int -pgm_poll_info ( - pgm_sock_t* const restrict sock, - struct pollfd* const restrict fds, - int* const restrict n_fds, /* in: #fds, out: used #fds */ - const int events /* POLLIN, POLLOUT */ - ) -{ - pgm_assert (NULL != sock); - pgm_assert (NULL != fds); - pgm_assert (NULL != n_fds); - - if (!sock->is_bound || sock->is_destroyed) - { - errno = EBADF; - return -1; - } - - int moo = 0; - -/* we currently only support one incoming socket */ - if (events & POLLIN) - { - pgm_assert ( (1 + moo) <= *n_fds ); - fds[moo].fd = sock->recv_sock; - fds[moo].events = POLLIN; - moo++; - if (sock->can_send_data) { - pgm_assert ( (1 + moo) <= *n_fds ); - fds[moo].fd = pgm_notify_get_fd (&sock->rdata_notify); - fds[moo].events = POLLIN; - moo++; - } - pgm_assert ( (1 + moo) <= *n_fds ); - fds[moo].fd = pgm_notify_get_fd (&sock->pending_notify); - fds[moo].events = POLLIN; - moo++; - } - -/* ODATA only published on regular socket, no need to poll router-alert sock */ - if (sock->can_send_data && events & POLLOUT) - { - pgm_assert ( (1 + moo) <= *n_fds ); - if (sock->use_pgmcc && sock->tokens < pgm_fp8 (1)) { -/* rx thread poll for ACK */ - fds[moo].fd = pgm_notify_get_fd (&sock->ack_notify); - fds[moo].events = POLLIN; - } else { -/* kernel resource poll */ - fds[moo].fd = sock->send_sock; - fds[moo].events = POLLOUT; - } - moo++; - } - - return *n_fds = moo; -} -#endif /* CONFIG_HAVE_POLL */ - -/* add epoll parameters for the recieve socket(s), events should - * be set to EPOLLIN to wait for incoming events (data), and EPOLLOUT to wait - * for non-blocking write. - * - * returns 0 on success, -1 on failure and sets errno appropriately. - */ -#ifdef CONFIG_HAVE_EPOLL -int -pgm_epoll_ctl ( - pgm_sock_t* const sock, - const int epfd, - const int op, /* EPOLL_CTL_ADD, ... */ - const int events /* EPOLLIN, EPOLLOUT */ - ) -{ - if (!(op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD)) - { - errno = EINVAL; - return -1; - } - else if (!sock->is_bound || sock->is_destroyed) - { - errno = EBADF; - return -1; - } - - struct epoll_event event; - int retval = 0; - - if (events & EPOLLIN) - { - event.events = events & (EPOLLIN | EPOLLET | EPOLLONESHOT); - event.data.ptr = sock; - retval = epoll_ctl (epfd, op, sock->recv_sock, &event); - if (retval) - goto out; - if (sock->can_send_data) { - retval = epoll_ctl (epfd, op, pgm_notify_get_fd (&sock->rdata_notify), &event); - if (retval) - goto out; - } - retval = epoll_ctl (epfd, op, pgm_notify_get_fd (&sock->pending_notify), &event); - if (retval) - goto out; - - if (events & EPOLLET) - sock->is_edge_triggered_recv = TRUE; - } - - if (sock->can_send_data && events & EPOLLOUT) - { - bool enable_ack_socket = FALSE; - bool enable_send_socket = FALSE; - -/* both sockets need to be added when PGMCC is enabled */ - if (sock->use_pgmcc && EPOLL_CTL_ADD == op) { - enable_ack_socket = enable_send_socket = TRUE; - } else { -/* automagically switch socket when congestion stall occurs */ - if (sock->use_pgmcc && sock->tokens < pgm_fp8 (1)) - enable_ack_socket = TRUE; - else - enable_send_socket = TRUE; - } - - if (enable_ack_socket) - { -/* rx thread poll for ACK */ - event.events = EPOLLIN | (events & (EPOLLONESHOT)); - event.data.ptr = sock; - retval = epoll_ctl (epfd, op, pgm_notify_get_fd (&sock->ack_notify), &event); - } - - if (enable_send_socket) - { -/* kernel resource poll */ - event.events = events & (EPOLLOUT | EPOLLET | EPOLLONESHOT); - event.data.ptr = sock; - retval = epoll_ctl (epfd, op, sock->send_sock, &event); - } - } -out: - return retval; -} -#endif - -static -const char* -pgm_family_string ( - const int family - ) -{ - const char* c; - - switch (family) { - case AF_UNSPEC: c = "AF_UNSPEC"; break; - case AF_INET: c = "AF_INET"; break; - case AF_INET6: c = "AF_INET6"; break; - default: c = "(unknown)"; break; - } - - return c; -} - -static -const char* -pgm_sock_type_string ( - const int sock_type - ) -{ - const char* c; - - switch (sock_type) { - case SOCK_SEQPACKET: c = "SOCK_SEQPACKET"; break; - default: c = "(unknown)"; break; - } - - return c; -} - -static -const char* -pgm_protocol_string ( - const int protocol - ) -{ - const char* c; - - switch (protocol) { - case IPPROTO_UDP: c = "IPPROTO_UDP"; break; - case IPPROTO_PGM: c = "IPPROTO_PGM"; break; - default: c = "(unknown)"; break; - } - - return c; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/socket_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/socket_unittest.c deleted file mode 100644 index 7f79f06..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/socket_unittest.c +++ /dev/null @@ -1,1186 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for PGM socket. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - - -/* mock state */ - -#define TEST_NETWORK "" -#define TEST_PORT 7500 -#define TEST_MAX_TPDU 1500 -#define TEST_TXW_SQNS 32 -#define TEST_RXW_SQNS 32 -#define TEST_HOPS 16 -#define TEST_SPM_AMBIENT ( pgm_secs(30) ) -#define TEST_SPM_HEARTBEAT_INIT { pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(1300), pgm_secs(7), pgm_secs(16), pgm_secs(25), pgm_secs(30) } -#define TEST_PEER_EXPIRY ( pgm_secs(300) ) -#define TEST_SPMR_EXPIRY ( pgm_msecs(250) ) -#define TEST_NAK_BO_IVL ( pgm_msecs(50) ) -#define TEST_NAK_RPT_IVL ( pgm_secs(2) ) -#define TEST_NAK_RDATA_IVL ( pgm_secs(2) ) -#define TEST_NAK_DATA_RETRIES 5 -#define TEST_NAK_NCF_RETRIES 2 - -#define pgm_ipproto_pgm mock_pgm_ipproto_pgm -#define pgm_peer_unref mock_pgm_peer_unref -#define pgm_on_nak_notify mock_pgm_on_nak_notify -#define pgm_send_spm mock_pgm_send_spm -#define pgm_timer_prepare mock_pgm_timer_prepare -#define pgm_timer_check mock_pgm_timer_check -#define pgm_timer_expiration mock_pgm_timer_expiration -#define pgm_timer_dispatch mock_pgm_timer_dispatch -#define pgm_txw_create mock_pgm_txw_create -#define pgm_txw_shutdown mock_pgm_txw_shutdown -#define pgm_rate_create mock_pgm_rate_create -#define pgm_rate_destroy mock_pgm_rate_destroy -#define pgm_rate_remaining mock_pgm_rate_remaining -#define pgm_rs_create mock_pgm_rs_create -#define pgm_rs_destroy mock_pgm_rs_destroy -#define pgm_time_update_now mock_pgm_time_update_now - -#define SOCK_DEBUG -#include "socket.c" - -int mock_pgm_ipproto_pgm = IPPROTO_PGM; - - -static -void -mock_setup (void) -{ - if (!g_thread_supported ()) g_thread_init (NULL); -} - -static -void -mock_teardown (void) -{ -} - -/* stock create pgm sockaddr structure for calls to pgm_bind() - */ - -static -struct pgm_sockaddr_t* -generate_asm_sockaddr (void) -{ - const pgm_gsi_t gsi = { 200, 202, 203, 204, 205, 206 }; - struct pgm_sockaddr_t* pgmsa = g_new0 (struct pgm_sockaddr_t, 1); - pgmsa->sa_port = 123; - memcpy (&pgmsa->sa_addr.gsi, &gsi, sizeof(gsi)); - return pgmsa; -} - -/* stock create unconnected socket for pgm_setsockopt(), etc. - */ - -static -struct pgm_sock_t* -generate_sock (void) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, g_htons(1000) }; - struct pgm_sock_t* sock = g_new0 (struct pgm_sock_t, 1); - memcpy (&sock->tsi, &tsi, sizeof(pgm_tsi_t)); - ((struct sockaddr*)&sock->send_addr)->sa_family = AF_INET; - ((struct sockaddr_in*)&sock->send_addr)->sin_addr.s_addr = inet_addr ("127.0.0.2"); - ((struct sockaddr*)&sock->send_gsr.gsr_group)->sa_family = AF_INET; - ((struct sockaddr_in*)&sock->send_gsr.gsr_group)->sin_addr.s_addr = inet_addr ("239.192.0.1"); - sock->dport = g_htons(TEST_PORT); - sock->window = g_malloc0 (sizeof(pgm_txw_t)); - sock->txw_sqns = TEST_TXW_SQNS; - sock->max_tpdu = TEST_MAX_TPDU; - sock->max_tsdu = TEST_MAX_TPDU - sizeof(struct pgm_ip) - pgm_pkt_offset (FALSE, FALSE); - sock->max_tsdu_fragment = TEST_MAX_TPDU - sizeof(struct pgm_ip) - pgm_pkt_offset (TRUE, FALSE); - sock->max_apdu = MIN(TEST_TXW_SQNS, PGM_MAX_FRAGMENTS) * sock->max_tsdu_fragment; - sock->iphdr_len = sizeof(struct pgm_ip); - sock->spm_heartbeat_interval = g_malloc0 (sizeof(guint) * (2+2)); - sock->spm_heartbeat_interval[0] = pgm_secs(1); - pgm_spinlock_init (&sock->txw_spinlock); - sock->is_bound = FALSE; - sock->is_connected = FALSE; - sock->is_destroyed = FALSE; - sock->is_reset = FALSE; - return sock; -} - -/** receiver module */ -PGM_GNUC_INTERNAL -void -mock_pgm_peer_unref ( - pgm_peer_t* peer - ) -{ -} - -/** source module */ -static -bool -mock_pgm_on_nak_notify ( - GIOChannel* source, - GIOCondition condition, - gpointer data - ) -{ - return TRUE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_send_spm ( - pgm_sock_t* sock, - int flags - ) -{ - return TRUE; -} - -/** timer module */ -PGM_GNUC_INTERNAL -bool -mock_pgm_timer_prepare ( - pgm_sock_t* const sock - ) -{ - return FALSE; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_timer_check ( - pgm_sock_t* const sock - ) -{ - return FALSE; -} - -PGM_GNUC_INTERNAL -pgm_time_t -mock_pgm_timer_expiration ( - pgm_sock_t* const sock - ) -{ - return 100L; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_timer_dispatch ( - pgm_sock_t* const sock - ) -{ - return TRUE; -} - -/** transmit window module */ -pgm_txw_t* -mock_pgm_txw_create ( - const pgm_tsi_t* const tsi, - const uint16_t tpdu_size, - const uint32_t sqns, - const unsigned secs, - const ssize_t max_rte, - const bool use_fec, - const uint8_t rs_n, - const uint8_t rs_k - ) -{ - pgm_txw_t* window = g_new0 (pgm_txw_t, 1); - return window; -} - -void -mock_pgm_txw_shutdown ( - pgm_txw_t* const window - ) -{ - g_free (window); -} - -/** rate control module */ -PGM_GNUC_INTERNAL -void -mock_pgm_rate_create ( - pgm_rate_t* bucket, - ssize_t rate_per_sec, - size_t iphdr_len, - uint16_t max_tpdu - ) -{ -} - -PGM_GNUC_INTERNAL -void -mock_pgm_rate_destroy ( - pgm_rate_t* bucket - ) -{ -} - -PGM_GNUC_INTERNAL -pgm_time_t -mock_pgm_rate_remaining ( - pgm_rate_t* bucket, - gsize packetlen - ) -{ - return 0; -} - -/** reed solomon module */ -void -mock_pgm_rs_create ( - pgm_rs_t* rs, - const uint8_t n, - const uint8_t k - ) -{ -} - -void -mock_pgm_rs_destroy ( - pgm_rs_t* rs - ) -{ -} - -/** time module */ -static pgm_time_t _mock_pgm_time_update_now (void); -pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; - -static -pgm_time_t -_mock_pgm_time_update_now (void) -{ - return 0x1; -} - - -/* mock functions for external references */ - - -/* target: - * bool - * pgm_socket ( - * pgm_sock_t** sock, - * const sa_family_t family, - * const int pgm_sock_type, - * const int protocol, - * pgm_error_t** error - * ) - */ - -START_TEST (test_create_pass_001) -{ - pgm_error_t* err = NULL; - pgm_sock_t* sock; -/* only one type currently implemented */ - const int pgm_sock_type = SOCK_SEQPACKET; -/* PGM/IPv4 */ - sock = NULL; - fail_unless (TRUE == pgm_socket (&sock, AF_INET, pgm_sock_type, IPPROTO_PGM, &err), "create failed"); -/* PGM/UDP over IPv4 */ - sock = NULL; - fail_unless (TRUE == pgm_socket (&sock, AF_INET, pgm_sock_type, IPPROTO_UDP, &err), "create failed"); -/* PGM/IPv6 */ - sock = NULL; - fail_unless (TRUE == pgm_socket (&sock, AF_INET6, pgm_sock_type, IPPROTO_PGM, &err), "create failed"); -/* PGM/UDP over IPv6 */ - sock = NULL; - fail_unless (TRUE == pgm_socket (&sock, AF_INET6, pgm_sock_type, IPPROTO_UDP, &err), "create failed"); - fail_unless (NULL == err, "error raised"); -} -END_TEST - -/* NULL socket */ -START_TEST (test_create_fail_002) -{ - pgm_error_t* err = NULL; - fail_unless (FALSE == pgm_socket (NULL, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); -} -END_TEST - -/* invalid protocol family */ -START_TEST (test_create_fail_003) -{ - pgm_error_t* err = NULL; - pgm_sock_t* sock = NULL; - fail_unless (FALSE == pgm_socket (&sock, AF_UNSPEC, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); -} -END_TEST - -/* invalid socket type */ -START_TEST (test_create_fail_004) -{ - pgm_error_t* err = NULL; - pgm_sock_t* sock = NULL; - fail_unless (FALSE == pgm_socket (&sock, AF_INET, SOCK_STREAM, IPPROTO_PGM, &err), "create failed"); - fail_unless (FALSE == pgm_socket (&sock, AF_INET, SOCK_DGRAM, IPPROTO_PGM, &err), "create failed"); -} -END_TEST - -/* invalid protocol */ -START_TEST (test_create_fail_005) -{ - pgm_error_t* err = NULL; - pgm_sock_t* sock = NULL; - fail_unless (FALSE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_TCP, &err), "create failed"); -} -END_TEST - - -/* target: - * bool - * pgm_bind ( - * pgm_sock_t* sock, - * const struct pgm_sockaddr_t* sockaddr, - * const socklen_t sockaddrlen, - * pgm_error_t** error - * ) - */ - -START_TEST (test_bind_pass_001) -{ - pgm_error_t* err = NULL; - pgm_sock_t* sock = NULL; - struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); - fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); - fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); - fail_unless (NULL == err, "error raised"); - fail_unless (TRUE == pgm_bind (sock, pgmsa, sizeof(*pgmsa), &err), "bind failed"); -} -END_TEST - -/* fail on unset options */ -START_TEST (test_bind_fail_001) -{ - pgm_error_t* err = NULL; - pgm_sock_t* sock = NULL; - struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); - fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); - fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); - fail_unless (NULL == err, "error raised"); - fail_unless (FALSE == pgm_bind (sock, pgmsa, sizeof(*pgmsa), &err), "bind failed"); -} -END_TEST - -/* invalid parameters */ -START_TEST (test_bind_fail_002) -{ - pgm_error_t* err = NULL; - fail_unless (FALSE == pgm_bind (NULL, NULL, 0, &err), "bind failed"); -} -END_TEST - -/* target: - * bool - * pgm_bind3 ( - * pgm_sock_t* sock, - * const struct pgm_sockaddr_t* sockaddr, - * const socklen_t sockaddrlen, - * const struct pgm_interface_req_t* send_req, - * const socklen_t send_req_len, - * const struct pgm_interface_req_t* recv_req, - * const socklen_t recv_req_len, - * pgm_error_t** error - * ) - */ - -/* fail on unset options */ -START_TEST (test_bind3_fail_001) -{ - pgm_error_t* err = NULL; - pgm_sock_t* sock = NULL; - struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); - fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); - fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); - fail_unless (NULL == err, "error raised"); - struct pgm_interface_req_t send_req = { .ir_interface = 0, .ir_scope_id = 0 }, - recv_req = { .ir_interface = 0, .ir_scope_id = 0 }; - fail_unless (FALSE == pgm_bind3 (sock, - pgmsa, sizeof(*pgmsa), - &send_req, sizeof(send_req), - &recv_req, sizeof(recv_req), - &err), "bind failed"); -} -END_TEST - -/* invalid parameters */ -START_TEST (test_bind3_fail_002) -{ - pgm_error_t* err = NULL; - fail_unless (FALSE == pgm_bind3 (NULL, NULL, 0, NULL, 0, NULL, 0, &err), "bind failed"); -} -END_TEST - -/* target: - * bool - * pgm_connect ( - * pgm_sock_t* sock, - * pgm_error_t** error - * ) - */ - -START_TEST (test_connect_pass_001) -{ - pgm_error_t* err = NULL; - pgm_sock_t* sock = NULL; - struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); - fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); - fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); - fail_unless (NULL == err, "error raised"); - fail_unless (TRUE == pgm_bind (sock, pgmsa, sizeof(*pgmsa), &err), "bind failed"); - fail_unless (TRUE == pgm_connect (sock, &err), "connect failed"); -} -END_TEST - -/* invalid parameters */ -START_TEST (test_connect_fail_001) -{ - pgm_error_t* err = NULL; - fail_unless (FALSE == pgm_connect (NULL, &err), "connect failed"); -} -END_TEST - -/* target: - * bool - * pgm_close ( - * pgm_sock_t* sock, - * bool flush - * ) - */ - -/* socket > close */ -START_TEST (test_destroy_pass_001) -{ - pgm_error_t* err = NULL; - pgm_sock_t* sock = NULL; - fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); - fail_unless (TRUE == pgm_close (sock, FALSE), "destroy failed"); -} -END_TEST - -/* socket > bind > close */ -START_TEST (test_destroy_pass_002) -{ - pgm_error_t* err = NULL; - pgm_sock_t* sock = NULL; - struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); - fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); - fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); - fail_unless (NULL == err, "error raised"); - fail_unless (TRUE == pgm_bind (sock, pgmsa, sizeof(*pgmsa), &err), "bind failed"); - fail_unless (TRUE == pgm_close (sock, FALSE), "destroy failed"); -} -END_TEST - -/* socket > bind > connect > close */ -START_TEST (test_destroy_pass_003) -{ - pgm_error_t* err = NULL; - pgm_sock_t* sock = NULL; - struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); - fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); - fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); - fail_unless (NULL == err, "error raised"); - fail_unless (TRUE == pgm_bind (sock, pgmsa, sizeof(*pgmsa), &err), "bind failed"); - fail_unless (TRUE == pgm_connect (sock, &err), "connect failed"); - fail_unless (TRUE == pgm_close (sock, FALSE), "destroy failed"); -} -END_TEST - -/* invalid parameters */ -START_TEST (test_destroy_fail_001) -{ - fail_unless (FALSE == pgm_close (NULL, FALSE), "destroy failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_MAX_TPDU, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_max_tpdu_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_MTU; - const int max_tpdu = 1500; - const void* optval = &max_tpdu; - const socklen_t optlen = sizeof(max_tpdu); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_max_tpdu failed"); -} -END_TEST - -/* invalid parameters */ -START_TEST (test_set_max_tpdu_fail_001) -{ - const int optname = PGM_MTU; - const int max_tpdu = 1500; - const void* optval = &max_tpdu; - const socklen_t optlen = sizeof(max_tpdu); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_max_tpdu failed"); -} -END_TEST - -/* too small */ -START_TEST (test_set_max_tpdu_fail_002) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_MTU; - const int max_tpdu = 1; - const void* optval = &max_tpdu; - const socklen_t optlen = sizeof(max_tpdu); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_max_tpdu failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_MULTICAST_LOOP, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_multicast_loop_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_MULTICAST_LOOP; - const int loop_enabled = 1; - const void* optval = &loop_enabled; - const socklen_t optlen = sizeof(loop_enabled); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_multicast_loop failed"); -} -END_TEST - -START_TEST (test_set_multicast_loop_fail_001) -{ - const int optname = PGM_MULTICAST_LOOP; - const int loop_enabled = 1; - const void* optval = &loop_enabled; - const socklen_t optlen = sizeof(loop_enabled); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_multicast_loop failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_MULTICAST_HOPS, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_hops_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_MULTICAST_HOPS; - const int hops = 16; - const void* optval = &hops; - const socklen_t optlen = sizeof(hops); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_hops failed"); -} -END_TEST - -START_TEST (test_set_hops_fail_001) -{ - const int optname = PGM_MULTICAST_HOPS; - const int hops = 16; - const void* optval = &hops; - const socklen_t optlen = sizeof(hops); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_hops failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_SNDBUF, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_sndbuf_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_SNDBUF; - const int bufsize = 131071; /* 128kB */ - const void* optval = &bufsize; - const socklen_t optlen = sizeof(bufsize); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_sndbuf failed"); -} -END_TEST - -START_TEST (test_set_sndbuf_fail_001) -{ - const int optname = PGM_SNDBUF; - const int bufsize = 131071; /* 128kB */ - const void* optval = &bufsize; - const socklen_t optlen = sizeof(bufsize); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_sndbuf failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_RCVBUF, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_rcvbuf_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_RCVBUF; - const int bufsize = 131071; /* 128kB */ - const void* optval = &bufsize; - const socklen_t optlen = sizeof(bufsize); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_rcvbuf failed"); -} -END_TEST - -START_TEST (test_set_rcvbuf_fail_001) -{ - const int optname = PGM_RCVBUF; - const int bufsize = 131071; /* 128kB */ - const void* optval = &bufsize; - const socklen_t optlen = sizeof(bufsize); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_rcvbuf failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_USE_FEC, - * const void* optval, - * const socklen_t optlen = sizeof(struct pgm_fecinfo_t) - * ) - */ - -START_TEST (test_set_fec_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_USE_FEC; - const struct pgm_fecinfo_t fecinfo = { - .ondemand_parity_enabled = TRUE, - .proactive_packets = 16, - .var_pktlen_enabled = TRUE, - .block_size = 255, - .group_size = 239 - }; - const void* optval = &fecinfo; - const socklen_t optlen = sizeof(fecinfo); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_fec failed"); -} -END_TEST - -START_TEST (test_set_fec_fail_001) -{ - const int optname = PGM_USE_FEC; - const struct pgm_fecinfo_t fecinfo = { - .ondemand_parity_enabled = TRUE, - .proactive_packets = 16, - .var_pktlen_enabled = TRUE, - .block_size = 255, - .group_size = 239 - }; - const void* optval = &fecinfo; - const socklen_t optlen = sizeof(fecinfo); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_fec failed"); -} -END_TEST - -/* TODO: invalid Reed-Solomon parameters - */ - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_USE_PGMCC, - * const void* optval, - * const socklen_t optlen = sizeof(struct pgm_pgmccinfo_t) - * ) - */ - -START_TEST (test_set_pgmcc_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_USE_PGMCC; - const struct pgm_pgmccinfo_t pgmccinfo = { - .ack_bo_ivl = pgm_msecs(100), - .ack_c = 123, - .ack_c_p = 456 - }; - const void* optval = &pgmccinfo; - const socklen_t optlen = sizeof(pgmccinfo); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_pgmcc failed"); -} -END_TEST - -START_TEST (test_set_pgmcc_fail_001) -{ - const int optname = PGM_USE_PGMCC; - const struct pgm_pgmccinfo_t pgmccinfo = { - .ack_bo_ivl = pgm_msecs(100), - .ack_c = 123, - .ack_c_p = 456 - }; - const void* optval = &pgmccinfo; - const socklen_t optlen = sizeof(pgmccinfo); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_pgmcc failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_USE_CR, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_cr_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_USE_CR; - const int magic_bunny = 1; - const void* optval = &magic_bunny; - const socklen_t optlen = sizeof(magic_bunny); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_cr failed"); -} -END_TEST - -START_TEST (test_set_cr_fail_001) -{ - const int optname = PGM_USE_CR; - const int magic_bunny = 1; - const void* optval = &magic_bunny; - const socklen_t optlen = sizeof(magic_bunny); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_cr failed"); -} -END_TEST - - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_SEND_ONLY, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_send_only_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_SEND_ONLY; - const int send_only = 1; - const void* optval = &send_only; - const socklen_t optlen = sizeof(send_only); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_send_only failed"); -} -END_TEST - -START_TEST (test_set_send_only_fail_001) -{ - const int optname = PGM_SEND_ONLY; - const int send_only = 1; - const void* optval = &send_only; - const socklen_t optlen = sizeof(send_only); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_send_only failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_RECV_ONLY, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_recv_only_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_RECV_ONLY; - const int recv_only = 1; - const void* optval = &recv_only; - const socklen_t optlen = sizeof(recv_only); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_recv_only failed"); -} -END_TEST - -START_TEST (test_set_recv_only_fail_001) -{ - const int optname = PGM_RECV_ONLY; - const int recv_only = 1; - const void* optval = &recv_only; - const socklen_t optlen = sizeof(recv_only); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_recv_only failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_PASSIVE, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_recv_only_pass_002) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_PASSIVE; - const int passive = 1; - const void* optval = &passive; - const socklen_t optlen = sizeof(passive); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_passive failed"); -} -END_TEST - -START_TEST (test_set_recv_only_fail_002) -{ - const int optname = PGM_PASSIVE; - const int passive = 1; - const void* optval = &passive; - const socklen_t optlen = sizeof(passive); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_passive failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_ABORT_ON_RESET, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_abort_on_reset_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_ABORT_ON_RESET; - const int abort_on_reset= 1; - const void* optval = &abort_on_reset; - const socklen_t optlen = sizeof(abort_on_reset); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_abort_on_reset failed"); -} -END_TEST - -START_TEST (test_set_abort_on_reset_fail_001) -{ - const int optname = PGM_ABORT_ON_RESET; - const int abort_on_reset= 1; - const void* optval = &abort_on_reset; - const socklen_t optlen = sizeof(abort_on_reset); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_abort_on_reset failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_NOBLOCK, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_noblock_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_NOBLOCK; - const int noblock = 1; - const void* optval = &noblock; - const socklen_t optlen = sizeof(noblock); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_noblock failed"); -} -END_TEST - -START_TEST (test_set_noblock_fail_001) -{ - const int optname = PGM_NOBLOCK; - const int noblock = 1; - const void* optval = &noblock; - const socklen_t optlen = sizeof(noblock); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_noblock failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_UDP_ENCAP_UCAST_PORT, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_udp_unicast_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_NOBLOCK; - const int unicast_port = 10001; - const void* optval = &unicast_port; - const socklen_t optlen = sizeof(unicast_port); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_udp_unicast failed"); -} -END_TEST - -START_TEST (test_set_udp_unicast_fail_001) -{ - const int optname = PGM_NOBLOCK; - const int unicast_port = 10001; - const void* optval = &unicast_port; - const socklen_t optlen = sizeof(unicast_port); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_udp_unicast failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_UDP_ENCAP_MCAST_PORT, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_udp_multicast_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_NOBLOCK; - const int multicast_port= 10001; - const void* optval = &multicast_port; - const socklen_t optlen = sizeof(multicast_port); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_udp_multicast failed"); -} -END_TEST - -START_TEST (test_set_udp_multicast_fail_001) -{ - const int optname = PGM_NOBLOCK; - const int multicast_port= 10002; - const void* optval = &multicast_port; - const socklen_t optlen = sizeof(multicast_port); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_udp_multicast failed"); -} -END_TEST - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_create = tcase_create ("create"); - suite_add_tcase (s, tc_create); - tcase_add_checked_fixture (tc_create, mock_setup, mock_teardown); - tcase_add_test (tc_create, test_create_pass_001); - tcase_add_test (tc_create, test_create_fail_002); - tcase_add_test (tc_create, test_create_fail_003); - tcase_add_test (tc_create, test_create_fail_004); - tcase_add_test (tc_create, test_create_fail_005); - - TCase* tc_bind = tcase_create ("bind"); - suite_add_tcase (s, tc_bind); - tcase_add_checked_fixture (tc_bind, mock_setup, mock_teardown); - tcase_add_test (tc_bind, test_bind_fail_001); - tcase_add_test (tc_bind, test_bind_fail_002); - - TCase* tc_connect = tcase_create ("connect"); - suite_add_tcase (s, tc_connect); - tcase_add_checked_fixture (tc_connect, mock_setup, mock_teardown); - tcase_add_test (tc_connect, test_connect_pass_001); - tcase_add_test (tc_connect, test_connect_fail_001); - - TCase* tc_destroy = tcase_create ("destroy"); - suite_add_tcase (s, tc_destroy); - tcase_add_checked_fixture (tc_destroy, mock_setup, mock_teardown); - tcase_add_test (tc_destroy, test_destroy_pass_001); - tcase_add_test (tc_destroy, test_destroy_fail_001); - - TCase* tc_set_max_tpdu = tcase_create ("set-max-tpdu"); - suite_add_tcase (s, tc_set_max_tpdu); - tcase_add_checked_fixture (tc_set_max_tpdu, mock_setup, mock_teardown); - tcase_add_test (tc_set_max_tpdu, test_set_max_tpdu_pass_001); - tcase_add_test (tc_set_max_tpdu, test_set_max_tpdu_fail_001); - - TCase* tc_set_multicast_loop = tcase_create ("set-multicast-loop"); - suite_add_tcase (s, tc_set_multicast_loop); - tcase_add_checked_fixture (tc_set_multicast_loop, mock_setup, mock_teardown); - tcase_add_test (tc_set_multicast_loop, test_set_multicast_loop_pass_001); - tcase_add_test (tc_set_multicast_loop, test_set_multicast_loop_fail_001); - - TCase* tc_set_hops = tcase_create ("set-hops"); - suite_add_tcase (s, tc_set_hops); - tcase_add_checked_fixture (tc_set_hops, mock_setup, mock_teardown); - tcase_add_test (tc_set_hops, test_set_hops_pass_001); - tcase_add_test (tc_set_hops, test_set_hops_fail_001); - - TCase* tc_set_sndbuf = tcase_create ("set-sndbuf"); - suite_add_tcase (s, tc_set_sndbuf); - tcase_add_checked_fixture (tc_set_sndbuf, mock_setup, mock_teardown); - tcase_add_test (tc_set_sndbuf, test_set_sndbuf_pass_001); - tcase_add_test (tc_set_sndbuf, test_set_sndbuf_fail_001); - - TCase* tc_set_rcvbuf = tcase_create ("set-rcvbuf"); - suite_add_tcase (s, tc_set_rcvbuf); - tcase_add_checked_fixture (tc_set_rcvbuf, mock_setup, mock_teardown); - tcase_add_test (tc_set_rcvbuf, test_set_rcvbuf_pass_001); - tcase_add_test (tc_set_rcvbuf, test_set_rcvbuf_fail_001); - - TCase* tc_set_fec = tcase_create ("set-fec"); - suite_add_tcase (s, tc_set_fec); - tcase_add_checked_fixture (tc_set_fec, mock_setup, mock_teardown); - tcase_add_test (tc_set_fec, test_set_fec_pass_001); - tcase_add_test (tc_set_fec, test_set_fec_fail_001); - - TCase* tc_set_pgmcc = tcase_create ("set-pgmcc"); - suite_add_tcase (s, tc_set_pgmcc); - tcase_add_checked_fixture (tc_set_pgmcc, mock_setup, mock_teardown); - tcase_add_test (tc_set_pgmcc, test_set_pgmcc_pass_001); - tcase_add_test (tc_set_pgmcc, test_set_pgmcc_fail_001); - - TCase* tc_set_cr = tcase_create ("set-cr"); - suite_add_tcase (s, tc_set_cr); - tcase_add_checked_fixture (tc_set_cr, mock_setup, mock_teardown); - tcase_add_test (tc_set_cr, test_set_cr_pass_001); - tcase_add_test (tc_set_cr, test_set_cr_fail_001); - - TCase* tc_set_send_only = tcase_create ("set-send-only"); - suite_add_tcase (s, tc_set_send_only); - tcase_add_checked_fixture (tc_set_send_only, mock_setup, mock_teardown); - tcase_add_test (tc_set_send_only, test_set_send_only_pass_001); - tcase_add_test (tc_set_send_only, test_set_send_only_fail_001); - - TCase* tc_set_recv_only = tcase_create ("set-recv-only"); - suite_add_tcase (s, tc_set_recv_only); - tcase_add_checked_fixture (tc_set_recv_only, mock_setup, mock_teardown); - tcase_add_test (tc_set_recv_only, test_set_recv_only_pass_001); - tcase_add_test (tc_set_recv_only, test_set_recv_only_pass_002); - tcase_add_test (tc_set_recv_only, test_set_recv_only_fail_001); - tcase_add_test (tc_set_recv_only, test_set_recv_only_fail_002); - - TCase* tc_set_abort_on_reset = tcase_create ("set-abort-on-reset"); - suite_add_tcase (s, tc_set_abort_on_reset); - tcase_add_checked_fixture (tc_set_abort_on_reset, mock_setup, mock_teardown); - tcase_add_test (tc_set_abort_on_reset, test_set_abort_on_reset_pass_001); - tcase_add_test (tc_set_abort_on_reset, test_set_abort_on_reset_fail_001); - - TCase* tc_set_noblock = tcase_create ("set-non-blocking"); - suite_add_tcase (s, tc_set_noblock); - tcase_add_checked_fixture (tc_set_noblock, mock_setup, mock_teardown); - tcase_add_test (tc_set_noblock, test_set_noblock_pass_001); - tcase_add_test (tc_set_noblock, test_set_noblock_fail_001); - - TCase* tc_set_udp_unicast = tcase_create ("set-udp-encap-ucast-port"); - suite_add_tcase (s, tc_set_udp_unicast); - tcase_add_checked_fixture (tc_set_udp_unicast, mock_setup, mock_teardown); - tcase_add_test (tc_set_udp_unicast, test_set_udp_unicast_pass_001); - tcase_add_test (tc_set_udp_unicast, test_set_udp_unicast_fail_001); - - TCase* tc_set_udp_multicast = tcase_create ("set-udp-encap-mcast-port"); - suite_add_tcase (s, tc_set_udp_multicast); - tcase_add_checked_fixture (tc_set_udp_multicast, mock_setup, mock_teardown); - tcase_add_test (tc_set_udp_multicast, test_set_udp_multicast_pass_001); - tcase_add_test (tc_set_udp_multicast, test_set_udp_multicast_fail_001); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/source.c b/3rdparty/openpgm-svn-r1085/pgm/source.c deleted file mode 100644 index 12a61b6..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/source.c +++ /dev/null @@ -1,2339 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM source socket. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -//#define SOURCE_DEBUG - -#ifndef SOURCE_DEBUG -# define PGM_DISABLE_ASSERT -#endif - -#if !defined(ENOBUFS) && defined(WSAENOBUFS) -# define ENOBUFS WSAENOBUFS -#endif - - -/* locals */ -static inline bool peer_is_source (const pgm_peer_t*) PGM_GNUC_CONST; -static inline bool peer_is_peer (const pgm_peer_t*) PGM_GNUC_CONST; -static void reset_heartbeat_spm (pgm_sock_t*const, const pgm_time_t); -static bool send_ncf (pgm_sock_t*const restrict, const struct sockaddr*const restrict, const struct sockaddr*const restrict, const uint32_t, const bool); -static bool send_ncf_list (pgm_sock_t*const restrict, const struct sockaddr*const restrict, const struct sockaddr*restrict, struct pgm_sqn_list_t*const restrict, const bool); -static int send_odata (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict, size_t*restrict); -static int send_odata_copy (pgm_sock_t*const restrict, const void*restrict, const uint16_t, size_t*restrict); -static int send_odatav (pgm_sock_t*const restrict, const struct pgm_iovec*const restrict, const unsigned, size_t*restrict); -static bool send_rdata (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict); - - -static inline -unsigned -_pgm_popcount ( - uint32_t n - ) -{ -#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) - return __builtin_popcount (n); -#else -/* MIT HAKMEM 169 */ - const uint32_t t = n - ((n >> 1) & 033333333333) - - ((n >> 2) & 011111111111); - return ((t + (t >> 3) & 030707070707)) % 63; -#endif -} - -static inline -bool -peer_is_source ( - const pgm_peer_t* peer - ) -{ - return (NULL == peer); -} - -static inline -bool -peer_is_peer ( - const pgm_peer_t* peer - ) -{ - return (NULL != peer); -} - -static inline -void -reset_spmr_timer ( - pgm_peer_t* const peer - ) -{ - peer->spmr_expiry = 0; -} - -static inline -size_t -source_max_tsdu ( - const pgm_sock_t* sock, - const bool can_fragment - ) -{ - size_t max_tsdu = can_fragment ? sock->max_tsdu_fragment : sock->max_tsdu; - if (sock->use_var_pktlen /* OPT_VAR_PKT_LEN */) - max_tsdu -= sizeof (uint16_t); - return max_tsdu; -} - -/* prototype of function to send pro-active parity NAKs. - */ -static -bool -pgm_schedule_proactive_nak ( - pgm_sock_t* sock, - uint32_t nak_tg_sqn /* transmission group (shifted) */ - ) -{ - pgm_return_val_if_fail (NULL != sock, FALSE); - const bool status = pgm_txw_retransmit_push (sock->window, - nak_tg_sqn | sock->rs_proactive_h, - TRUE /* is_parity */, - sock->tg_sqn_shift); - return status; -} - -/* a deferred request for RDATA, now processing in the timer thread, we check the transmit - * window to see if the packet exists and forward on, maintaining a lock until the queue is - * empty. - * - * returns TRUE on success, returns FALSE if operation would block. - */ - -bool -pgm_on_deferred_nak ( - pgm_sock_t* const sock - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - -/* We can flush queue and block all odata, or process one set, or process each - * sequence number individually. - */ - -/* parity packets are re-numbered across the transmission group with index h, sharing the space - * with the original packets. beyond the transmission group size (k), the PGM option OPT_PARITY_GRP - * provides the extra offset value. - */ - -/* peek from the retransmit queue so we can eliminate duplicate NAKs up until the repair packet - * has been retransmitted. - */ - pgm_spinlock_lock (&sock->txw_spinlock); - struct pgm_sk_buff_t* skb = pgm_txw_retransmit_try_peek (sock->window); - if (skb) { - skb = pgm_skb_get (skb); - pgm_spinlock_unlock (&sock->txw_spinlock); - if (!send_rdata (sock, skb)) { - pgm_free_skb (skb); - pgm_notify_send (&sock->rdata_notify); - return FALSE; - } - pgm_free_skb (skb); -/* now remove sequence number from retransmit queue, re-enabling NAK processing for this sequence number */ - pgm_txw_retransmit_remove_head (sock->window); - } else - pgm_spinlock_unlock (&sock->txw_spinlock); - return TRUE; -} - -/* SPMR indicates if multicast to cancel own SPMR, or unicast to send SPM. - * - * rate limited to 1/IHB_MIN per TSI (13.4). - * - * if SPMR was valid, returns TRUE, if invalid returns FALSE. - */ - -bool -pgm_on_spmr ( - pgm_sock_t* const restrict sock, - pgm_peer_t* const restrict peer, /* maybe NULL if socket is source */ - struct pgm_sk_buff_t* const restrict skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - - pgm_debug ("pgm_on_spmr (sock:%p peer:%p skb:%p)", - (void*)sock, (void*)peer, (void*)skb); - - if (PGM_UNLIKELY(!pgm_verify_spmr (skb))) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed SPMR rejected.")); - return FALSE; - } - - if (peer_is_source (peer)) { - const bool send_status = pgm_send_spm (sock, 0); - if (PGM_UNLIKELY(!send_status)) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Failed to send SPM on SPM-Request.")); - } - } else { - pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Suppressing SPMR due to peer multicast SPMR.")); - reset_spmr_timer (peer); - } - return TRUE; -} - -/* Process opt_pgmcc_feedback PGM option that ships attached to ACK or NAK. - * Contents use to elect best ACKer. - * - * returns TRUE if peer is the elected ACKer. - */ - -static -bool -on_opt_pgmcc_feedback ( - pgm_sock_t* const restrict sock, - const struct pgm_sk_buff_t* const restrict skb, - const struct pgm_opt_pgmcc_feedback* restrict opt_pgmcc_feedback - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - pgm_assert (NULL != opt_pgmcc_feedback); - - const uint32_t opt_tstamp = ntohl (opt_pgmcc_feedback->opt_tstamp); - const uint16_t opt_loss_rate = ntohs (opt_pgmcc_feedback->opt_loss_rate); - - const uint32_t rtt = pgm_to_msecs (skb->tstamp) - opt_tstamp; - const uint64_t peer_loss = rtt * rtt * opt_loss_rate; - - struct sockaddr_storage peer_nla; - pgm_nla_to_sockaddr (&opt_pgmcc_feedback->opt_nla_afi, (struct sockaddr*)&peer_nla); - -/* ACKer elections */ - if (PGM_UNLIKELY(pgm_sockaddr_is_addr_unspecified ((const struct sockaddr*)&sock->acker_nla))) - { - pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Elected first ACKer")); - memcpy (&sock->acker_nla, &peer_nla, pgm_sockaddr_storage_len (&peer_nla)); - } - else if (peer_loss > sock->acker_loss && - 0 != pgm_sockaddr_cmp ((const struct sockaddr*)&peer_nla, (const struct sockaddr*)&sock->acker_nla)) - { - pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Elected new ACKer")); - memcpy (&sock->acker_nla, &peer_nla, pgm_sockaddr_storage_len (&peer_nla)); - } - -/* update ACKer state */ - if (0 == pgm_sockaddr_cmp ((const struct sockaddr*)&peer_nla, (const struct sockaddr*)&sock->acker_nla)) - { - sock->acker_loss = peer_loss; - return TRUE; - } - - return FALSE; -} - -/* NAK requesting RDATA transmission for a sending sock, only valid if - * sequence number(s) still in transmission window. - * - * we can potentially have different IP versions for the NAK packet to the send group. - * - * TODO: fix IPv6 AFIs - * - * take in a NAK and pass off to an asynchronous queue for another thread to process - * - * if NAK is valid, returns TRUE. on error, FALSE is returned. - */ - -bool -pgm_on_nak ( - pgm_sock_t* const restrict sock, - struct pgm_sk_buff_t* const restrict skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - - pgm_debug ("pgm_on_nak (sock:%p skb:%p)", - (const void*)sock, (const void*)skb); - - const bool is_parity = skb->pgm_header->pgm_options & PGM_OPT_PARITY; - if (is_parity) { - sock->cumulative_stats[PGM_PC_SOURCE_PARITY_NAKS_RECEIVED]++; - if (!sock->use_ondemand_parity) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Parity NAK rejected as on-demand parity is not enabled.")); - sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; - return FALSE; - } - } else - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED]++; - - if (PGM_UNLIKELY(!pgm_verify_nak (skb))) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected.")); - sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; - return FALSE; - } - - const struct pgm_nak* nak = (struct pgm_nak*) skb->data; - const struct pgm_nak6* nak6 = (struct pgm_nak6*)skb->data; - -/* NAK_SRC_NLA contains our sock unicast NLA */ - struct sockaddr_storage nak_src_nla; - pgm_nla_to_sockaddr (&nak->nak_src_nla_afi, (struct sockaddr*)&nak_src_nla); - if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nak_src_nla, (struct sockaddr*)&sock->send_addr) != 0)) - { - char saddr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&nak_src_nla, saddr, sizeof(saddr)); - pgm_trace (PGM_LOG_ROLE_NETWORK,_("NAK rejected for unmatched NLA: %s"), saddr); - sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; - return FALSE; - } - -/* NAK_GRP_NLA containers our sock multicast group */ - struct sockaddr_storage nak_grp_nla; - pgm_nla_to_sockaddr ((AF_INET6 == nak_src_nla.ss_family) ? &nak6->nak6_grp_nla_afi : &nak->nak_grp_nla_afi, (struct sockaddr*)&nak_grp_nla); - if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nak_grp_nla, (struct sockaddr*)&sock->send_gsr.gsr_group) != 0)) - { - char sgroup[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop ((struct sockaddr*)&nak_src_nla, sgroup, sizeof(sgroup)); - pgm_trace (PGM_LOG_ROLE_NETWORK,_("NAK rejected as targeted for different multicast group: %s"), sgroup); - sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; - return FALSE; - } - -/* create queue object */ - struct pgm_sqn_list_t sqn_list; - sqn_list.sqn[0] = ntohl (nak->nak_sqn); - sqn_list.len = 1; - - pgm_debug ("nak_sqn %" PRIu32, sqn_list.sqn[0]); - -/* check NAK list */ - const uint32_t* nak_list = NULL; - uint_fast8_t nak_list_len = 0; - if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) - { - const struct pgm_opt_length* opt_len = (AF_INET6 == nak_src_nla.ss_family) ? - (const struct pgm_opt_length*)(nak6 + 1) : - (const struct pgm_opt_length*)(nak + 1); - if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected.")); - sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; - return FALSE; - } - if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected.")); - sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; - return FALSE; - } -/* TODO: check for > 16 options & past packet end */ - const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; - do { - opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); - if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_NAK_LIST) { - nak_list = ((const struct pgm_opt_nak_list*)(opt_header + 1))->opt_sqn; - nak_list_len = ( opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(uint8_t) ) / sizeof(uint32_t); - break; - } - } while (!(opt_header->opt_type & PGM_OPT_END)); - } - -/* nak list numbers */ - if (PGM_UNLIKELY(nak_list_len > 63)) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected on too long sequence list.")); - return FALSE; - } - - for (uint_fast8_t i = 0; i < nak_list_len; i++) - { - sqn_list.sqn[sqn_list.len++] = ntohl (*nak_list); - nak_list++; - } - -/* send NAK confirm packet immediately, then defer to timer thread for a.s.a.p - * delivery of the actual RDATA packets. blocking send for NCF is ignored as RDATA - * broadcast will be sent later. - */ - if (nak_list_len) - send_ncf_list (sock, (struct sockaddr*)&nak_src_nla, (struct sockaddr*)&nak_grp_nla, &sqn_list, is_parity); - else - send_ncf (sock, (struct sockaddr*)&nak_src_nla, (struct sockaddr*)&nak_grp_nla, sqn_list.sqn[0], is_parity); - -/* queue retransmit requests */ - for (uint_fast8_t i = 0; i < sqn_list.len; i++) { - const bool push_status = pgm_txw_retransmit_push (sock->window, sqn_list.sqn[i], is_parity, sock->tg_sqn_shift); - if (PGM_UNLIKELY(!push_status)) { - pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Failed to push retransmit request for #%" PRIu32), sqn_list.sqn[i]); - } - } - return TRUE; -} - -/* Null-NAK, or N-NAK propogated by a DLR for hand waving excitement - * - * if NNAK is valid, returns TRUE. on error, FALSE is returned. - */ - -bool -pgm_on_nnak ( - pgm_sock_t* const restrict sock, - struct pgm_sk_buff_t* const restrict skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - - pgm_debug ("pgm_on_nnak (sock:%p skb:%p)", - (void*)sock, (void*)skb); - - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED]++; - - if (PGM_UNLIKELY(!pgm_verify_nnak (skb))) { - sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; - return FALSE; - } - - const struct pgm_nak* nnak = (struct pgm_nak*) skb->data; - const struct pgm_nak6* nnak6 = (struct pgm_nak6*)skb->data; - -/* NAK_SRC_NLA contains our sock unicast NLA */ - struct sockaddr_storage nnak_src_nla; - pgm_nla_to_sockaddr (&nnak->nak_src_nla_afi, (struct sockaddr*)&nnak_src_nla); - - if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nnak_src_nla, (struct sockaddr*)&sock->send_addr) != 0)) - { - sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; - return FALSE; - } - -/* NAK_GRP_NLA containers our sock multicast group */ - struct sockaddr_storage nnak_grp_nla; - pgm_nla_to_sockaddr ((AF_INET6 == nnak_src_nla.ss_family) ? &nnak6->nak6_grp_nla_afi : &nnak->nak_grp_nla_afi, (struct sockaddr*)&nnak_grp_nla); - if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nnak_grp_nla, (struct sockaddr*)&sock->send_gsr.gsr_group) != 0)) - { - sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; - return FALSE; - } - -/* check NNAK list */ - uint_fast8_t nnak_list_len = 0; - if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) - { - const struct pgm_opt_length* opt_len = (AF_INET6 == nnak_src_nla.ss_family) ? - (const struct pgm_opt_length*)(nnak6 + 1) : - (const struct pgm_opt_length*)(nnak + 1); - if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) { - sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; - return FALSE; - } - if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) { - sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; - return FALSE; - } -/* TODO: check for > 16 options & past packet end */ - const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; - do { - opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); - if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_NAK_LIST) { - nnak_list_len = ( opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(uint8_t) ) / sizeof(uint32_t); - break; - } - } while (!(opt_header->opt_type & PGM_OPT_END)); - } - - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED] += 1 + nnak_list_len; - return TRUE; -} - -/* ACK, sent upstream by one selected ACKER for congestion control feedback. - * - * if ACK is valid, returns TRUE. on error, FALSE is returned. - */ - -bool -pgm_on_ack ( - pgm_sock_t* const restrict sock, - struct pgm_sk_buff_t* const restrict skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - - pgm_debug ("pgm_on_ack (sock:%p skb:%p)", - (const void*)sock, (const void*)skb); - - sock->cumulative_stats[PGM_PC_SOURCE_ACK_PACKETS_RECEIVED]++; - - if (PGM_UNLIKELY(!pgm_verify_ack (skb))) { - sock->cumulative_stats[PGM_PC_SOURCE_ACK_ERRORS]++; - return FALSE; - } - - if (!sock->use_pgmcc) - return FALSE; - - const struct pgm_ack* ack = (struct pgm_ack*)skb->data; - bool is_acker = FALSE; - -/* check PGMCC feedback option for new elections */ - if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) - { - const struct pgm_opt_length* opt_len = (const struct pgm_opt_length*)(ack + 1); - if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed ACK rejected.")); - return FALSE; - } - if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) { - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed ACK rejected.")); - return FALSE; - } - const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; - do { - opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); - if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_PGMCC_FEEDBACK) { - const struct pgm_opt_pgmcc_feedback* opt_pgmcc_feedback = (const struct pgm_opt_pgmcc_feedback*)(opt_header + 1); - is_acker = on_opt_pgmcc_feedback (sock, skb, opt_pgmcc_feedback); - break; /* ignore other options */ - } - } while (!(opt_header->opt_type & PGM_OPT_END)); - } - -/* ignore ACKs from other receivers or sessions */ - if (!is_acker) - return TRUE; - -/* reset ACK expiration */ - sock->next_crqst = 0; - -/* count new ACK sequences */ - const uint32_t ack_rx_max = ntohl (ack->ack_rx_max); - const int32_t delta = ack_rx_max - sock->ack_rx_max; -/* ignore older ACKs when multiple active ACKers */ - if (pgm_uint32_gt (ack_rx_max, sock->ack_rx_max)) - sock->ack_rx_max = ack_rx_max; - uint32_t ack_bitmap = ntohl (ack->ack_bitmap); - if (delta > 32) sock->ack_bitmap = 0; /* sequence jump ahead beyond past bitmap */ - else if (delta > 0) sock->ack_bitmap <<= delta; /* immediate sequence */ - else if (delta > -32) ack_bitmap <<= -delta; /* repair sequence scoped by bitmap */ - else ack_bitmap = 0; /* old sequence */ - unsigned new_acks = _pgm_popcount (ack_bitmap & ~sock->ack_bitmap); - sock->ack_bitmap |= ack_bitmap; - - if (0 == new_acks) - return TRUE; - - const bool is_congestion_limited = (sock->tokens < pgm_fp8 (1)); - -/* after loss detection cancel any further manipulation of the window - * until feedback is received for the next transmitted packet. - */ - if (sock->is_congested) - { - if (pgm_uint32_lte (ack_rx_max, sock->suspended_sqn)) - { - pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC window token manipulation suspended due to congestion (T:%u W:%u)"), - pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); - const uint_fast32_t token_inc = pgm_fp8mul (pgm_fp8 (new_acks), pgm_fp8 (1) + pgm_fp8div (pgm_fp8 (1), sock->cwnd_size)); - sock->tokens = MIN( sock->tokens + token_inc, sock->cwnd_size ); - goto notify_tx; - } - sock->is_congested = FALSE; - } - -/* count outstanding lost sequences */ - const unsigned total_lost = _pgm_popcount (~sock->ack_bitmap); - -/* no detected data loss at ACKer, increase congestion window size */ - if (0 == total_lost) - { - new_acks += sock->acks_after_loss; - sock->acks_after_loss = 0; - uint_fast32_t n = pgm_fp8 (new_acks); - uint_fast32_t token_inc = 0; - -/* slow-start phase, exponential increase to SSTHRESH */ - if (sock->cwnd_size < sock->ssthresh) { - const uint_fast32_t d = MIN( n, sock->ssthresh - sock->cwnd_size ); - n -= d; - token_inc = d + d; - sock->cwnd_size += d; - } - - const uint_fast32_t iw = pgm_fp8div (pgm_fp8 (1), sock->cwnd_size); - -/* linear window increase */ - token_inc += pgm_fp8mul (n, pgm_fp8 (1) + iw); - sock->cwnd_size += pgm_fp8mul (n, iw); - sock->tokens = MIN( sock->tokens + token_inc, sock->cwnd_size ); -// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC++ (T:%u W:%u)"), -// pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); - } - else - { -/* Look for an unacknowledged data packet which is followed by at least three - * acknowledged data packets, then the packet is assumed to be lost and PGMCC - * reacts by halving the window. - * - * Common value will be 0xfffffff7. - */ - sock->acks_after_loss += new_acks; - if (sock->acks_after_loss >= 3) - { - sock->acks_after_loss = 0; - sock->suspended_sqn = ack_rx_max; - sock->is_congested = TRUE; - sock->cwnd_size = pgm_fp8div (sock->cwnd_size, pgm_fp8 (2)); - if (sock->cwnd_size > sock->tokens) - sock->tokens = 0; - else - sock->tokens -= sock->cwnd_size; - sock->ack_bitmap = 0xffffffff; - pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC congestion, half window size (T:%u W:%u)"), - pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); - } - } - -/* token is now available so notify tx thread that transmission time is available */ -notify_tx: - if (is_congestion_limited && - sock->tokens >= pgm_fp8 (1)) - { - pgm_notify_send (&sock->ack_notify); - } - return TRUE; -} - -/* ambient/heartbeat SPM's - * - * heartbeat: ihb_tmr decaying between ihb_min and ihb_max 2x after last packet - * - * on success, TRUE is returned, if operation would block, FALSE is returned. - */ - -bool -pgm_send_spm ( - pgm_sock_t* const sock, - const int flags - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != sock->window); - - pgm_debug ("pgm_send_spm (sock:%p flags:%d)", - (const void*)sock, flags); - - size_t tpdu_length = sizeof(struct pgm_header); - if (AF_INET == sock->send_gsr.gsr_group.ss_family) - tpdu_length += sizeof(struct pgm_spm); - else - tpdu_length += sizeof(struct pgm_spm6); - if (sock->use_proactive_parity || - sock->use_ondemand_parity || - sock->is_pending_crqst || - PGM_OPT_FIN == flags) - { - tpdu_length += sizeof(struct pgm_opt_length); -/* forward error correction */ - if (sock->use_proactive_parity || - sock->use_ondemand_parity) - tpdu_length += sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_parity_prm); -/* congestion report request */ - if (sock->is_pending_crqst) - tpdu_length += sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_crqst); -/* end of session */ - if (PGM_OPT_FIN == flags) - tpdu_length += sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fin); - } - char buf[ tpdu_length ]; - if (PGM_UNLIKELY(pgm_mem_gc_friendly)) - memset (buf, 0, tpdu_length); - struct pgm_header* header = (struct pgm_header*)buf; - struct pgm_spm* spm = (struct pgm_spm *)(header + 1); - struct pgm_spm6* spm6 = (struct pgm_spm6*)(header + 1); - memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); - header->pgm_sport = sock->tsi.sport; - header->pgm_dport = sock->dport; - header->pgm_type = PGM_SPM; - header->pgm_options = 0; - header->pgm_tsdu_length = 0; - -/* SPM */ - spm->spm_sqn = htonl (sock->spm_sqn); - spm->spm_trail = htonl (pgm_txw_trail_atomic (sock->window)); - spm->spm_lead = htonl (pgm_txw_lead_atomic (sock->window)); - spm->spm_reserved = 0; -/* our nla */ - pgm_sockaddr_to_nla ((struct sockaddr*)&sock->send_addr, (char*)&spm->spm_nla_afi); - -/* PGM options */ - if (sock->use_proactive_parity || - sock->use_ondemand_parity || - sock->is_pending_crqst || - PGM_OPT_FIN == flags) - { - struct pgm_opt_length* opt_len; - struct pgm_opt_header *opt_header, *last_opt_header; - uint16_t opt_total_length; - - if (AF_INET == sock->send_gsr.gsr_group.ss_family) - opt_header = (struct pgm_opt_header*)(spm + 1); - else - opt_header = (struct pgm_opt_header*)(spm6 + 1); - header->pgm_options |= PGM_OPT_PRESENT; - opt_len = (struct pgm_opt_length*)opt_header; - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_total_length = sizeof(struct pgm_opt_length); - last_opt_header = opt_header = (struct pgm_opt_header*)(opt_len + 1); - -/* OPT_PARITY_PRM */ - if (sock->use_proactive_parity || - sock->use_ondemand_parity) - { - header->pgm_options |= PGM_OPT_NETWORK; - opt_total_length += sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_parity_prm); - opt_header->opt_type = PGM_OPT_PARITY_PRM; - opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_parity_prm); - struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1); - opt_parity_prm->opt_reserved = (sock->use_proactive_parity ? PGM_PARITY_PRM_PRO : 0) | - (sock->use_ondemand_parity ? PGM_PARITY_PRM_OND : 0); - opt_parity_prm->parity_prm_tgs = htonl (sock->rs_k); - last_opt_header = opt_header; - opt_header = (struct pgm_opt_header*)(opt_parity_prm + 1); - } - -/* OPT_CRQST */ - if (sock->is_pending_crqst) - { - header->pgm_options |= PGM_OPT_NETWORK; - opt_total_length += sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_crqst); - opt_header->opt_type = PGM_OPT_CRQST; - opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_crqst); - struct pgm_opt_crqst* opt_crqst = (struct pgm_opt_crqst*)(opt_header + 1); -/* request receiver worst path report, OPT_CR_RX_WP */ - opt_crqst->opt_reserved = PGM_OPT_CRQST_RXP; - sock->is_pending_crqst = FALSE; - last_opt_header = opt_header; - opt_header = (struct pgm_opt_header*)(opt_crqst + 1); - } - -/* OPT_FIN */ - if (PGM_OPT_FIN == flags) - { - opt_total_length += sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fin); - opt_header->opt_type = PGM_OPT_FIN; - opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fin); - struct pgm_opt_fin* opt_fin = (struct pgm_opt_fin*)(opt_header + 1); - opt_fin->opt_reserved = 0; - last_opt_header = opt_header; - opt_header = (struct pgm_opt_header*)(opt_fin + 1); - } - - last_opt_header->opt_type |= PGM_OPT_END; - opt_len->opt_total_length = htons (opt_total_length); - } - -/* checksum optional for SPMs */ - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); - - const ssize_t sent = pgm_sendto (sock, - flags != PGM_OPT_SYN && sock->is_controlled_spm, /* rate limited */ - TRUE, /* with router alert */ - buf, - tpdu_length, - (struct sockaddr*)&sock->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { - sock->blocklen = tpdu_length; - return FALSE; - } -/* advance SPM sequence only on successful transmission */ - sock->spm_sqn++; - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); - return TRUE; -} - -/* send a NAK confirm (NCF) message with provided sequence number list. - * - * on success, TRUE is returned, returns FALSE if operation would block. - */ - -static -bool -send_ncf ( - pgm_sock_t* const restrict sock, - const struct sockaddr* const restrict nak_src_nla, - const struct sockaddr* const restrict nak_grp_nla, - const uint32_t sequence, - const bool is_parity /* send parity NCF */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != nak_src_nla); - pgm_assert (NULL != nak_grp_nla); - pgm_assert (nak_src_nla->sa_family == nak_grp_nla->sa_family); - -#ifdef SOURCE_DEBUG - char saddr[INET6_ADDRSTRLEN], gaddr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop (nak_src_nla, saddr, sizeof(saddr)); - pgm_sockaddr_ntop (nak_grp_nla, gaddr, sizeof(gaddr)); - pgm_debug ("send_ncf (sock:%p nak-src-nla:%s nak-grp-nla:%s sequence:%" PRIu32" is-parity:%s)", - (void*)sock, - saddr, - gaddr, - sequence, - is_parity ? "TRUE": "FALSE" - ); -#endif - - size_t tpdu_length = sizeof(struct pgm_header); - tpdu_length += (AF_INET == nak_src_nla->sa_family) ? sizeof(struct pgm_nak) : sizeof(struct pgm_nak6); - char buf[ tpdu_length ]; - struct pgm_header* header = (struct pgm_header*)buf; - struct pgm_nak* ncf = (struct pgm_nak *)(header + 1); - struct pgm_nak6* ncf6 = (struct pgm_nak6*)(header + 1); - memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); - header->pgm_sport = sock->tsi.sport; - header->pgm_dport = sock->dport; - header->pgm_type = PGM_NCF; - header->pgm_options = is_parity ? PGM_OPT_PARITY : 0; - header->pgm_tsdu_length = 0; - -/* NCF */ - ncf->nak_sqn = htonl (sequence); - -/* source nla */ - pgm_sockaddr_to_nla (nak_src_nla, (char*)&ncf->nak_src_nla_afi); - -/* group nla */ - pgm_sockaddr_to_nla (nak_grp_nla, (AF_INET6 == nak_src_nla->sa_family) ? (char*)&ncf6->nak6_grp_nla_afi : (char*)&ncf->nak_grp_nla_afi ); - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); - - const ssize_t sent = pgm_sendto (sock, - FALSE, /* not rate limited */ - TRUE, /* with router alert */ - buf, - tpdu_length, - (struct sockaddr*)&sock->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) - return FALSE; - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); - return TRUE; -} - -/* A NCF packet with a OPT_NAK_LIST option extension - * - * on success, TRUE is returned. on error, FALSE is returned. - */ - -static -bool -send_ncf_list ( - pgm_sock_t* const restrict sock, - const struct sockaddr* const restrict nak_src_nla, - const struct sockaddr* const restrict nak_grp_nla, - struct pgm_sqn_list_t* const restrict sqn_list, /* will change to network-order */ - const bool is_parity /* send parity NCF */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != nak_src_nla); - pgm_assert (NULL != nak_grp_nla); - pgm_assert (sqn_list->len > 1); - pgm_assert (sqn_list->len <= 63); - pgm_assert (nak_src_nla->sa_family == nak_grp_nla->sa_family); - -#ifdef SOURCE_DEBUG - char saddr[INET6_ADDRSTRLEN], gaddr[INET6_ADDRSTRLEN]; - char list[1024]; - pgm_sockaddr_ntop (nak_src_nla, saddr, sizeof(saddr)); - pgm_sockaddr_ntop (nak_grp_nla, gaddr, sizeof(gaddr)); - sprintf (list, "%" PRIu32, sqn_list->sqn[0]); - for (uint_fast8_t i = 1; i < sqn_list->len; i++) { - char sequence[ 2 + strlen("4294967295") ]; - sprintf (sequence, " %" PRIu32, sqn_list->sqn[i]); - strcat (list, sequence); - } - pgm_debug ("send_ncf_list (sock:%p nak-src-nla:%s nak-grp-nla:%s sqn-list:[%s] is-parity:%s)", - (void*)sock, - saddr, - gaddr, - list, - is_parity ? "TRUE": "FALSE" - ); -#endif - - size_t tpdu_length = sizeof(struct pgm_header) + - sizeof(struct pgm_opt_length) + /* includes header */ - sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + - ( (sqn_list->len-1) * sizeof(uint32_t) ); - tpdu_length += (AF_INET == nak_src_nla->sa_family) ? sizeof(struct pgm_nak) : sizeof(struct pgm_nak6); - char buf[ tpdu_length ]; - struct pgm_header* header = (struct pgm_header*)buf; - struct pgm_nak* ncf = (struct pgm_nak *)(header + 1); - struct pgm_nak6* ncf6 = (struct pgm_nak6*)(header + 1); - memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); - header->pgm_sport = sock->tsi.sport; - header->pgm_dport = sock->dport; - header->pgm_type = PGM_NCF; - header->pgm_options = is_parity ? (PGM_OPT_PRESENT | PGM_OPT_NETWORK | PGM_OPT_PARITY) : (PGM_OPT_PRESENT | PGM_OPT_NETWORK); - header->pgm_tsdu_length = 0; -/* NCF */ - ncf->nak_sqn = htonl (sqn_list->sqn[0]); - -/* source nla */ - pgm_sockaddr_to_nla (nak_src_nla, (char*)&ncf->nak_src_nla_afi); - -/* group nla */ - pgm_sockaddr_to_nla (nak_grp_nla, (AF_INET6 == nak_src_nla->sa_family) ? (char*)&ncf6->nak6_grp_nla_afi : (char*)&ncf->nak_grp_nla_afi ); - -/* OPT_NAK_LIST */ - struct pgm_opt_length* opt_len = (AF_INET6 == nak_src_nla->sa_family) ? (struct pgm_opt_length*)(ncf6 + 1) : (struct pgm_opt_length*)(ncf + 1); - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_nak_list) + - ( (sqn_list->len-1) * sizeof(uint32_t) ) ); - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_nak_list) + - ( (sqn_list->len-1) * sizeof(uint32_t) ); - struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); - opt_nak_list->opt_reserved = 0; -/* to network-order */ - for (uint_fast8_t i = 1; i < sqn_list->len; i++) - opt_nak_list->opt_sqn[i-1] = htonl (sqn_list->sqn[i]); - - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); - - const ssize_t sent = pgm_sendto (sock, - FALSE, /* not rate limited */ - TRUE, /* with router alert */ - buf, - tpdu_length, - (struct sockaddr*)&sock->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) - return FALSE; - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); - return TRUE; -} - -/* cancel any pending heartbeat SPM and schedule a new one - */ - -static -void -reset_heartbeat_spm ( - pgm_sock_t* sock, - const pgm_time_t now - ) -{ - pgm_mutex_lock (&sock->timer_mutex); - const pgm_time_t next_poll = sock->next_poll; - const pgm_time_t spm_heartbeat_interval = sock->spm_heartbeat_interval[ sock->spm_heartbeat_state = 1 ]; - sock->next_heartbeat_spm = now + spm_heartbeat_interval; - if (pgm_time_after( next_poll, sock->next_heartbeat_spm )) - { - sock->next_poll = sock->next_heartbeat_spm; - if (!sock->is_pending_read) { - pgm_notify_send (&sock->pending_notify); - sock->is_pending_read = TRUE; - } - } - pgm_mutex_unlock (&sock->timer_mutex); -} - -/* state helper for resuming sends - */ -#define STATE(x) (sock->pkt_dontwait_state.x) - -/* send one PGM data packet, transmit window owned memory. - * - * On success, returns PGM_IO_STATUS_NORMAL and the number of data bytes pushed - * into the transmit window and attempted to send to the socket layer is saved - * into bytes_written. On non-blocking sockets, PGM_IO_STATUS_WOULD_BLOCK is - * returned if the send would block. PGM_IO_STATUS_RATE_LIMITED is returned if - * the packet sizes would exceed the current rate limit. - * - * ! always returns successful if data is pushed into the transmit window, even if - * sendto() double fails ¡ we don't want the application to try again as that is the - * reliable socks role. - */ - -static -int -send_odata ( - pgm_sock_t* const restrict sock, - struct pgm_sk_buff_t* const restrict skb, - size_t* restrict bytes_written - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - pgm_assert (skb->len <= sock->max_tsdu); - - pgm_debug ("send_odata (sock:%p skb:%p bytes-written:%p)", - (void*)sock, (void*)skb, (void*)bytes_written); - - const uint16_t tsdu_length = skb->len; - const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; - const size_t tpdu_length = tsdu_length + pgm_pkt_offset (FALSE, pgmcc_family); - -/* continue if send would block */ - if (sock->is_apdu_eagain) { - STATE(skb)->tstamp = pgm_time_update_now(); - goto retry_send; - } - -/* add PGM header to skbuff */ - STATE(skb) = pgm_skb_get(skb); - STATE(skb)->sock = sock; - STATE(skb)->tstamp = pgm_time_update_now(); - - STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; - STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); - memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); - STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; - STATE(skb)->pgm_header->pgm_dport = sock->dport; - STATE(skb)->pgm_header->pgm_type = PGM_ODATA; - STATE(skb)->pgm_header->pgm_options = sock->use_pgmcc ? PGM_OPT_PRESENT : 0; - STATE(skb)->pgm_header->pgm_tsdu_length = htons (tsdu_length); - -/* ODATA */ - STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); - STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); - - STATE(skb)->pgm_header->pgm_checksum = 0; - void* data = STATE(skb)->pgm_data + 1; - if (sock->use_pgmcc) { - struct pgm_opt_length* opt_len = data; - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - ((AF_INET6 == sock->acker_nla.ss_family) ? - sizeof(struct pgm_opt6_pgmcc_data) : - sizeof(struct pgm_opt_pgmcc_data)) ); - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_PGMCC_DATA | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + - ((AF_INET6 == sock->acker_nla.ss_family) ? - sizeof(struct pgm_opt6_pgmcc_data) : - sizeof(struct pgm_opt_pgmcc_data)); - struct pgm_opt_pgmcc_data* pgmcc_data = (struct pgm_opt_pgmcc_data*)(opt_header + 1); - struct pgm_opt6_pgmcc_data* pgmcc_data6 = (struct pgm_opt6_pgmcc_data*)(opt_header + 1); - - pgmcc_data->opt_tstamp = htonl (pgm_to_msecs (STATE(skb)->tstamp)); -/* acker nla */ - pgm_sockaddr_to_nla ((struct sockaddr*)&sock->acker_nla, (char*)&pgmcc_data->opt_nla_afi); - if (AF_INET6 == sock->acker_nla.ss_family) - data = (char*)pgmcc_data6 + sizeof(struct pgm_opt6_pgmcc_data); - else - data = (char*)pgmcc_data + sizeof(struct pgm_opt_pgmcc_data); - } - const size_t pgm_header_len = (char*)data - (char*)STATE(skb)->pgm_header; - const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); - STATE(unfolded_odata) = pgm_csum_partial (data, tsdu_length, 0); - STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); - -/* add to transmit window, skb::data set to payload */ - pgm_spinlock_lock (&sock->txw_spinlock); - pgm_txw_add (sock->window, STATE(skb)); - pgm_spinlock_unlock (&sock->txw_spinlock); - -/* the transmit window MUST check the user count to ensure it does not - * attempt to send a repair-data packet based on in transit original data. - */ - - ssize_t sent; -retry_send: - -/* congestion control */ - if (sock->use_pgmcc && - sock->tokens < pgm_fp8 (1)) - { -// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Token limit reached.")); - sock->is_apdu_eagain = TRUE; - sock->blocklen = tpdu_length; - return PGM_IO_STATUS_CONGESTION; /* peer expiration to re-elect ACKer */ - } - - sent = pgm_sendto (sock, - sock->is_controlled_odata, /* rate limited */ - FALSE, /* regular socket */ - STATE(skb)->head, - tpdu_length, - (struct sockaddr*)&sock->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { - sock->is_apdu_eagain = TRUE; - sock->blocklen = tpdu_length; - if (EAGAIN == errno) { - if (sock->use_pgmcc) - pgm_notify_clear (&sock->ack_notify); - return PGM_IO_STATUS_WOULD_BLOCK; - } - return PGM_IO_STATUS_RATE_LIMITED; - } - -/* save unfolded odata for retransmissions */ - pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); - - sock->is_apdu_eagain = FALSE; - reset_heartbeat_spm (sock, STATE(skb)->tstamp); - if (sock->use_pgmcc) { - sock->tokens -= pgm_fp8 (1); - sock->ack_expiry = STATE(skb)->tstamp + sock->ack_expiry_ivl; - } - - if (PGM_LIKELY((size_t)sent == tpdu_length)) { - sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += tsdu_length; - sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] ++; - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); - } - -/* check for end of transmission group */ - if (sock->use_proactive_parity) { - const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); - const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; - if (!((odata_sqn + 1) & ~tg_sqn_mask)) - pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); - } - -/* remove applications reference to skbuff */ - pgm_free_skb (STATE(skb)); - if (bytes_written) - *bytes_written = tsdu_length; - return PGM_IO_STATUS_NORMAL; -} - -/* send one PGM original data packet, callee owned memory. - * - * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets - * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if - * packet size exceeds the current rate limit. - */ - -static -int -send_odata_copy ( - pgm_sock_t* const restrict sock, - const void* restrict tsdu, - const uint16_t tsdu_length, - size_t* restrict bytes_written - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (tsdu_length <= sock->max_tsdu); - if (PGM_LIKELY(tsdu_length)) pgm_assert (NULL != tsdu); - - pgm_debug ("send_odata_copy (sock:%p tsdu:%p tsdu_length:%u bytes-written:%p)", - (void*)sock, tsdu, tsdu_length, (void*)bytes_written); - - const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; - const size_t tpdu_length = tsdu_length + pgm_pkt_offset (FALSE, pgmcc_family); - -/* continue if blocked mid-apdu, updating timestamp */ - if (sock->is_apdu_eagain) { - STATE(skb)->tstamp = pgm_time_update_now(); - goto retry_send; - } - - STATE(skb) = pgm_alloc_skb (sock->max_tpdu); - STATE(skb)->sock = sock; - STATE(skb)->tstamp = pgm_time_update_now(); - pgm_skb_reserve (STATE(skb), pgm_pkt_offset (FALSE, pgmcc_family)); - pgm_skb_put (STATE(skb), tsdu_length); - - STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; - STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); - memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); - STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; - STATE(skb)->pgm_header->pgm_dport = sock->dport; - STATE(skb)->pgm_header->pgm_type = PGM_ODATA; - STATE(skb)->pgm_header->pgm_options = sock->use_pgmcc ? PGM_OPT_PRESENT : 0; - STATE(skb)->pgm_header->pgm_tsdu_length = htons (tsdu_length); - -/* ODATA */ - STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); - STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); - - STATE(skb)->pgm_header->pgm_checksum = 0; - void* data = STATE(skb)->pgm_data + 1; - if (sock->use_pgmcc) { - struct pgm_opt_length* opt_len = data; - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - ((AF_INET6 == sock->acker_nla.ss_family) ? - sizeof(struct pgm_opt6_pgmcc_data) : - sizeof(struct pgm_opt_pgmcc_data)) ); - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_PGMCC_DATA | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + - ((AF_INET6 == sock->acker_nla.ss_family) ? - sizeof(struct pgm_opt6_pgmcc_data) : - sizeof(struct pgm_opt_pgmcc_data)); - struct pgm_opt_pgmcc_data* pgmcc_data = (struct pgm_opt_pgmcc_data*)(opt_header + 1); - struct pgm_opt6_pgmcc_data* pgmcc_data6 = (struct pgm_opt6_pgmcc_data*)(opt_header + 1); - - pgmcc_data->opt_reserved = 0; - pgmcc_data->opt_tstamp = htonl (pgm_to_msecs (STATE(skb)->tstamp)); -/* acker nla */ - pgm_sockaddr_to_nla ((struct sockaddr*)&sock->acker_nla, (char*)&pgmcc_data->opt_nla_afi); - data = (char*)opt_header + opt_header->opt_length; - } - const size_t pgm_header_len = (char*)data - (char*)STATE(skb)->pgm_header; - const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); - STATE(unfolded_odata) = pgm_csum_partial_copy (tsdu, data, tsdu_length, 0); - STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); - -/* add to transmit window, skb::data set to payload */ - pgm_spinlock_lock (&sock->txw_spinlock); - pgm_txw_add (sock->window, STATE(skb)); - pgm_spinlock_unlock (&sock->txw_spinlock); - - ssize_t sent; -retry_send: - -/* congestion control */ - if (sock->use_pgmcc && - sock->tokens < pgm_fp8 (1)) - { -// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Token limit reached.")); - sock->is_apdu_eagain = TRUE; - sock->blocklen = tpdu_length; - return PGM_IO_STATUS_CONGESTION; - } - - sent = pgm_sendto (sock, - sock->is_controlled_odata, /* rate limited */ - FALSE, /* regular socket */ - STATE(skb)->head, - tpdu_length, - (struct sockaddr*)&sock->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { - sock->is_apdu_eagain = TRUE; - sock->blocklen = tpdu_length; - if (EAGAIN == errno) { - if (sock->use_pgmcc) - pgm_notify_clear (&sock->ack_notify); - return PGM_IO_STATUS_WOULD_BLOCK; - } - return PGM_IO_STATUS_RATE_LIMITED; - } - - if (sock->use_pgmcc) { - sock->tokens -= pgm_fp8 (1); - pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC tokens-- (T:%u W:%u)"), - pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); - sock->ack_expiry = STATE(skb)->tstamp + sock->ack_expiry_ivl; - } - -/* save unfolded odata for retransmissions */ - pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); - - sock->is_apdu_eagain = FALSE; - reset_heartbeat_spm (sock, STATE(skb)->tstamp); - - if (PGM_LIKELY((size_t)sent == tpdu_length)) { - sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += tsdu_length; - sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] ++; - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); - } - -/* check for end of transmission group */ - if (sock->use_proactive_parity) { - const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); - const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; - if (!((odata_sqn + 1) & ~tg_sqn_mask)) - pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); - } - -/* return data payload length sent */ - if (bytes_written) - *bytes_written = tsdu_length; - return PGM_IO_STATUS_NORMAL; -} - -/* send one PGM original data packet, callee owned scatter/gather io vector - * - * ⎢ DATA₀ ⎢ - * ⎢ DATA₁ ⎢ → send_odatav() → ⎢ TSDU₀ ⎢ → libc - * ⎢ ⋮ ⎢ - * - * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets - * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if - * packet size exceeds the current rate limit. - */ - -static -int -send_odatav ( - pgm_sock_t* const restrict sock, - const struct pgm_iovec* const restrict vector, - const unsigned count, /* number of items in vector */ - size_t* restrict bytes_written - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (count <= PGM_MAX_FRAGMENTS); - if (PGM_LIKELY(count)) pgm_assert (NULL != vector); - - pgm_debug ("send_odatav (sock:%p vector:%p count:%u bytes-written:%p)", - (const void*)sock, (const void*)vector, count, (const void*)bytes_written); - - if (PGM_UNLIKELY(0 == count)) - return send_odata_copy (sock, NULL, 0, bytes_written); - -/* continue if blocked on send */ - if (sock->is_apdu_eagain) - goto retry_send; - - STATE(tsdu_length) = 0; - for (unsigned i = 0; i < count; i++) - { -#ifdef TRANSPORT_DEBUG - if (PGM_LIKELY(vector[i].iov_len)) { - pgm_assert( vector[i].iov_base ); - } -#endif - STATE(tsdu_length) += vector[i].iov_len; - } - pgm_return_val_if_fail (STATE(tsdu_length) <= sock->max_tsdu, PGM_IO_STATUS_ERROR); - - STATE(skb) = pgm_alloc_skb (sock->max_tpdu); - STATE(skb)->sock = sock; - STATE(skb)->tstamp = pgm_time_update_now(); - const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; - pgm_skb_reserve (STATE(skb), pgm_pkt_offset (FALSE, pgmcc_family)); - pgm_skb_put (STATE(skb), STATE(tsdu_length)); - - STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->data; - STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); - memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); - STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; - STATE(skb)->pgm_header->pgm_dport = sock->dport; - STATE(skb)->pgm_header->pgm_type = PGM_ODATA; - STATE(skb)->pgm_header->pgm_options = 0; - STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); - -/* ODATA */ - STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); - STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); - - STATE(skb)->pgm_header->pgm_checksum = 0; - const size_t pgm_header_len = (char*)(STATE(skb)->pgm_data + 1) - (char*)STATE(skb)->pgm_header; - const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); - -/* unroll first iteration to make friendly branch prediction */ - char* dst = (char*)(STATE(skb)->pgm_data + 1); - STATE(unfolded_odata) = pgm_csum_partial_copy ((const char*)vector[0].iov_base, dst, vector[0].iov_len, 0); - -/* iterate over one or more vector elements to perform scatter/gather checksum & copy */ - for (unsigned i = 1; i < count; i++) { - dst += vector[i-1].iov_len; - const uint32_t unfolded_element = pgm_csum_partial_copy ((const char*)vector[i].iov_base, dst, vector[i].iov_len, 0); - STATE(unfolded_odata) = pgm_csum_block_add (STATE(unfolded_odata), unfolded_element, vector[i-1].iov_len); - } - - STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); - -/* add to transmit window, skb::data set to payload */ - pgm_spinlock_lock (&sock->txw_spinlock); - pgm_txw_add (sock->window, STATE(skb)); - pgm_spinlock_unlock (&sock->txw_spinlock); - - ssize_t sent; - size_t tpdu_length; -retry_send: - pgm_assert ((char*)STATE(skb)->tail > (char*)STATE(skb)->head); - tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; - sent = pgm_sendto (sock, - sock->is_controlled_odata, /* rate limited */ - FALSE, /* regular socket */ - STATE(skb)->head, - tpdu_length, - (struct sockaddr*)&sock->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { - sock->is_apdu_eagain = TRUE; - sock->blocklen = tpdu_length; - if (EAGAIN == errno) { - if (sock->use_pgmcc) - pgm_notify_clear (&sock->ack_notify); - return PGM_IO_STATUS_WOULD_BLOCK; - } - return PGM_IO_STATUS_RATE_LIMITED; - } - -/* save unfolded odata for retransmissions */ - pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); - - sock->is_apdu_eagain = FALSE; - reset_heartbeat_spm (sock, STATE(skb)->tstamp); - - if (PGM_LIKELY((size_t)sent == STATE(skb)->len)) { - sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += STATE(tsdu_length); - sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] ++; - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); - } - -/* check for end of transmission group */ - if (sock->use_proactive_parity) { - const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); - const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; - if (!((odata_sqn + 1) & ~tg_sqn_mask)) - pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); - } - -/* return data payload length sent */ - if (bytes_written) - *bytes_written = STATE(tsdu_length); - return PGM_IO_STATUS_NORMAL; -} - -/* send PGM original data, callee owned memory. if larger than maximum TPDU - * size will be fragmented. - * - * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets - * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if - * packet size exceeds the current rate limit. - */ - -static -int -send_apdu ( - pgm_sock_t* const restrict sock, - const void* restrict apdu, - const size_t apdu_length, - size_t* restrict bytes_written - ) -{ - size_t bytes_sent = 0; /* counted at IP layer */ - unsigned packets_sent = 0; /* IP packets */ - size_t data_bytes_sent = 0; - const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; - - pgm_assert (NULL != sock); - pgm_assert (NULL != apdu); - -/* continue if blocked mid-apdu */ - if (sock->is_apdu_eagain) - goto retry_send; - -/* if non-blocking calculate total wire size and check rate limit */ - STATE(is_rate_limited) = FALSE; - if (sock->is_nonblocking && sock->is_controlled_odata) - { - const size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); - size_t tpdu_length = 0; - size_t offset_ = 0; - do { - const uint16_t tsdu_length = MIN( source_max_tsdu (sock, TRUE), apdu_length - offset_ ); - tpdu_length += sock->iphdr_len + header_length + tsdu_length; - offset_ += tsdu_length; - } while (offset_ < apdu_length); - -/* calculation includes one iphdr length already */ - if (!pgm_rate_check (&sock->rate_control, - tpdu_length - sock->iphdr_len, - sock->is_nonblocking)) - { - sock->blocklen = tpdu_length; - return PGM_IO_STATUS_RATE_LIMITED; - } - STATE(is_rate_limited) = TRUE; - } - - STATE(data_bytes_offset) = 0; - STATE(first_sqn) = pgm_txw_next_lead(sock->window); - - do { -/* retrieve packet storage from transmit window */ - size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); - STATE(tsdu_length) = MIN( source_max_tsdu (sock, TRUE), apdu_length - STATE(data_bytes_offset) ); - - STATE(skb) = pgm_alloc_skb (sock->max_tpdu); - STATE(skb)->sock = sock; - STATE(skb)->tstamp = pgm_time_update_now(); - pgm_skb_reserve (STATE(skb), header_length); - pgm_skb_put (STATE(skb), STATE(tsdu_length)); - - STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; - STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); - memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); - STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; - STATE(skb)->pgm_header->pgm_dport = sock->dport; - STATE(skb)->pgm_header->pgm_type = PGM_ODATA; - STATE(skb)->pgm_header->pgm_options = PGM_OPT_PRESENT; - STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); - -/* ODATA */ - STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); - STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); - -/* OPT_LENGTH */ - struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(STATE(skb)->pgm_data + 1); - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fragment) ); -/* OPT_FRAGMENT */ - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fragment); - STATE(skb)->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); - STATE(skb)->pgm_opt_fragment->opt_reserved = 0; - STATE(skb)->pgm_opt_fragment->opt_sqn = htonl (STATE(first_sqn)); - STATE(skb)->pgm_opt_fragment->opt_frag_off = htonl (STATE(data_bytes_offset)); - STATE(skb)->pgm_opt_fragment->opt_frag_len = htonl (apdu_length); - -/* TODO: the assembly checksum & copy routine is faster than memcpy & pgm_cksum on >= opteron hardware */ - STATE(skb)->pgm_header->pgm_checksum = 0; - const size_t pgm_header_len = (char*)(STATE(skb)->pgm_opt_fragment + 1) - (char*)STATE(skb)->pgm_header; - const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); - STATE(unfolded_odata) = pgm_csum_partial_copy ((const char*)apdu + STATE(data_bytes_offset), STATE(skb)->pgm_opt_fragment + 1, STATE(tsdu_length), 0); - STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); - -/* add to transmit window, skb::data set to payload */ - pgm_spinlock_lock (&sock->txw_spinlock); - pgm_txw_add (sock->window, STATE(skb)); - pgm_spinlock_unlock (&sock->txw_spinlock); - - ssize_t sent; - size_t tpdu_length; -retry_send: - pgm_assert ((char*)STATE(skb)->tail > (char*)STATE(skb)->head); - tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; - sent = pgm_sendto (sock, - !STATE(is_rate_limited), /* rate limit on blocking */ - FALSE, /* regular socket */ - STATE(skb)->head, - tpdu_length, - (struct sockaddr*)&sock->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { - sock->is_apdu_eagain = TRUE; - sock->blocklen = tpdu_length; - goto blocked; - } - -/* save unfolded odata for retransmissions */ - pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); - - if (PGM_LIKELY((size_t)sent == tpdu_length)) { - bytes_sent += tpdu_length + sock->iphdr_len; /* as counted at IP layer */ - packets_sent++; /* IP packets */ - data_bytes_sent += STATE(tsdu_length); - } - - STATE(data_bytes_offset) += STATE(tsdu_length); - -/* check for end of transmission group */ - if (sock->use_proactive_parity) { - const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); - const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; - if (!((odata_sqn + 1) & ~tg_sqn_mask)) - pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); - } - - } while ( STATE(data_bytes_offset) < apdu_length); - pgm_assert( STATE(data_bytes_offset) == apdu_length ); - - sock->is_apdu_eagain = FALSE; - reset_heartbeat_spm (sock, STATE(skb)->tstamp); - - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); - sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; - sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; - if (bytes_written) - *bytes_written = apdu_length; - return PGM_IO_STATUS_NORMAL; - -blocked: - if (bytes_sent) { - reset_heartbeat_spm (sock, STATE(skb)->tstamp); - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); - sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; - sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; - } - if (EAGAIN == errno) { - if (sock->use_pgmcc) - pgm_notify_clear (&sock->ack_notify); - return PGM_IO_STATUS_WOULD_BLOCK; - } - return PGM_IO_STATUS_RATE_LIMITED; -} - -/* Send one APDU, whether it fits within one TPDU or more. - * - * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets - * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if - * packet size exceeds the current rate limit. - */ -int -pgm_send ( - pgm_sock_t* const restrict sock, - const void* restrict apdu, - const size_t apdu_length, - size_t* restrict bytes_written - ) -{ - pgm_debug ("pgm_send (sock:%p apdu:%p apdu-length:%zu bytes-written:%p)", - (void*)sock, apdu, apdu_length, (void*)bytes_written); - -/* parameters */ - pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); - if (PGM_LIKELY(apdu_length)) pgm_return_val_if_fail (NULL != apdu, PGM_IO_STATUS_ERROR); - -/* shutdown */ - if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) - pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); - -/* state */ - if (PGM_UNLIKELY(!sock->is_bound || - sock->is_destroyed || - apdu_length > sock->max_apdu)) - { - pgm_rwlock_reader_unlock (&sock->lock); - pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); - } - -/* source */ - pgm_mutex_lock (&sock->source_mutex); - -/* pass on non-fragment calls */ - if (apdu_length <= sock->max_tsdu) - { - const int status = send_odata_copy (sock, apdu, apdu_length, bytes_written); - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return status; - } - - const int status = send_apdu (sock, apdu, apdu_length, bytes_written); - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return status; -} - -/* send PGM original data, callee owned scatter/gather IO vector. if larger than maximum TPDU - * size will be fragmented. - * - * is_one_apdu = true: - * - * ⎢ DATA₀ ⎢ - * ⎢ DATA₁ ⎢ → pgm_sendv() → ⎢ ⋯ TSDU₁ TSDU₀ ⎢ → libc - * ⎢ ⋮ ⎢ - * - * is_one_apdu = false: - * - * ⎢ APDU₀ ⎢ ⎢ ⋯ TSDU₁,₀ TSDU₀,₀ ⎢ - * ⎢ APDU₁ ⎢ → pgm_sendv() → ⎢ ⋯ TSDU₁,₁ TSDU₀,₁ ⎢ → libc - * ⎢ ⋮ ⎢ ⎢ ⋮ ⋮ ⎢ - * - * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets - * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if - * packet size exceeds the current rate limit. - */ - -int -pgm_sendv ( - pgm_sock_t* const restrict sock, - const struct pgm_iovec* const restrict vector, - const unsigned count, /* number of items in vector */ - const bool is_one_apdu, /* true = vector = apdu, false = vector::iov_base = apdu */ - size_t* restrict bytes_written - ) -{ - pgm_debug ("pgm_sendv (sock:%p vector:%p count:%u is-one-apdu:%s bytes-written:%p)", - (const void*)sock, - (const void*)vector, - count, - is_one_apdu ? "TRUE" : "FALSE", - (const void*)bytes_written); - - pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); - pgm_return_val_if_fail (count <= PGM_MAX_FRAGMENTS, PGM_IO_STATUS_ERROR); - if (PGM_LIKELY(count)) pgm_return_val_if_fail (NULL != vector, PGM_IO_STATUS_ERROR); - if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) - pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); - if (PGM_UNLIKELY(!sock->is_bound || - sock->is_destroyed)) - { - pgm_rwlock_reader_unlock (&sock->lock); - pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); - } - - pgm_mutex_lock (&sock->source_mutex); - -/* pass on zero length as cannot count vector lengths */ - if (PGM_UNLIKELY(0 == count)) - { - const int status = send_odata_copy (sock, NULL, count, bytes_written); - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return status; - } - - size_t bytes_sent = 0; - unsigned packets_sent = 0; - size_t data_bytes_sent = 0; - const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; - -/* continue if blocked mid-apdu */ - if (sock->is_apdu_eagain) { - if (is_one_apdu) { - if (STATE(apdu_length) <= sock->max_tsdu) - { - const int status = send_odatav (sock, vector, count, bytes_written); - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return status; - } - else - goto retry_one_apdu_send; - } else { - goto retry_send; - } - } - -/* calculate (total) APDU length */ - STATE(apdu_length) = 0; - for (unsigned i = 0; i < count; i++) - { -#ifdef TRANSPORT_DEBUG - if (PGM_LIKELY(vector[i].iov_len)) { - pgm_assert( vector[i].iov_base ); - } -#endif - if (!is_one_apdu && - vector[i].iov_len > sock->max_apdu) - { - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); - } - STATE(apdu_length) += vector[i].iov_len; - } - -/* pass on non-fragment calls */ - if (is_one_apdu) { - if (STATE(apdu_length) <= sock->max_tsdu) { - const int status = send_odatav (sock, vector, count, bytes_written); - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return status; - } else if (STATE(apdu_length) > sock->max_apdu) { - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); - } - } - -/* if non-blocking calculate total wire size and check rate limit */ - STATE(is_rate_limited) = FALSE; - if (sock->is_nonblocking && sock->is_controlled_odata) - { - const size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); - size_t tpdu_length = 0; - size_t offset_ = 0; - do { - const uint16_t tsdu_length = MIN( source_max_tsdu (sock, TRUE), STATE(apdu_length) - offset_ ); - tpdu_length += sock->iphdr_len + header_length + tsdu_length; - offset_ += tsdu_length; - } while (offset_ < STATE(apdu_length)); - -/* calculation includes one iphdr length already */ - if (!pgm_rate_check (&sock->rate_control, - tpdu_length - sock->iphdr_len, - sock->is_nonblocking)) - { - sock->blocklen = tpdu_length; - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_RATE_LIMITED; - } - STATE(is_rate_limited) = TRUE; - } - -/* non-fragmented packets can be forwarded onto basic send() */ - if (!is_one_apdu) - { - for (STATE(data_pkt_offset) = 0; STATE(data_pkt_offset) < count; STATE(data_pkt_offset)++) - { - size_t wrote_bytes; - int status; -retry_send: - status = send_apdu (sock, - vector[STATE(data_pkt_offset)].iov_base, - vector[STATE(data_pkt_offset)].iov_len, - &wrote_bytes); - switch (status) { - case PGM_IO_STATUS_NORMAL: - break; - case PGM_IO_STATUS_WOULD_BLOCK: - case PGM_IO_STATUS_RATE_LIMITED: - sock->is_apdu_eagain = TRUE; - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return status; - case PGM_IO_STATUS_ERROR: - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return status; - default: - pgm_assert_not_reached(); - } - data_bytes_sent += wrote_bytes; - } - - sock->is_apdu_eagain = FALSE; - if (bytes_written) - *bytes_written = data_bytes_sent; - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_NORMAL; - } - - STATE(data_bytes_offset) = 0; - STATE(vector_index) = 0; - STATE(vector_offset) = 0; - - STATE(first_sqn) = pgm_txw_next_lead(sock->window); - - do { -/* retrieve packet storage from transmit window */ - size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); - STATE(tsdu_length) = MIN( source_max_tsdu (sock, TRUE), STATE(apdu_length) - STATE(data_bytes_offset) ); - STATE(skb) = pgm_alloc_skb (sock->max_tpdu); - STATE(skb)->sock = sock; - STATE(skb)->tstamp = pgm_time_update_now(); - pgm_skb_reserve (STATE(skb), header_length); - pgm_skb_put (STATE(skb), STATE(tsdu_length)); - - STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; - STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); - memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); - STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; - STATE(skb)->pgm_header->pgm_dport = sock->dport; - STATE(skb)->pgm_header->pgm_type = PGM_ODATA; - STATE(skb)->pgm_header->pgm_options = PGM_OPT_PRESENT; - STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); - -/* ODATA */ - STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); - STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); - -/* OPT_LENGTH */ - struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(STATE(skb)->pgm_data + 1); - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fragment) ); -/* OPT_FRAGMENT */ - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fragment); - STATE(skb)->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); - STATE(skb)->pgm_opt_fragment->opt_reserved = 0; - STATE(skb)->pgm_opt_fragment->opt_sqn = htonl (STATE(first_sqn)); - STATE(skb)->pgm_opt_fragment->opt_frag_off = htonl (STATE(data_bytes_offset)); - STATE(skb)->pgm_opt_fragment->opt_frag_len = htonl (STATE(apdu_length)); - -/* checksum & copy */ - STATE(skb)->pgm_header->pgm_checksum = 0; - const size_t pgm_header_len = (char*)(STATE(skb)->pgm_opt_fragment + 1) - (char*)STATE(skb)->pgm_header; - const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); - -/* iterate over one or more vector elements to perform scatter/gather checksum & copy - * - * STATE(vector_index) - index into application scatter/gather vector - * STATE(vector_offset) - current offset into current vector element - * STATE(unfolded_odata)- checksum accumulator - */ - const char* src = (const char*)vector[STATE(vector_index)].iov_base + STATE(vector_offset); - char* dst = (char*)(STATE(skb)->pgm_opt_fragment + 1); - size_t src_length = vector[STATE(vector_index)].iov_len - STATE(vector_offset); - size_t dst_length = 0; - size_t copy_length = MIN( STATE(tsdu_length), src_length ); - STATE(unfolded_odata) = pgm_csum_partial_copy (src, dst, copy_length, 0); - - for(;;) - { - if (copy_length == src_length) { -/* application packet complete */ - STATE(vector_index)++; - STATE(vector_offset) = 0; - } else { -/* data still remaining */ - STATE(vector_offset) += copy_length; - } - - dst_length += copy_length; - -/* sock packet complete */ - if (dst_length == STATE(tsdu_length)) - break; - - src = (const char*)vector[STATE(vector_index)].iov_base + STATE(vector_offset); - dst += copy_length; - src_length = vector[STATE(vector_index)].iov_len - STATE(vector_offset); - copy_length = MIN( STATE(tsdu_length) - dst_length, src_length ); - const uint32_t unfolded_element = pgm_csum_partial_copy (src, dst, copy_length, 0); - STATE(unfolded_odata) = pgm_csum_block_add (STATE(unfolded_odata), unfolded_element, dst_length); - } - - STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); - -/* add to transmit window, skb::data set to payload */ - pgm_spinlock_lock (&sock->txw_spinlock); - pgm_txw_add (sock->window, STATE(skb)); - pgm_spinlock_unlock (&sock->txw_spinlock); - - ssize_t sent; - size_t tpdu_length; -retry_one_apdu_send: - tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; - sent = pgm_sendto (sock, - !STATE(is_rate_limited), /* rate limited on blocking */ - FALSE, /* regular socket */ - STATE(skb)->head, - tpdu_length, - (struct sockaddr*)&sock->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { - sock->is_apdu_eagain = TRUE; - sock->blocklen = tpdu_length; - goto blocked; - } - -/* save unfolded odata for retransmissions */ - pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); - - if (PGM_LIKELY((size_t)sent == tpdu_length)) { - bytes_sent += tpdu_length + sock->iphdr_len; /* as counted at IP layer */ - packets_sent++; /* IP packets */ - data_bytes_sent += STATE(tsdu_length); - } - - STATE(data_bytes_offset) += STATE(tsdu_length); - -/* check for end of transmission group */ - if (sock->use_proactive_parity) { - const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); - const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; - if (!((odata_sqn + 1) & ~tg_sqn_mask)) - pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); - } - - } while ( STATE(data_bytes_offset) < STATE(apdu_length) ); - pgm_assert( STATE(data_bytes_offset) == STATE(apdu_length) ); - - sock->is_apdu_eagain = FALSE; - reset_heartbeat_spm (sock, STATE(skb)->tstamp); - - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); - sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; - sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; - if (bytes_written) - *bytes_written = STATE(apdu_length); - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_NORMAL; - -blocked: - if (bytes_sent) { - reset_heartbeat_spm (sock, STATE(skb)->tstamp); - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); - sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; - sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; - } - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - if (EAGAIN == errno) { - if (sock->use_pgmcc) - pgm_notify_clear (&sock->ack_notify); - return PGM_IO_STATUS_WOULD_BLOCK; - } - return PGM_IO_STATUS_RATE_LIMITED; -} - -/* send PGM original data, transmit window owned scatter/gather IO vector. - * - * ⎢ TSDU₀ ⎢ - * ⎢ TSDU₁ ⎢ → pgm_send_skbv() → ⎢ ⋯ TSDU₁ TSDU₀ ⎢ → libc - * ⎢ ⋮ ⎢ - * - * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets - * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if - * packet size exceeds the current rate limit. - */ - -int -pgm_send_skbv ( - pgm_sock_t* const restrict sock, - struct pgm_sk_buff_t** const restrict vector, /* array of skb pointers vs. array of skbs */ - const unsigned count, - const bool is_one_apdu, /* true: vector = apdu, false: vector::iov_base = apdu */ - size_t* restrict bytes_written - ) -{ - pgm_debug ("pgm_send_skbv (sock:%p vector:%p count:%u is-one-apdu:%s bytes-written:%p)", - (const void*)sock, - (const void*)vector, - count, - is_one_apdu ? "TRUE" : "FALSE", - (const void*)bytes_written); - - pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); - pgm_return_val_if_fail (count <= PGM_MAX_FRAGMENTS, PGM_IO_STATUS_ERROR); - if (PGM_LIKELY(count)) pgm_return_val_if_fail (NULL != vector, PGM_IO_STATUS_ERROR); - if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) - pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); - if (PGM_UNLIKELY(!sock->is_bound || - sock->is_destroyed)) - { - pgm_rwlock_reader_unlock (&sock->lock); - pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); - } - - pgm_mutex_lock (&sock->source_mutex); - -/* pass on zero length as cannot count vector lengths */ - if (PGM_UNLIKELY(0 == count)) - { - const int status = send_odata_copy (sock, NULL, count, bytes_written); - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return status; - } - else if (1 == count) - { - const int status = send_odata (sock, vector[0], bytes_written); - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return status; - } - - size_t bytes_sent = 0; - unsigned packets_sent = 0; - size_t data_bytes_sent = 0; - const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; - -/* continue if blocked mid-apdu */ - if (sock->is_apdu_eagain) - goto retry_send; - - STATE(is_rate_limited) = FALSE; - if (sock->is_nonblocking && sock->is_controlled_odata) - { - size_t total_tpdu_length = 0; - for (unsigned i = 0; i < count; i++) - total_tpdu_length += sock->iphdr_len + pgm_pkt_offset (is_one_apdu, pgmcc_family) + vector[i]->len; - -/* calculation includes one iphdr length already */ - if (!pgm_rate_check (&sock->rate_control, - total_tpdu_length - sock->iphdr_len, - sock->is_nonblocking)) - { - sock->blocklen = total_tpdu_length; - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_RATE_LIMITED; - } - STATE(is_rate_limited) = TRUE; - } - - if (is_one_apdu) - { - STATE(apdu_length) = 0; - STATE(first_sqn) = pgm_txw_next_lead(sock->window); - for (unsigned i = 0; i < count; i++) - { - if (PGM_UNLIKELY(vector[i]->len > sock->max_tsdu_fragment)) { - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_ERROR; - } - STATE(apdu_length) += vector[i]->len; - } - if (PGM_UNLIKELY(STATE(apdu_length) > sock->max_apdu)) { - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_ERROR; - } - } - - for (STATE(vector_index) = 0; STATE(vector_index) < count; STATE(vector_index)++) - { - STATE(tsdu_length) = vector[STATE(vector_index)]->len; - - STATE(skb) = pgm_skb_get(vector[STATE(vector_index)]); - STATE(skb)->sock = sock; - STATE(skb)->tstamp = pgm_time_update_now(); - - STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; - STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); - memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); - STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; - STATE(skb)->pgm_header->pgm_dport = sock->dport; - STATE(skb)->pgm_header->pgm_type = PGM_ODATA; - STATE(skb)->pgm_header->pgm_options = is_one_apdu ? PGM_OPT_PRESENT : 0; - STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); - -/* ODATA */ - STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); - STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); - - if (is_one_apdu) - { -/* OPT_LENGTH */ - struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(STATE(skb)->pgm_data + 1); - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fragment) ); -/* OPT_FRAGMENT */ - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fragment); - STATE(skb)->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); - STATE(skb)->pgm_opt_fragment->opt_reserved = 0; - STATE(skb)->pgm_opt_fragment->opt_sqn = htonl (STATE(first_sqn)); - STATE(skb)->pgm_opt_fragment->opt_frag_off = htonl (STATE(data_bytes_offset)); - STATE(skb)->pgm_opt_fragment->opt_frag_len = htonl (STATE(apdu_length)); - - pgm_assert (STATE(skb)->data == (STATE(skb)->pgm_opt_fragment + 1)); - } - else - { - pgm_assert (STATE(skb)->data == (STATE(skb)->pgm_data + 1)); - } - -/* TODO: the assembly checksum & copy routine is faster than memcpy & pgm_cksum on >= opteron hardware */ - STATE(skb)->pgm_header->pgm_checksum = 0; - pgm_assert ((char*)STATE(skb)->data > (char*)STATE(skb)->pgm_header); - const size_t pgm_header_len = (char*)STATE(skb)->data - (char*)STATE(skb)->pgm_header; - const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); - STATE(unfolded_odata) = pgm_csum_partial ((char*)STATE(skb)->data, STATE(tsdu_length), 0); - STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); - -/* add to transmit window, skb::data set to payload */ - pgm_spinlock_lock (&sock->txw_spinlock); - pgm_txw_add (sock->window, STATE(skb)); - pgm_spinlock_unlock (&sock->txw_spinlock); - ssize_t sent; - size_t tpdu_length; -retry_send: - pgm_assert ((char*)STATE(skb)->tail > (char*)STATE(skb)->head); - tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; - sent = pgm_sendto (sock, - !STATE(is_rate_limited), /* rate limited on blocking */ - FALSE, /* regular socket */ - STATE(skb)->head, - tpdu_length, - (struct sockaddr*)&sock->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); - if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { - sock->is_apdu_eagain = TRUE; - sock->blocklen = tpdu_length; - goto blocked; - } - -/* save unfolded odata for retransmissions */ - pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); - - if (PGM_LIKELY((size_t)sent == tpdu_length)) { - bytes_sent += tpdu_length + sock->iphdr_len; /* as counted at IP layer */ - packets_sent++; /* IP packets */ - data_bytes_sent += STATE(tsdu_length); - } - - pgm_free_skb (STATE(skb)); - STATE(data_bytes_offset) += STATE(tsdu_length); - -/* check for end of transmission group */ - if (sock->use_proactive_parity) { - const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); - const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; - if (!((odata_sqn + 1) & ~tg_sqn_mask)) - pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); - } - - } -#ifdef TRANSPORT_DEBUG - if (is_one_apdu) - { - pgm_assert( STATE(data_bytes_offset) == STATE(apdu_length) ); - } -#endif - - sock->is_apdu_eagain = FALSE; - reset_heartbeat_spm (sock, STATE(skb)->tstamp); - - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); - sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; - sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; - if (bytes_written) - *bytes_written = data_bytes_sent; - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - return PGM_IO_STATUS_NORMAL; - -blocked: - if (bytes_sent) { - reset_heartbeat_spm (sock, STATE(skb)->tstamp); - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); - sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; - sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; - } - pgm_mutex_unlock (&sock->source_mutex); - pgm_rwlock_reader_unlock (&sock->lock); - if (EAGAIN == errno) { - if (sock->use_pgmcc) - pgm_notify_clear (&sock->ack_notify); - return PGM_IO_STATUS_WOULD_BLOCK; - } - return PGM_IO_STATUS_RATE_LIMITED; -} - -/* cleanup resuming send state helper - */ -#undef STATE - -/* send repair packet. - * - * on success, TRUE is returned. on error, FALSE is returned. - */ - -static -bool -send_rdata ( - pgm_sock_t* restrict sock, - struct pgm_sk_buff_t* restrict skb - ) -{ -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (NULL != skb); - pgm_assert ((char*)skb->tail > (char*)skb->head); - - const size_t tpdu_length = (char*)skb->tail - (char*)skb->head; - -/* update previous odata/rdata contents */ - struct pgm_header* header = skb->pgm_header; - struct pgm_data* rdata = skb->pgm_data; - header->pgm_type = PGM_RDATA; -/* RDATA */ - rdata->data_trail = htonl (pgm_txw_trail(sock->window)); - - header->pgm_checksum = 0; - const size_t pgm_header_len = tpdu_length - ntohs(header->pgm_tsdu_length); - uint32_t unfolded_header = pgm_csum_partial (header, pgm_header_len, 0); - uint32_t unfolded_odata = pgm_txw_get_unfolded_checksum (skb); - header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, unfolded_odata, pgm_header_len)); - -/* congestion control */ - if (sock->use_pgmcc && - sock->tokens < pgm_fp8 (1)) - { -// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Token limit reached.")); - sock->blocklen = tpdu_length; - return FALSE; - } - - const ssize_t sent = pgm_sendto (sock, - sock->is_controlled_rdata, /* rate limited */ - TRUE, /* with router alert */ - header, - tpdu_length, - (struct sockaddr*)&sock->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); - - if (sent < 0 && EAGAIN == errno) { - sock->blocklen = tpdu_length; - return FALSE; - } - - const pgm_time_t now = pgm_time_update_now(); - - if (sock->use_pgmcc) { - sock->tokens -= pgm_fp8 (1); - sock->ack_expiry = now + sock->ack_expiry_ivl; - } - -/* re-set spm timer: we are already in the timer thread, no need to prod timers - */ - pgm_mutex_lock (&sock->timer_mutex); - sock->spm_heartbeat_state = 1; - sock->next_heartbeat_spm = now + sock->spm_heartbeat_interval[sock->spm_heartbeat_state++]; - pgm_mutex_unlock (&sock->timer_mutex); - - pgm_txw_inc_retransmit_count (skb); - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED] += ntohs(header->pgm_tsdu_length); - sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED]++; /* impossible to determine APDU count */ - pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); - return TRUE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/source_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/source_unittest.c deleted file mode 100644 index 27ffebe..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/source_unittest.c +++ /dev/null @@ -1,1216 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for PGM source transport. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* mock state */ - -#define TEST_NETWORK "" -#define TEST_PORT 7500 -#define TEST_MAX_TPDU 1500 -#define TEST_TXW_SQNS 32 -#define TEST_RXW_SQNS 32 -#define TEST_HOPS 16 -#define TEST_SPM_AMBIENT ( pgm_secs(30) ) -#define TEST_SPM_HEARTBEAT_INIT { pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(1300), pgm_secs(7), pgm_secs(16), pgm_secs(25), pgm_secs(30) } -#define TEST_PEER_EXPIRY ( pgm_secs(300) ) -#define TEST_SPMR_EXPIRY ( pgm_msecs(250) ) -#define TEST_NAK_BO_IVL ( pgm_msecs(50) ) -#define TEST_NAK_RPT_IVL ( pgm_secs(2) ) -#define TEST_NAK_RDATA_IVL ( pgm_secs(2) ) -#define TEST_NAK_DATA_RETRIES 5 -#define TEST_NAK_NCF_RETRIES 2 - -static gboolean mock_is_valid_spmr = TRUE; -static gboolean mock_is_valid_ack = TRUE; -static gboolean mock_is_valid_nak = TRUE; -static gboolean mock_is_valid_nnak = TRUE; - - -#define pgm_txw_get_unfolded_checksum mock_pgm_txw_get_unfolded_checksum -#define pgm_txw_set_unfolded_checksum mock_pgm_txw_set_unfolded_checksum -#define pgm_txw_inc_retransmit_count mock_pgm_txw_inc_retransmit_count -#define pgm_txw_add mock_pgm_txw_add -#define pgm_txw_peek mock_pgm_txw_peek -#define pgm_txw_retransmit_push mock_pgm_txw_retransmit_push -#define pgm_txw_retransmit_try_peek mock_pgm_txw_retransmit_try_peek -#define pgm_txw_retransmit_remove_head mock_pgm_txw_retransmit_remove_head -#define pgm_rs_encode mock_pgm_rs_encode -#define pgm_rate_check mock_pgm_rate_check -#define pgm_verify_spmr mock_pgm_verify_spmr -#define pgm_verify_ack mock_pgm_verify_ack -#define pgm_verify_nak mock_pgm_verify_nak -#define pgm_verify_nnak mock_pgm_verify_nnak -#define pgm_compat_csum_partial mock_pgm_compat_csum_partial -#define pgm_compat_csum_partial_copy mock_pgm_compat_csum_partial_copy -#define pgm_csum_block_add mock_pgm_csum_block_add -#define pgm_csum_fold mock_pgm_csum_fold -#define pgm_sendto mock_pgm_sendto -#define pgm_time_update_now mock_pgm_time_update_now - - -#define SOURCE_DEBUG -#include "source.c" - - -static -void -mock_setup (void) -{ - if (!g_thread_supported ()) g_thread_init (NULL); -} - -static -struct pgm_sock_t* -generate_sock (void) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, g_htons(1000) }; - struct pgm_sock_t* sock = g_new0 (struct pgm_sock_t, 1); - memcpy (&sock->tsi, &tsi, sizeof(pgm_tsi_t)); - ((struct sockaddr*)&sock->send_addr)->sa_family = AF_INET; - ((struct sockaddr_in*)&sock->send_addr)->sin_addr.s_addr = inet_addr ("127.0.0.2"); - ((struct sockaddr*)&sock->send_gsr.gsr_group)->sa_family = AF_INET; - ((struct sockaddr_in*)&sock->send_gsr.gsr_group)->sin_addr.s_addr = inet_addr ("239.192.0.1"); - sock->dport = g_htons(TEST_PORT); - sock->window = g_malloc0 (sizeof(pgm_txw_t)); - sock->txw_sqns = TEST_TXW_SQNS; - sock->max_tpdu = TEST_MAX_TPDU; - sock->max_tsdu = TEST_MAX_TPDU - sizeof(struct pgm_ip) - pgm_pkt_offset (FALSE, FALSE); - sock->max_tsdu_fragment = TEST_MAX_TPDU - sizeof(struct pgm_ip) - pgm_pkt_offset (TRUE, FALSE); - sock->max_apdu = MIN(TEST_TXW_SQNS, PGM_MAX_FRAGMENTS) * sock->max_tsdu_fragment; - sock->iphdr_len = sizeof(struct pgm_ip); - sock->spm_heartbeat_interval = g_malloc0 (sizeof(guint) * (2+2)); - sock->spm_heartbeat_interval[0] = pgm_secs(1); - pgm_spinlock_init (&sock->txw_spinlock); - sock->is_bound = FALSE; - sock->is_destroyed = FALSE; - return sock; -} - -static -struct pgm_sk_buff_t* -generate_skb (void) -{ - const char source[] = "i am not a string"; - struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); - pgm_skb_reserve (skb, pgm_pkt_offset (FALSE, FALSE)); - pgm_skb_put (skb, sizeof(source)); - memcpy (skb->data, source, sizeof(source)); - return skb; -} - -static -struct pgm_sk_buff_t* -generate_fragment_skb (void) -{ - const char source[] = "i am not a string"; - struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); - pgm_skb_reserve (skb, pgm_pkt_offset (TRUE, FALSE)); - pgm_skb_put (skb, sizeof(source)); - memcpy (skb->data, source, sizeof(source)); - return skb; -} - -static -struct pgm_sk_buff_t* -generate_odata (void) -{ - const char source[] = "i am not a string"; - const guint16 header_length = sizeof(struct pgm_header) + sizeof(struct pgm_data); - struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); - pgm_skb_reserve (skb, header_length); - memset (skb->head, 0, header_length); - skb->pgm_header = (struct pgm_header*)skb->head; - skb->pgm_data = (struct pgm_data*)(skb->pgm_header + 1); - skb->pgm_header->pgm_type = PGM_ODATA; - skb->pgm_header->pgm_tsdu_length = g_htons (sizeof(source)); - memcpy (skb->data, source, sizeof(source)); - pgm_skb_put (skb, sizeof(source)); -/* reverse pull */ - skb->len += (guint8*)skb->data - (guint8*)skb->head; - skb->data = skb->head; - return skb; -} - -static -pgm_peer_t* -generate_peer (void) -{ - pgm_peer_t* peer = g_malloc0 (sizeof(pgm_peer_t)); - return peer; -} - -static -struct pgm_sk_buff_t* -generate_spmr (void) -{ - struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); - const guint16 header_length = sizeof(struct pgm_header); - pgm_skb_reserve (skb, header_length); - memset (skb->head, 0, header_length); - skb->pgm_header = (struct pgm_header*)skb->head; - skb->pgm_header->pgm_type = PGM_SPMR; - pgm_skb_put (skb, header_length); - return skb; -} - -static -struct pgm_sk_buff_t* -generate_single_nak (void) -{ - struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); - const guint16 header_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); - pgm_skb_reserve (skb, sizeof(struct pgm_header)); - memset (skb->head, 0, header_length); - skb->pgm_header = (struct pgm_header*)skb->head; - skb->pgm_header->pgm_type = PGM_NAK; - struct pgm_nak* nak = (struct pgm_nak*)(skb->pgm_header + 1); - struct sockaddr_in nla = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr("127.0.0.2") - }; - pgm_sockaddr_to_nla ((struct sockaddr*)&nla, (char*)&nak->nak_src_nla_afi); - struct sockaddr_in group = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr("239.192.0.1") - }; - pgm_sockaddr_to_nla ((struct sockaddr*)&group, (char*)&nak->nak_grp_nla_afi); - pgm_skb_put (skb, header_length); - return skb; -} - -static -struct pgm_sk_buff_t* -generate_single_nnak (void) -{ - struct pgm_sk_buff_t* skb = generate_single_nak (); - skb->pgm_header->pgm_type = PGM_NNAK; - return skb; -} - -static -struct pgm_sk_buff_t* -generate_parity_nak (void) -{ - struct pgm_sk_buff_t* skb = generate_single_nak (); - skb->pgm_header->pgm_options = PGM_OPT_PARITY; - return skb; -} - -static -struct pgm_sk_buff_t* -generate_nak_list (void) -{ - struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); - const guint16 header_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak) + - sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + - ( 62 * sizeof(guint32) ); - pgm_skb_reserve (skb, sizeof(struct pgm_header)); - memset (skb->head, 0, header_length); - skb->pgm_header = (struct pgm_header*)skb->head; - skb->pgm_header->pgm_type = PGM_NAK; - skb->pgm_header->pgm_options = PGM_OPT_PRESENT | PGM_OPT_NETWORK; - struct pgm_nak *nak = (struct pgm_nak*)(skb->pgm_header + 1); - struct sockaddr_in nla = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr("127.0.0.2") - }; - pgm_sockaddr_to_nla ((struct sockaddr*)&nla, (char*)&nak->nak_src_nla_afi); - struct sockaddr_in group = { - .sin_family = AF_INET, - .sin_addr.s_addr = inet_addr("239.192.0.1") - }; - pgm_sockaddr_to_nla ((struct sockaddr*)&group, (char*)&nak->nak_grp_nla_afi); - struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(nak + 1); - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = g_htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_nak_list) + - ( 62 * sizeof(guint32) ) ); - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + - ( 62 * sizeof(guint32) ); - struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); - for (unsigned i = 1; i < 63; i++) { - opt_nak_list->opt_sqn[i-1] = g_htonl (i); - } - pgm_skb_put (skb, header_length); - return skb; -} - -static -struct pgm_sk_buff_t* -generate_parity_nak_list (void) -{ - struct pgm_sk_buff_t* skb = generate_nak_list (); - skb->pgm_header->pgm_options = PGM_OPT_PARITY | PGM_OPT_PRESENT | PGM_OPT_NETWORK; - return skb; -} - -void -mock_pgm_txw_add ( - pgm_txw_t* const window, - struct pgm_sk_buff_t* const skb - ) -{ - g_debug ("mock_pgm_txw_add (window:%p skb:%p)", - (gpointer)window, (gpointer)skb); -} - -struct pgm_sk_buff_t* -mock_pgm_txw_peek ( - const pgm_txw_t* const window, - const uint32_t sequence - ) -{ - g_debug ("mock_pgm_txw_peek (window:%p sequence:%" G_GUINT32_FORMAT ")", - (gpointer)window, sequence); - return NULL; -} - -bool -mock_pgm_txw_retransmit_push ( - pgm_txw_t* const window, - const uint32_t sequence, - const bool is_parity, - const uint8_t tg_sqn_shift - ) -{ - g_debug ("mock_pgm_txw_retransmit_push (window:%p sequence:%" G_GUINT32_FORMAT " is-parity:%s tg-sqn-shift:%d)", - (gpointer)window, - sequence, - is_parity ? "YES" : "NO", - tg_sqn_shift); - return TRUE; -} - -void -mock_pgm_txw_set_unfolded_checksum ( - struct pgm_sk_buff_t*const skb, - const uint32_t csum - ) -{ -} - -uint32_t -pgm_txw_get_unfolded_checksum ( - const struct pgm_sk_buff_t*const skb - ) -{ - return 0; -} - -void -mock_pgm_txw_inc_retransmit_count ( - struct pgm_sk_buff_t*const skb - ) -{ -} - -struct pgm_sk_buff_t* -mock_pgm_txw_retransmit_try_peek ( - pgm_txw_t* const window - ) -{ - g_debug ("mock_pgm_txw_retransmit_try_peek (window:%p)", - (gpointer)window); - return generate_odata (); -} - -void -mock_pgm_txw_retransmit_remove_head ( - pgm_txw_t* const window - ) -{ - g_debug ("mock_pgm_txw_retransmit_remove_head (window:%p)", - (gpointer)window); -} - -void -mock_pgm_rs_encode ( - pgm_rs_t* rs, - const pgm_gf8_t** src, - uint8_t offset, - pgm_gf8_t* dst, - uint16_t len - ) -{ - g_debug ("mock_pgm_rs_encode (rs:%p src:%p offset:%u dst:%p len:%" G_GSIZE_FORMAT ")", - rs, src, offset, dst, len); -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_rate_check ( - pgm_rate_t* bucket, - const size_t data_size, - const bool is_nonblocking - ) -{ - g_debug ("mock_pgm_rate_check (bucket:%p data-size:%u is-nonblocking:%s)", - bucket, data_size, is_nonblocking ? "TRUE" : "FALSE"); - return TRUE; -} - -bool -mock_pgm_verify_spmr ( - const struct pgm_sk_buff_t* const skb - ) -{ - return mock_is_valid_spmr; -} - -bool -mock_pgm_verify_ack ( - const struct pgm_sk_buff_t* const skb - ) -{ - return mock_is_valid_ack; -} - -bool -mock_pgm_verify_nak ( - const struct pgm_sk_buff_t* const skb - ) -{ - return mock_is_valid_nak; -} - -bool -mock_pgm_verify_nnak ( - const struct pgm_sk_buff_t* const skb - ) -{ - return mock_is_valid_nnak; -} - -uint32_t -mock_pgm_compat_csum_partial ( - const void* addr, - uint16_t len, - uint32_t csum - ) -{ - return 0x0; -} - -uint32_t -mock_pgm_compat_csum_partial_copy ( - const void* src, - void* dst, - uint16_t len, - uint32_t csum - ) -{ - return 0x0; -} - -uint32_t -mock_pgm_csum_block_add ( - uint32_t csum, - uint32_t csum2, - uint16_t offset - ) -{ - return 0x0; -} - -uint16_t -mock_pgm_csum_fold ( - uint32_t csum - ) -{ - return 0x0; -} - -PGM_GNUC_INTERNAL -ssize_t -mock_pgm_sendto ( - pgm_sock_t* sock, - bool use_rate_limit, - bool use_router_alert, - const void* buf, - size_t len, - const struct sockaddr* to, - socklen_t tolen - ) -{ - char saddr[INET6_ADDRSTRLEN]; - pgm_sockaddr_ntop (to, saddr, sizeof(saddr)); - g_debug ("mock_pgm_sendto (sock:%p use-rate-limit:%s use-router-alert:%s buf:%p len:%d to:%s tolen:%d)", - (gpointer)sock, - use_rate_limit ? "YES" : "NO", - use_router_alert ? "YES" : "NO", - buf, - len, - saddr, - tolen); - return len; -} - -/** time module */ -static pgm_time_t _mock_pgm_time_update_now (void); -pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; - -static -pgm_time_t -_mock_pgm_time_update_now (void) -{ - return 0x1; -} - -/** socket module */ -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return can_fragment ? ( sizeof(struct pgm_header) - + sizeof(struct pgm_data) - + sizeof(struct pgm_opt_length) - + sizeof(struct pgm_opt_header) - + sizeof(struct pgm_opt_fragment) ) - : ( sizeof(struct pgm_header) + sizeof(struct pgm_data) ); -} - - -/* mock functions for external references */ - - -/* target: - * PGMIOStatus - * pgm_send ( - * pgm_sock_t* sock, - * gconstpointer apdu, - * gsize apdu_length, - * gsize* bytes_written - * ) - */ - -START_TEST (test_send_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->is_bound = TRUE; - const gsize apdu_length = 100; - guint8 buffer[ apdu_length ]; - gsize bytes_written; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_send (sock, buffer, apdu_length, &bytes_written), "send not normal"); - fail_unless ((gssize)apdu_length == bytes_written, "send underrun"); -} -END_TEST - -/* large apdu */ -START_TEST (test_send_pass_002) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->is_bound = TRUE; - const gsize apdu_length = 16000; - guint8 buffer[ apdu_length ]; - gsize bytes_written; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_send (sock, buffer, apdu_length, &bytes_written), "send not normal"); - fail_unless ((gssize)apdu_length == bytes_written, "send underrun"); -} -END_TEST - -START_TEST (test_send_fail_001) -{ - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - const gsize apdu_length = 100; - gsize bytes_written; - fail_unless (PGM_IO_STATUS_ERROR == pgm_send (NULL, buffer, apdu_length, &bytes_written), "send not error"); -} -END_TEST - -/* target: - * PGMIOStatus - * pgm_sendv ( - * pgm_sock_t* sock, - * const struct pgmiovec* vector, - * guint count, - * gboolean is_one_apdu, - * gsize* bytes_written - * ) - */ - -START_TEST (test_sendv_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->is_bound = TRUE; - const gsize apdu_length = 100; - guint8 buffer[ apdu_length ]; - struct pgm_iovec vector[] = { { .iov_base = buffer, .iov_len = apdu_length } }; - gsize bytes_written; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_sendv (sock, vector, 1, TRUE, &bytes_written), "send not normal"); - fail_unless ((gssize)apdu_length == bytes_written, "send underrun"); -} -END_TEST - -/* large apdu */ -START_TEST (test_sendv_pass_002) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->is_bound = TRUE; - const gsize apdu_length = 16000; - guint8 buffer[ apdu_length ]; - struct pgm_iovec vector[] = { { .iov_base = buffer, .iov_len = apdu_length } }; - gsize bytes_written; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_sendv (sock, vector, 1, TRUE, &bytes_written), "send not normal"); - fail_unless ((gssize)apdu_length == bytes_written, "send underrun"); -} -END_TEST - -/* multipart apdu */ -START_TEST (test_sendv_pass_003) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->is_bound = TRUE; - const gsize apdu_length = 16000; - guint8 buffer[ apdu_length ]; - struct pgm_iovec vector[ 16 ]; - for (unsigned i = 0; i < G_N_ELEMENTS(vector); i++) { - vector[i].iov_base = &buffer[ (i * apdu_length) / G_N_ELEMENTS(vector) ]; - vector[i].iov_len = apdu_length / G_N_ELEMENTS(vector); - } - gsize bytes_written; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_sendv (sock, vector, G_N_ELEMENTS(vector), TRUE, &bytes_written), "send not normal"); - fail_unless ((gssize)apdu_length == bytes_written, "send underrun"); -} -END_TEST - -/* multiple apdus */ -START_TEST (test_sendv_pass_004) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->is_bound = TRUE; - const gsize apdu_length = 16000; - struct pgm_iovec vector[ 16 ]; - for (unsigned i = 0; i < G_N_ELEMENTS(vector); i++) { - vector[i].iov_base = g_malloc0 (apdu_length); - vector[i].iov_len = apdu_length; - } - gsize bytes_written; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_sendv (sock, vector, G_N_ELEMENTS(vector), FALSE, &bytes_written), "send not normal"); - fail_unless ((gssize)(apdu_length * G_N_ELEMENTS(vector)) == bytes_written, "send underrun"); -} -END_TEST - -START_TEST (test_sendv_fail_001) -{ - guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; - const gsize tsdu_length = 100; - struct pgm_iovec vector[] = { { .iov_base = buffer, .iov_len = tsdu_length } }; - gsize bytes_written; - fail_unless (PGM_IO_STATUS_ERROR == pgm_sendv (NULL, vector, 1, TRUE, &bytes_written), "send not error"); -} -END_TEST - -/* target: - * PGMIOStatus - * pgm_send_skbv ( - * pgm_sock_t* sock, - * struct pgm_sk_buff_t* vector[], - * guint count, - * gboolean is_one_apdu, - * gsize* bytes_written - * ) - */ - -START_TEST (test_send_skbv_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->is_bound = TRUE; - struct pgm_sk_buff_t* skb = NULL; - skb = generate_skb (); - fail_if (NULL == skb, "generate_skb failed"); - gsize apdu_length = (gsize)skb->len; - gsize bytes_written; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_send_skbv (sock, &skb, 1, TRUE, &bytes_written), "send not normal"); - fail_unless (apdu_length == bytes_written, "send underrun"); -} -END_TEST - -/* multipart apdu */ -START_TEST (test_send_skbv_pass_002) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->is_bound = TRUE; - struct pgm_sk_buff_t* skb[16]; - for (unsigned i = 0; i < G_N_ELEMENTS(skb); i++) { - skb[i] = generate_fragment_skb (); - fail_if (NULL == skb[i], "generate_fragment_skb failed"); - } - gsize apdu_length = (gsize)skb[0]->len * G_N_ELEMENTS(skb); - gsize bytes_written; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_send_skbv (sock, skb, G_N_ELEMENTS(skb), TRUE, &bytes_written), "send not normal"); - fail_unless (apdu_length == bytes_written, "send underrun"); -} -END_TEST - -/* multiple apdus */ -START_TEST (test_send_skbv_pass_003) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->is_bound = TRUE; - struct pgm_sk_buff_t* skb[16]; - for (unsigned i = 0; i < G_N_ELEMENTS(skb); i++) { - skb[i] = generate_skb (); - fail_if (NULL == skb[i], "generate_skb failed"); - } - gsize bytes_written; - fail_unless (PGM_IO_STATUS_NORMAL == pgm_send_skbv (sock, skb, G_N_ELEMENTS(skb), FALSE, &bytes_written), "send not normal"); - fail_unless ((gssize)(skb[0]->len * G_N_ELEMENTS(skb)) == bytes_written, "send underrun"); -} -END_TEST - -START_TEST (test_send_skbv_fail_001) -{ - struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU), *skbv[] = { skb }; - fail_if (NULL == skb, "alloc_skb failed"); -/* reserve PGM header */ - pgm_skb_put (skb, pgm_pkt_offset (TRUE, FALSE)); - const gsize tsdu_length = 100; - gsize bytes_written; - fail_unless (PGM_IO_STATUS_ERROR == pgm_send_skbv (NULL, skbv, 1, TRUE, &bytes_written), "send not error"); -} -END_TEST - -/* target: - * gboolean - * pgm_send_spm ( - * pgm_sock_t* sock, - * int flags - * ) - */ - -START_TEST (test_send_spm_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - fail_unless (TRUE == pgm_send_spm (sock, 0), "send_spm failed"); -} -END_TEST - -START_TEST (test_send_spm_fail_001) -{ - pgm_send_spm (NULL, 0); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_on_deferred_nak ( - * pgm_sock_t* sock - * ) - */ - -START_TEST (test_on_deferred_nak_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - pgm_on_deferred_nak (sock); -} -END_TEST - -START_TEST (test_on_deferred_nak_fail_001) -{ - pgm_on_deferred_nak (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * gboolean - * pgm_on_spmr ( - * pgm_sock_t* sock, - * pgm_peer_t* peer, - * struct pgm_sk_buff_t* skb - * ) - */ - -/* peer spmr */ -START_TEST (test_on_spmr_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - pgm_peer_t* peer = generate_peer (); - fail_if (NULL == peer, "generate_peer failed"); - struct pgm_sk_buff_t* skb = generate_spmr (); - fail_if (NULL == skb, "generate_spmr failed"); - skb->sock = sock; - fail_unless (TRUE == pgm_on_spmr (sock, peer, skb), "on_spmr failed"); -} -END_TEST - -/* source spmr */ -START_TEST (test_on_spmr_pass_002) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - struct pgm_sk_buff_t* skb = generate_spmr (); - fail_if (NULL == skb, "generate_spmr failed"); - skb->sock = sock; - fail_unless (TRUE == pgm_on_spmr (sock, NULL, skb), "on_spmr failed"); -} -END_TEST - -/* invalid spmr */ -START_TEST (test_on_spmr_fail_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - pgm_peer_t* peer = generate_peer (); - fail_if (NULL == peer, "generate_peer failed"); - struct pgm_sk_buff_t* skb = generate_spmr (); - fail_if (NULL == skb, "generate_spmr failed"); - skb->sock = sock; - mock_is_valid_spmr = FALSE; - fail_unless (FALSE == pgm_on_spmr (sock, peer, skb), "on_spmr failed"); -} -END_TEST - -START_TEST (test_on_spmr_fail_002) -{ - pgm_on_spmr (NULL, NULL, NULL); - fail ("reached"); -} -END_TEST - -/* target: - * gboolean - * pgm_on_nak ( - * pgm_sock_t* sock, - * struct pgm_sk_buff_t* skb - * ) - */ - -/* single nak */ -START_TEST (test_on_nak_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - struct pgm_sk_buff_t* skb = generate_single_nak (); - fail_if (NULL == skb, "generate_single_nak failed"); - skb->sock = sock; - fail_unless (TRUE == pgm_on_nak (sock, skb), "on_nak failed"); -} -END_TEST - -/* nak list */ -START_TEST (test_on_nak_pass_002) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - struct pgm_sk_buff_t* skb = generate_nak_list (); - fail_if (NULL == skb, "generate_nak_list failed"); - skb->sock = sock; - fail_unless (TRUE == pgm_on_nak (sock, skb), "on_nak failed"); -} -END_TEST - -/* single parity nak */ -START_TEST (test_on_nak_pass_003) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->use_ondemand_parity = TRUE; - struct pgm_sk_buff_t* skb = generate_parity_nak (); - fail_if (NULL == skb, "generate_parity_nak failed"); - skb->sock = sock; - fail_unless (TRUE == pgm_on_nak (sock, skb), "on_nak failed"); -} -END_TEST - -/* parity nak list */ -START_TEST (test_on_nak_pass_004) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->use_ondemand_parity = TRUE; - struct pgm_sk_buff_t* skb = generate_parity_nak_list (); - fail_if (NULL == skb, "generate_parity_nak_list failed"); - skb->sock = sock; - fail_unless (TRUE == pgm_on_nak (sock, skb), "on_nak failed"); -} -END_TEST - -START_TEST (test_on_nak_fail_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - struct pgm_sk_buff_t* skb = generate_single_nak (); - fail_if (NULL == skb, "generate_single_nak failed"); - skb->sock = sock; - mock_is_valid_nak = FALSE; - fail_unless (FALSE == pgm_on_nak (sock, skb), "on_nak failed"); -} -END_TEST - -START_TEST (test_on_nak_fail_002) -{ - pgm_on_nak (NULL, NULL); - fail ("reached"); -} -END_TEST - -/* target: - * gboolean - * pgm_on_nnak ( - * pgm_sock_t* sock, - * struct pgm_sk_buff_t* skb - * ) - */ - -START_TEST (test_on_nnak_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - struct pgm_sk_buff_t* skb = generate_single_nnak (); - fail_if (NULL == skb, "generate_single_nnak failed"); - skb->sock = sock; - fail_unless (TRUE == pgm_on_nnak (sock, skb), "on_nnak failed"); -} -END_TEST - -START_TEST (test_on_nnak_fail_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - struct pgm_sk_buff_t* skb = generate_single_nnak (); - fail_if (NULL == skb, "generate_single_nnak failed"); - skb->sock = sock; - mock_is_valid_nnak = FALSE; - fail_unless (FALSE == pgm_on_nnak (sock, skb), "on_nnak failed"); -} -END_TEST - -START_TEST (test_on_nnak_fail_002) -{ - pgm_on_nnak (NULL, NULL); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_AMBIENT_SPM, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_ambient_spm_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_AMBIENT_SPM; - const int ambient_spm = pgm_msecs(1000); - const void* optval = &ambient_spm; - const socklen_t optlen = sizeof(ambient_spm); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_ambient_spm failed"); -} -END_TEST - -START_TEST (test_set_ambient_spm_fail_001) -{ - const int optname = PGM_AMBIENT_SPM; - const int ambient_spm = pgm_msecs(1000); - const void* optval = &ambient_spm; - const socklen_t optlen = sizeof(ambient_spm); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_ambient_spm failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_HEARTBEAT_SPM, - * const void* optval, - * const socklen_t optlen = sizeof(int) * n - * ) - */ - -START_TEST (test_set_heartbeat_spm_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_HEARTBEAT_SPM; - const int intervals[] = { 1, 2, 3, 4, 5 }; - const void* optval = &intervals; - const socklen_t optlen = sizeof(intervals); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_heartbeat_spm failed"); -} -END_TEST - -START_TEST (test_set_heartbeat_spm_fail_001) -{ - const int optname = PGM_HEARTBEAT_SPM; - const int intervals[] = { 1, 2, 3, 4, 5 }; - const void* optval = &intervals; - const socklen_t optlen = sizeof(intervals); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_heartbeat_spm failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_TXW_SQNS, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_txw_sqns_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_TXW_SQNS; - const int txw_sqns = 100; - const void* optval = &txw_sqns; - const socklen_t optlen = sizeof(txw_sqns); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_txw_sqns failed"); -} -END_TEST - -START_TEST (test_set_txw_sqns_fail_001) -{ - const int optname = PGM_TXW_SQNS; - const int txw_sqns = 100; - const void* optval = &txw_sqns; - const socklen_t optlen = sizeof(txw_sqns); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_txw_sqns failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_TXW_SECS, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_txw_secs_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_TXW_SECS; - const int txw_secs = pgm_secs(10); - const void* optval = &txw_secs; - const socklen_t optlen = sizeof(txw_secs); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_txw_secs failed"); -} -END_TEST - -START_TEST (test_set_txw_secs_fail_001) -{ - const int optname = PGM_TXW_SECS; - const int txw_secs = pgm_secs(10); - const void* optval = &txw_secs; - const socklen_t optlen = sizeof(txw_secs); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_txw_secs failed"); -} -END_TEST - -/* target: - * bool - * pgm_setsockopt ( - * pgm_sock_t* const sock, - * const int optname = PGM_TXW_MAX_RTE, - * const void* optval, - * const socklen_t optlen = sizeof(int) - * ) - */ - -START_TEST (test_set_txw_max_rte_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - const int optname = PGM_TXW_MAX_RTE; - const int txw_max_rte = 100*1000; - const void* optval = &txw_max_rte; - const socklen_t optlen = sizeof(txw_max_rte); - fail_unless (TRUE == pgm_setsockopt (sock, optname, optval, optlen), "set_txw_max_rte failed"); -} -END_TEST - -START_TEST (test_set_txw_max_rte_fail_001) -{ - const int optname = PGM_TXW_MAX_RTE; - const int txw_max_rte = 100*1000; - const void* optval = &txw_max_rte; - const socklen_t optlen = sizeof(txw_max_rte); - fail_unless (FALSE == pgm_setsockopt (NULL, optname, optval, optlen), "set_txw_max_rte failed"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_send = tcase_create ("send"); - suite_add_tcase (s, tc_send); - tcase_add_checked_fixture (tc_send, mock_setup, NULL); - tcase_add_test (tc_send, test_send_pass_001); - tcase_add_test (tc_send, test_send_pass_002); - tcase_add_test (tc_send, test_send_fail_001); - - TCase* tc_sendv = tcase_create ("sendv"); - suite_add_tcase (s, tc_sendv); - tcase_add_checked_fixture (tc_sendv, mock_setup, NULL); - tcase_add_test (tc_sendv, test_sendv_pass_001); - tcase_add_test (tc_sendv, test_sendv_pass_002); - tcase_add_test (tc_sendv, test_sendv_pass_003); - tcase_add_test (tc_sendv, test_sendv_pass_004); - tcase_add_test (tc_sendv, test_sendv_fail_001); - - TCase* tc_send_skbv = tcase_create ("send-skbv"); - suite_add_tcase (s, tc_send_skbv); - tcase_add_checked_fixture (tc_send_skbv, mock_setup, NULL); - tcase_add_test (tc_send_skbv, test_send_skbv_pass_001); - tcase_add_test (tc_send_skbv, test_send_skbv_pass_002); - tcase_add_test (tc_send_skbv, test_send_skbv_fail_001); - - TCase* tc_send_spm = tcase_create ("send-spm"); - suite_add_tcase (s, tc_send_spm); - tcase_add_checked_fixture (tc_send_spm, mock_setup, NULL); - tcase_add_test (tc_send_spm, test_send_spm_pass_001); - tcase_add_test_raise_signal (tc_send_spm, test_send_spm_fail_001, SIGABRT); - - TCase* tc_on_deferred_nak = tcase_create ("on-deferred-nak"); - suite_add_tcase (s, tc_on_deferred_nak); - tcase_add_checked_fixture (tc_on_deferred_nak, mock_setup, NULL); - tcase_add_test (tc_on_deferred_nak, test_on_deferred_nak_pass_001); - tcase_add_test_raise_signal (tc_on_deferred_nak, test_on_deferred_nak_fail_001, SIGABRT); - - TCase* tc_on_spmr = tcase_create ("on-spmr"); - suite_add_tcase (s, tc_on_spmr); - tcase_add_checked_fixture (tc_on_spmr, mock_setup, NULL); - tcase_add_test (tc_on_spmr, test_on_spmr_pass_001); - tcase_add_test (tc_on_spmr, test_on_spmr_pass_002); - tcase_add_test (tc_on_spmr, test_on_spmr_fail_001); - tcase_add_test_raise_signal (tc_on_spmr, test_on_spmr_fail_002, SIGABRT); - - TCase* tc_on_nak = tcase_create ("on-nak"); - suite_add_tcase (s, tc_on_nak); - tcase_add_checked_fixture (tc_on_nak, mock_setup, NULL); - tcase_add_test (tc_on_nak, test_on_nak_pass_001); - tcase_add_test (tc_on_nak, test_on_nak_pass_002); - tcase_add_test (tc_on_nak, test_on_nak_pass_003); - tcase_add_test (tc_on_nak, test_on_nak_pass_004); - tcase_add_test (tc_on_nak, test_on_nak_fail_001); - tcase_add_test_raise_signal (tc_on_nak, test_on_nak_fail_002, SIGABRT); - - TCase* tc_on_nnak = tcase_create ("on-nnak"); - suite_add_tcase (s, tc_on_nnak); - tcase_add_checked_fixture (tc_on_nnak, mock_setup, NULL); - tcase_add_test (tc_on_nnak, test_on_nnak_pass_001); - tcase_add_test (tc_on_nnak, test_on_nnak_fail_001); - tcase_add_test_raise_signal (tc_on_nnak, test_on_nnak_fail_002, SIGABRT); - - TCase* tc_set_ambient_spm = tcase_create ("set-ambient-spm"); - suite_add_tcase (s, tc_set_ambient_spm); - tcase_add_checked_fixture (tc_set_ambient_spm, mock_setup, NULL); - tcase_add_test (tc_set_ambient_spm, test_set_ambient_spm_pass_001); - tcase_add_test (tc_set_ambient_spm, test_set_ambient_spm_fail_001); - - TCase* tc_set_heartbeat_spm = tcase_create ("set-heartbeat-spm"); - suite_add_tcase (s, tc_set_heartbeat_spm); - tcase_add_checked_fixture (tc_set_heartbeat_spm, mock_setup, NULL); - tcase_add_test (tc_set_heartbeat_spm, test_set_heartbeat_spm_pass_001); - tcase_add_test (tc_set_heartbeat_spm, test_set_heartbeat_spm_fail_001); - - TCase* tc_set_txw_sqns = tcase_create ("set-txw-sqns"); - suite_add_tcase (s, tc_set_txw_sqns); - tcase_add_checked_fixture (tc_set_txw_sqns, mock_setup, NULL); - tcase_add_test (tc_set_txw_sqns, test_set_txw_sqns_pass_001); - tcase_add_test (tc_set_txw_sqns, test_set_txw_sqns_fail_001); - - TCase* tc_set_txw_secs = tcase_create ("set-txw-secs"); - suite_add_tcase (s, tc_set_txw_secs); - tcase_add_checked_fixture (tc_set_txw_secs, mock_setup, NULL); - tcase_add_test (tc_set_txw_secs, test_set_txw_secs_pass_001); - tcase_add_test (tc_set_txw_secs, test_set_txw_secs_fail_001); - - TCase* tc_set_txw_max_rte = tcase_create ("set-txw-max-rte"); - suite_add_tcase (s, tc_set_txw_max_rte); - tcase_add_checked_fixture (tc_set_txw_max_rte, mock_setup, NULL); - tcase_add_test (tc_set_txw_max_rte, test_set_txw_max_rte_pass_001); - tcase_add_test (tc_set_txw_max_rte, test_set_txw_max_rte_fail_001); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/string.c b/3rdparty/openpgm-svn-r1085/pgm/string.c deleted file mode 100644 index 93458fd..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/string.c +++ /dev/null @@ -1,486 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * portable string manipulation functions. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef CONFIG_HAVE_VASPRINTF -# define _GNU_SOURCE -#endif -#include -#include -#include /* _GNU_SOURCE for vasprintf */ -#include -#include - - -//#define STRING_DEBUG - -/* Return copy of string, must be freed with pgm_free(). - */ - -char* -pgm_strdup ( - const char* str - ) -{ - char* new_str; - size_t length; - - if (PGM_LIKELY (NULL != str)) - { - length = strlen (str) + 1; - new_str = malloc (length); - memcpy (new_str, str, length); - } - else - new_str = NULL; - - return new_str; -} - -/* Calculates the maximum space needed to store the output of the sprintf() function. - */ - -int -pgm_printf_string_upper_bound ( - const char* format, - va_list args - ) -{ - char c; - return vsnprintf (&c, 1, format, args) + 1; -} - -/* memory must be freed with free() - */ - -int -pgm_vasprintf ( - char** restrict string, - const char* restrict format, - va_list args - ) -{ - pgm_return_val_if_fail (string != NULL, -1); -#ifdef CONFIG_HAVE_VASPRINTF - const int len = vasprintf (string, format, args); - if (len < 0) - *string = NULL; -#else - va_list args2; - va_copy (args2, args); - *string = malloc (pgm_printf_string_upper_bound (format, args)); -/* NB: must be able to handle NULL args, fails on GCC */ - const int len = vsprintf (*string, format, args); - va_end (args2); -#endif - return len; -} - -char* -pgm_strdup_vprintf ( - const char* format, - va_list args - ) -{ - char *string = NULL; - pgm_vasprintf (&string, format, args); - return string; -} - -static -char* -pgm_stpcpy ( - char* restrict dest, - const char* restrict src - ) -{ - pgm_return_val_if_fail (dest != NULL, NULL); - pgm_return_val_if_fail (src != NULL, NULL); -#ifdef CONFIG_HAVE_STPCPY - return stpcpy (dest, src); -#else - char *d = dest; - const char *s = src; - do { - *d++ = *s; - } while (*s++ != '\0'); - return d - 1; -#endif -} - -char* -pgm_strconcat ( - const char* string1, - ... - ) -{ - size_t l; - va_list args; - char* s; - char* concat; - char* ptr; - - if (!string1) - return NULL; - - l = 1 + strlen (string1); - va_start (args, string1); - s = va_arg (args, char*); - while (s) { - l += strlen (s); - s = va_arg (args, char*); - } - va_end (args); - - concat = malloc (l); - ptr = concat; - - ptr = pgm_stpcpy (ptr, string1); - va_start (args, string1); - s = va_arg (args, char*); - while (s) { - ptr = pgm_stpcpy (ptr, s); - s = va_arg (args, char*); - } - va_end (args); - - return concat; -} - -/* Split a string with delimiter, result must be freed with pgm_strfreev(). - */ - -char** -pgm_strsplit ( - const char* restrict string, - const char* restrict delimiter, - int max_tokens - ) -{ - pgm_slist_t *string_list = NULL, *slist; - char **str_array, *s; - unsigned n = 0; - const char *remainder; - - pgm_return_val_if_fail (string != NULL, NULL); - pgm_return_val_if_fail (delimiter != NULL, NULL); - pgm_return_val_if_fail (delimiter[0] != '\0', NULL); - - if (max_tokens < 1) - max_tokens = INT_MAX; - - remainder = string; - s = strstr (remainder, delimiter); - if (s) - { - const size_t delimiter_len = strlen (delimiter); - - while (--max_tokens && s) - { - const size_t len = s - remainder; - char *new_string = malloc (len + 1); - strncpy (new_string, remainder, len); - new_string[len] = 0; - string_list = pgm_slist_prepend (string_list, new_string); - n++; - remainder = s + delimiter_len; - s = strstr (remainder, delimiter); - } - } - if (*string) - { - n++; - string_list = pgm_slist_prepend (string_list, pgm_strdup (remainder)); - } - - str_array = pgm_new (char*, n + 1); - str_array[n--] = NULL; - for (slist = string_list; slist; slist = slist->next) - str_array[n--] = slist->data; - - pgm_slist_free (string_list); - - return str_array; -} - -/* Free a NULL-terminated array of strings, such as created by pgm_strsplit - */ - -void -pgm_strfreev ( - char** str_array - ) -{ - if (PGM_LIKELY (NULL != str_array)) - { - for (unsigned i = 0; str_array[i] != NULL; i++) - free (str_array[i]); - - pgm_free (str_array); - } -} - -/* resize dynamic string - */ - -static -void -pgm_string_maybe_expand ( - pgm_string_t* string, - size_t len - ) -{ - if ((string->len + len) >= string->allocated_len) - { - string->allocated_len = pgm_nearest_power (1, string->len + len + 1); - string->str = pgm_realloc (string->str, string->allocated_len); - } -} - -/* val may not be a part of string - */ - -static -pgm_string_t* -pgm_string_insert_len ( - pgm_string_t* restrict string, - ssize_t pos, - const char* restrict val, - ssize_t len - ) -{ - pgm_return_val_if_fail (NULL != string, NULL); - pgm_return_val_if_fail (NULL != val, string); - - if (len < 0) - len = strlen (val); - - if (pos < 0) - pos = string->len; - else - pgm_return_val_if_fail ((size_t)pos <= string->len, string); - - pgm_string_maybe_expand (string, len); - - if ((size_t)pos < string->len) - memmove (string->str + pos + len, string->str + pos, string->len - pos); - - if (len == 1) - string->str[pos] = *val; - else - memcpy (string->str + pos, val, len); - string->len += len; - string->str[string->len] = 0; - return string; -} - -static -pgm_string_t* -pgm_string_insert_c ( - pgm_string_t* string, - ssize_t pos, - char c - ) -{ - pgm_return_val_if_fail (NULL != string, NULL); - - if (pos < 0) - pos = string->len; - else - pgm_return_val_if_fail ((size_t)pos <= string->len, string); - - pgm_string_maybe_expand (string, 1); - - if ((size_t)pos < string->len) - memmove (string->str + pos + 1, string->str + pos, string->len - pos); - - string->str[pos] = c; - string->len ++; - string->str[string->len] = '\0'; - return string; -} - -static -pgm_string_t* -pgm_string_append_len ( - pgm_string_t* restrict string, - const char* restrict val, - size_t len - ) -{ - pgm_return_val_if_fail (NULL != string, NULL); - pgm_return_val_if_fail (NULL != val, string); - - return pgm_string_insert_len (string, -1, val, len); -} - -/* create new dynamic string - */ - -static -pgm_string_t* -pgm_string_sized_new ( - size_t init_size - ) -{ - pgm_string_t* string = pgm_new (pgm_string_t, 1); - string->allocated_len = 0; - string->len = 0; - string->str = NULL; - pgm_string_maybe_expand (string, MAX(init_size, 2)); - string->str[0] = '\0'; - return string; -} - -pgm_string_t* -pgm_string_new ( - const char* init - ) -{ - pgm_string_t* string; - - if (NULL == init || '\0' == *init) - string = pgm_string_sized_new (2); - else - { - const size_t len = strlen (init); - string = pgm_string_sized_new (len + 2); - pgm_string_append_len (string, init, len); - } - return string; -} - -/* free dynamic string, optionally just the wrapper object - */ - -char* -pgm_string_free ( - pgm_string_t* string, - bool free_segment - ) -{ - char* segment; - - pgm_return_val_if_fail (NULL != string, NULL); - - if (free_segment) { - pgm_free (string->str); - segment = NULL; - } else - segment = string->str; - - pgm_free (string); - return segment; -} - -static -pgm_string_t* -pgm_string_truncate ( - pgm_string_t* restrict string, - size_t len - ) -{ - pgm_return_val_if_fail (NULL != string, NULL); - - string->len = MIN (len, string->len); - string->str[ string->len ] = '\0'; - - return string; -} - -pgm_string_t* -pgm_string_append ( - pgm_string_t* restrict string, - const char* restrict val - ) -{ - pgm_return_val_if_fail (NULL != string, NULL); - pgm_return_val_if_fail (NULL != val, string); - - return pgm_string_insert_len (string, -1, val, -1); -} - -pgm_string_t* -pgm_string_append_c ( - pgm_string_t* string, - char c - ) -{ - pgm_return_val_if_fail (NULL != string, NULL); - - return pgm_string_insert_c (string, -1, c); -} - -static void pgm_string_append_vprintf (pgm_string_t*restrict, const char*restrict, va_list) PGM_GNUC_PRINTF(2, 0); - -static -void -pgm_string_append_vprintf ( - pgm_string_t* restrict string, - const char* restrict format, - va_list args - ) -{ - char *buf; - int len; - - pgm_return_if_fail (NULL != string); - pgm_return_if_fail (NULL != format); - - len = pgm_vasprintf (&buf, format, args); - if (len >= 0) { - pgm_string_maybe_expand (string, len); - memcpy (string->str + string->len, buf, len + 1); - string->len += len; - free (buf); - } -} - -void -pgm_string_printf ( - pgm_string_t* restrict string, - const char* restrict format, - ... - ) -{ - va_list args; - - pgm_string_truncate (string, 0); - - va_start (args, format); - pgm_string_append_vprintf (string, format, args); - va_end (args); -} - -void -pgm_string_append_printf ( - pgm_string_t* restrict string, - const char* restrict format, - ... - ) -{ - va_list args; - - va_start (args, format); - pgm_string_append_vprintf (string, format, args); - va_end (args); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/PGM/Test.pm b/3rdparty/openpgm-svn-r1085/pgm/test/PGM/Test.pm deleted file mode 100644 index cb2ee6d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/PGM/Test.pm +++ /dev/null @@ -1,394 +0,0 @@ -package PGM::Test; - -use strict; -our($VERSION); -use Carp; -use IO::File; -use IPC::Open2; -use Net::SSH qw(sshopen2); -use Sys::Hostname; -use POSIX ":sys_wait_h"; -use JSON; - -$VERSION = '1.00'; - -=head1 NAME - -PGM::Test - PGM test module - -=head1 SYNOPSIS - - $test = PGM::Test->new(); - -=cut - -my $json = new JSON; - -sub new { - my $class = shift; - my $self = {}; - my %params = @_; - - $self->{tag} = exists $params{tag} ? $params{tag} : confess "tag parameter is required"; - $self->{host} = exists $params{host} ? $params{host} : confess "host parameter is required"; - $self->{cmd} = exists $params{cmd} ? $params{cmd} : confess "cmd parameter is required"; - - $self->{in} = IO::File->new(); - $self->{out} = IO::File->new(); - $self->{pid} = undef; - - bless $self, $class; - return $self; -} - -sub connect { - my $self = shift; - my $host = hostname; - - if ($self->{host} =~ /^(localhost|127\.1|127\.0\.0\.1|$host)$/) - { - print "$self->{tag}: opening local connection\n"; - $self->{pid} = open2 ($self->{in}, - $self->{out}, - "uname -a && sudo $self->{cmd}") - or croak "open2 failed $!"; - } - else - { - print "$self->{tag}: opening SSH connection to $self->{host} ...\n"; - $self->{pid} = sshopen2 ($self->{host}, - $self->{in}, - $self->{out}, - "uname -a && sudo $self->{cmd}") - or croak "SSH failed: $!"; - } - - print "$self->{tag}: connected.\n"; - $self->wait_for_ready; -} - -sub disconnect { - my($self,$quiet) = @_; - my $out = $self->{out}; - - print "$self->{tag}: sending quit command ...\n"; - eval { - local($SIG{ALRM}) = sub { die "alarm\n"; }; - alarm 10; - print $out "quit\n"; - while (readline($self->{in})) { - chomp; - print "$self->{tag} [$_]\n" if (!$quiet); - } - alarm 0; - }; - if ($@) { - print "$self->{tag}: alarm raised on quit command.\n"; - } else { - print "$self->{tag}: eof.\n"; - } - - print "$self->{tag}: closing SSH connection ...\n"; - close ($self->{in}); - close ($self->{out}); - print "$self->{tag}: closed.\n"; -} - -sub DESTROY { - my $self = shift; - - if ($self->{pid}) { - print "$self->{tag}: waiting child to terminate ...\n"; - eval { - local($SIG{ALRM}) = sub { die "alarm\n"; }; - alarm 10; - waitpid $self->{pid}, 0; - alarm 0; - }; - if ($@) { - die unless $@ eq "alarm\n"; - local($SIG{CHLD}) = 'IGNORE'; - print "$self->{tag}: killing child ...\n"; - kill 'INT' => $self->{pid}; - print "$self->{tag}: killed.\n"; - } else { - print "$self->{tag}: terminated.\n"; - } - } -} - -sub wait_for_ready { - my $self = shift; - - while (readline($self->{in})) { - chomp; - print "$self->{tag} [$_]\n"; - last if /^READY/; - } -} - -sub wait_for_block { - my $self = shift; - my $fh = $self->{in}; - my $b = ''; - my $state = 0; - - while (<$fh>) { - chomp(); - my $l = $_; - if ($state == 0) { - if ($l =~ /^{$/) { - $state = 1; - } else { - print "$self->{tag} [$l]\n"; - } - } - - if ($state == 1) { - $b .= $l; - - if ($l =~ /^}$/) { - $state = 0; - return $b; - } - } - } -} - -sub wait_for_spm { - my $self = shift; - my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; - my $obj = undef; - - eval { - local $SIG{ALRM} = sub { die "alarm\n"; }; - alarm $timeout; - for (;;) { - my $block = $self->wait_for_block; - $obj = $json->jsonToObj($block); - last if ($obj->{PGM}->{type} =~ /SPM$/); - } - alarm 0; - }; - if ($@) { - die unless $@ eq "alarm\n"; - confess "$self->{tag}: alarm raised waiting for spm.\n"; - } - - return $obj; -} - -sub wait_for_spmr { - my $self = shift; - my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; - my $obj = undef; - - eval { - local $SIG{ALRM} = sub { die "alarm\n"; }; - alarm $timeout; - for (;;) { - my $block = $self->wait_for_block; - $obj = $json->jsonToObj($block); - last if ($obj->{PGM}->{type} =~ /SPMR/); - } - alarm 0; - }; - if ($@) { - die unless $@ eq "alarm\n"; - confess "$self->{tag}: alarm raised waiting for spmr.\n"; - } - - return $obj; -} - -sub die_on_spmr { - my $self = shift; - my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; - my $obj = undef; - - eval { - local $SIG{ALRM} = sub { die "alarm\n"; }; - alarm $timeout; - for (;;) { - my $block = $self->wait_for_block; - $obj = $json->jsonToObj($block); - last if ($obj->{PGM}->{type} =~ /SPMR/); - } - alarm 0; - }; - if ($@) { - die unless $@ eq "alarm\n"; - return $obj; - } - - confess "$self->{tag}: spmr received during blackout.\n"; -} - -# data to {app} -sub wait_for_data { - my $self = shift; - my $fh = $self->{in}; - my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; - my $data = undef; - - eval { - local $SIG{ALRM} = sub { die "alarm\n"; }; - alarm $timeout; - while (<$fh>) { - chomp; - if (/^DATA: (.+)$/) { - $data = $1; - last; - } - print "$self->{tag} [$_]\n"; - } - alarm 0; - }; - if ($@) { - die unless $@ eq "alarm\n"; - confess "$self->{tag}: alarm raised waiting for data.\n"; - } - - return $data; -} - -sub wait_for_odata { - my $self = shift; - my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; - my $obj = undef; - - eval { - local $SIG{ALRM} = sub { die "alarm\n"; }; - alarm $timeout; - for (;;) { - my $block = $self->wait_for_block; - $obj = $json->jsonToObj($block); - last if ($obj->{PGM}->{type} =~ /ODATA/); - } - alarm 0; - }; - if ($@) { - die unless $@ eq "alarm\n"; - confess "$self->{tag}: alarm raised waiting for odata.\n"; - } - - return $obj; -} - -sub wait_for_rdata { - my $self = shift; - my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; - my $obj = undef; - - eval { - local $SIG{ALRM} = sub { die "alarm\n"; }; - alarm $timeout; - for (;;) { - my $block = $self->wait_for_block; - $obj = $json->jsonToObj($block); - last if ($obj->{PGM}->{type} =~ /RDATA/); - } - alarm 0; - }; - if ($@) { - die unless $@ eq "alarm\n"; - confess "$self->{tag}: alarm raised waiting for rdata.\n"; - } - - return $obj; -} - -sub die_on_nak { - my $self = shift; - my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; - my $obj = undef; - - eval { - local $SIG{ALRM} = sub { die "alarm\n"; }; - alarm $timeout; - for (;;) { - my $block = $self->wait_for_block; - $obj = $json->jsonToObj($block); - last if ($obj->{PGM}->{type} =~ /NAK/); - } - alarm 0; - }; - if ($@) { - die unless $@ eq "alarm\n"; - return $obj; - } - - confess "$self->{tag}: nak received during blackout.\n"; -} - -sub wait_for_nak { - my $self = shift; - my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; - my $obj = undef; - - eval { - local $SIG{ALRM} = sub { die "alarm\n"; }; - alarm $timeout; - for (;;) { - my $block = $self->wait_for_block; - $obj = $json->jsonToObj($block); - last if ($obj->{PGM}->{type} =~ /NAK/); - } - alarm 0; - }; - if ($@) { - die unless $@ eq "alarm\n"; - confess "$self->{tag}: alarm raised waiting for nak.\n"; - } - - return $obj; -} - -sub wait_for_ncf { - my $self = shift; - my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; - my $obj = undef; - - eval { - local $SIG{ALRM} = sub { die "alarm\n"; }; - alarm $timeout; - for (;;) { - my $block = $self->wait_for_block; - $obj = $json->jsonToObj($block); - last if ($obj->{PGM}->{type} =~ /NCF/); - } - alarm 0; - }; - if ($@) { - die unless $@ eq "alarm\n"; - confess "$self->{tag}: alarm raised waiting for ncf.\n"; - } - - return $obj; -} - -sub print { - my $self = shift; - my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; - my $out = $self->{out}; - - print "$self->{tag}> @_"; - eval { - local($SIG{ALRM}) = sub { die "alarm\n"; }; - alarm $timeout; - print $out "@_"; - $self->wait_for_ready; - alarm 0; - }; - if ($@) { - die unless $@ eq "alarm\n"; - confess "$self->{tag}: alarm raised.\n"; - } -} - -sub say { - my $self = shift; - $self->print ("@_\n"); -} - -1; diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/SConscript b/3rdparty/openpgm-svn-r1085/pgm/test/SConscript deleted file mode 100644 index 7ca9926..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/SConscript +++ /dev/null @@ -1,15 +0,0 @@ -# -*- mode: python -*- -# OpenPGM build script -# $Id$ - -Import('env') -e = env.Clone(); -e.MergeFlags(env['GLIB_FLAGS']); -e.Append(LIBS = ['libpgm', 'libpgmex']); -e.Append(CCFLAGS = '-DGETTEXT_PACKAGE=\'"pgm"\''); - -e.Program(['monitor.c', 'dump-json.c']) -e.Program(['app.c', 'async.c']) -e.Program(['sim.c', 'dump-json.c', 'async.c']) - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/ambient_spm.pl b/3rdparty/openpgm-svn-r1085/pgm/test/ambient_spm.pl deleted file mode 100755 index dca52a5..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/ambient_spm.pl +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/perl -# ambient_spm.pl -# 5.1.4. Ambient SPMs - -use strict; -use PGM::Test; -use IO::Handle; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -pipe(FROM_PARENT, TO_CHILD) or die "pipe: $!"; -FROM_PARENT->autoflush(1); - -$mon->connect; -$app->connect; - -sub close_ssh { - close FROM_PARENT; close TO_CHILD; - $mon = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -if (my $pid = fork) { -# parent - close FROM_PARENT; - - print "mon: wait for odata ...\n"; - $mon->wait_for_odata; - print "mon: odata received.\n"; - print "mon: wait for spm ...\n"; - $mon->wait_for_spm ({ 'timeout' => 45 }); - print "mon: received spm.\n"; - - print TO_CHILD "die\n"; - - close TO_CHILD; - waitpid($pid,0); -} else { -# child - die "cannot fork: $!" unless defined $pid; - close TO_CHILD; - print "app: loop sending data.\n"; - vec(my $rin, fileno(FROM_PARENT), 1) = 1; - my $rout = undef; - -# hide stdout - open(OLDOUT, ">&STDOUT"); - open(STDOUT, ">/dev/null") or die "Can't redirect stdout: $!"; - -# send every ~50ms - while (! select($rout = $rin, undef, undef, 0.05)) - { - $app->say ("send ao ringo"); - } - -# restore stdout - close(STDOUT) or die "Can't close STDOUT: $!"; - open(STDOUT, ">&OLDOUT") or die "Can't restore stdout: $!"; - close(OLDOUT) or die "Can't close OLDOUT: $!"; - - print "app: loop finished.\n"; - close FROM_PARENT; - exit; -} - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/apdu.pl b/3rdparty/openpgm-svn-r1085/pgm/test/apdu.pl deleted file mode 100755 index f4669c0..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/apdu.pl +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/perl -# apdu.pl -# 6.1. Data Reception - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("set network $config{app}{network}"); -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -$sim->say ("set network $config{sim}{network}"); -$sim->say ("create ao"); -$sim->say ("bind ao"); - -print "sim: publish APDU.\n"; -$sim->say ("send ao ringo x 1000"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: received data [$data].\n"; - -my $ref_data = "ringo" x 1000; -die "incoming data corrupt\n" unless ($data == $ref_data); - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/apdu_parity.pl b/3rdparty/openpgm-svn-r1085/pgm/test/apdu_parity.pl deleted file mode 100755 index eb4cf27..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/apdu_parity.pl +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/perl -# apdu_parity.pl -# 6.1. Data Reception - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$sim->connect; -$app->connect; - -sub close_ssh { - $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$app->say ("create ao"); -##$app->say ("set ao FEC RS(255,4)"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -$sim->say ("create ao"); -$sim->say ("set ao FEC RS(255,4)"); -$sim->say ("bind ao"); - -print "sim: publish APDU.\n"; -$sim->say ("send brokn ao ringo x 1200"); - -print "sim: insert parity NAK from app.\n"; - -#print "sim: wait for NAK.\n"; -#my $nak = $sim->wait_for_nak; -#die "Selective NAK received, parityPacket=false\n" unless $nak->{PGM}->{options}->{parityPacket}; -#print "Parity NAK received.\n"; - -print "sim: insert parity RDATA from sim.\n"; - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: received data [$data].\n"; - -my $ref_data = "ringo" x 1200; -die "incoming data corrupt\n" unless ($data == $ref_data); - -print "test completed successfully.\n"; - -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/app.c b/3rdparty/openpgm-svn-r1085/pgm/test/app.c deleted file mode 100644 index 1d8f585..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/app.c +++ /dev/null @@ -1,904 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM conformance test application. - * - * Copyright (c) 2006-2007 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include "async.h" - - -/* typedefs */ - -struct idle_source { - GSource source; - guint64 expiration; -}; - -struct app_session { - char* name; - pgm_transport_t* transport; - pgm_async_t* async; -}; - -/* globals */ -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "app" - -static int g_port = 7500; -static const char* g_network = ";239.192.0.1"; - -static guint g_max_tpdu = 1500; -static guint g_sqns = 100 * 1000; - -static GHashTable* g_sessions = NULL; -static GMainLoop* g_loop = NULL; -static GIOChannel* g_stdin_channel = NULL; - - -static void on_signal (int, gpointer); -static gboolean on_startup (gpointer); -static gboolean on_mark (gpointer); -static void destroy_session (gpointer, gpointer, gpointer); -static int on_data (gpointer, guint, gpointer); -static gboolean on_stdin_data (GIOChannel*, GIOCondition, gpointer); - - -G_GNUC_NORETURN static -void -usage (const char* bin) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - exit (1); -} - -int -main ( - int argc, - char *argv[] - ) -{ - pgm_error_t* err = NULL; - -/* pre-initialise PGM messages module to add hook for GLib logging */ - pgm_messages_init(); - log_init (); - g_message ("app"); - - if (!pgm_init (&err)) { - g_error ("Unable to start PGM engine: %s", (err && err->message) ? err->message : "(null)"); - pgm_error_free (err); - pgm_messages_shutdown(); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:h")) != -1) - { - switch (c) { - case 'n': g_network = optarg; break; - case 's': g_port = atoi (optarg); break; - - case 'h': - case '?': - pgm_messages_shutdown(); - usage (binary_name); - } - } - - g_loop = g_main_loop_new (NULL, FALSE); - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); - signal (SIGHUP, SIG_IGN); - pgm_signal_install (SIGINT, on_signal, g_loop); - pgm_signal_install (SIGTERM, on_signal, g_loop); - -/* delayed startup */ - g_message ("scheduling startup."); - g_timeout_add (0, (GSourceFunc)on_startup, NULL); - -/* dispatch loop */ - g_message ("entering main event loop ... "); - g_main_loop_run (g_loop); - - g_message ("event loop terminated, cleaning up."); - -/* cleanup */ - g_main_loop_unref(g_loop); - g_loop = NULL; - - if (g_sessions) { - g_message ("destroying sessions."); - g_hash_table_foreach_remove (g_sessions, (GHRFunc)destroy_session, NULL); - g_hash_table_unref (g_sessions); - g_sessions = NULL; - } - - if (g_stdin_channel) { - puts ("unbinding stdin."); - g_io_channel_unref (g_stdin_channel); - g_stdin_channel = NULL; - } - - g_message ("PGM engine shutdown."); - pgm_shutdown(); - g_message ("finished."); - pgm_messages_shutdown(); - return EXIT_SUCCESS; -} - -static -void -destroy_session ( - gpointer key, /* session name */ - gpointer value, /* transport_session object */ - G_GNUC_UNUSED gpointer user_data - ) -{ - struct app_session* sess = (struct app_session*)value; - - g_message ("destroying transport \"%s\"", (char*)key); - pgm_transport_destroy (sess->transport, TRUE); - sess->transport = NULL; - - if (sess->async) { - g_message ("destroying asynchronous session on \"%s\"", (char*)key); - pgm_async_destroy (sess->async); - sess->async = NULL; - } - - g_free (sess->name); - sess->name = NULL; - g_free (sess); -} - -static -void -on_signal ( - int signum, - gpointer user_data - ) -{ - GMainLoop* loop = (GMainLoop*)user_data; - g_message ("on_signal (signum:%d user-data:%p)", signum, user_data); - g_main_loop_quit (loop); -} - -static -gboolean -on_startup ( - G_GNUC_UNUSED gpointer data - ) -{ - g_message ("startup."); - - g_sessions = g_hash_table_new (g_str_hash, g_str_equal); - -/* add stdin to event manager */ - g_stdin_channel = g_io_channel_unix_new (fileno(stdin)); - printf ("binding stdin with encoding %s.\n", g_io_channel_get_encoding(g_stdin_channel)); - - g_io_add_watch (g_stdin_channel, G_IO_IN | G_IO_PRI, on_stdin_data, NULL); - -/* period timer to indicate some form of life */ -// TODO: Gnome 2.14: replace with g_timeout_add_seconds() - g_timeout_add(10 * 1000, (GSourceFunc)on_mark, NULL); - - puts ("READY"); - fflush (stdout); - return FALSE; -} - -static -int -on_data ( - gpointer data, - G_GNUC_UNUSED guint len, - G_GNUC_UNUSED gpointer user_data - ) -{ - printf ("DATA: %s\n", (char*)data); - fflush (stdout); - return 0; -} - -static -void -session_create ( - char* name - ) -{ - struct pgm_transport_info_t hints = { - .ti_family = AF_INET - }, *res = NULL; - pgm_error_t* err = NULL; - -/* check for duplicate */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess != NULL) { - puts ("FAILED: duplicate session"); - return; - } - -/* create new and fill in bits */ - sess = g_new0(struct app_session, 1); - sess->name = g_memdup (name, strlen(name)+1); - - if (!pgm_if_get_transport_info (g_network, &hints, &res, &err)) { - printf ("FAILED: pgm_if_get_transport_info(): %s\n", (err && err->message) ? err->message : "(null)"); - pgm_error_free (err); - goto err_free; - } - - if (!pgm_gsi_create_from_hostname (&res->ti_gsi, &err)) { - printf ("FAILED: pgm_gsi_create_from_hostname(): %s\n", (err && err->message) ? err->message : "(null)"); - pgm_error_free (err); - pgm_if_free_transport_info (res); - goto err_free; - } - - res->ti_dport = g_port; - res->ti_sport = 0; -printf ("pgm_transport_create (transport:%p res:%p err:%p)\n", (gpointer)sess->transport, (gpointer)res, (gpointer)&err); - if (!pgm_transport_create (&sess->transport, res, &err)) { - printf ("FAILED: pgm_transport_create(): %s\n", (err && err->message) ? err->message : "(null)"); - pgm_error_free (err); - pgm_if_free_transport_info (res); - goto err_free; - } - - pgm_if_free_transport_info (res); - -/* success */ - g_hash_table_insert (g_sessions, sess->name, sess); - printf ("created new session \"%s\"\n", sess->name); - puts ("READY"); - - return; - -err_free: - g_free(sess->name); - g_free(sess); -} - -static -void -session_set_nak_bo_ivl ( - char* name, - guint nak_bo_ivl /* milliseconds */ - ) -{ -/* check that session exists */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - if (!pgm_transport_set_nak_bo_ivl (sess->transport, pgm_msecs(nak_bo_ivl))) - puts ("FAILED: pgm_transport_set_nak_bo_ivl"); - else - puts ("READY"); -} - -static -void -session_set_nak_rpt_ivl ( - char* name, - guint nak_rpt_ivl /* milliseconds */ - ) -{ -/* check that session exists */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - if (!pgm_transport_set_nak_rpt_ivl (sess->transport, pgm_msecs(nak_rpt_ivl))) - puts ("FAILED: pgm_transport_set_nak_rpt_ivl"); - else - puts ("READY"); -} - -static -void -session_set_nak_rdata_ivl ( - char* name, - guint nak_rdata_ivl /* milliseconds */ - ) -{ -/* check that session exists */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - if (!pgm_transport_set_nak_rdata_ivl (sess->transport, pgm_msecs(nak_rdata_ivl))) - puts ("FAILED: pgm_transport_set_nak_rdata_ivl"); - else - puts ("READY"); -} - -static -void -session_set_nak_ncf_retries ( - char* name, - guint nak_ncf_retries - ) -{ -/* check that session exists */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - if (!pgm_transport_set_nak_ncf_retries (sess->transport, nak_ncf_retries)) - puts ("FAILED pgm_transport_set_nak_ncf_retries"); - else - puts ("READY"); -} - -static -void -session_set_nak_data_retries ( - char* name, - guint nak_data_retries - ) -{ -/* check that session exists */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - if (!pgm_transport_set_nak_data_retries (sess->transport, nak_data_retries)) - puts ("FAILED: pgm_transport_set_nak_data_retries"); - else - puts ("READY"); -} - -static -void -session_set_txw_max_rte ( - char* name, - guint txw_max_rte - ) -{ -/* check that session exists */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - if (!pgm_transport_set_txw_max_rte (sess->transport, txw_max_rte)) - puts ("FAILED:pgm_transport_set_txw_max_rte"); - else - puts ("READY"); -} - -static -void -session_set_fec ( - char* name, - guint default_n, - guint default_k - ) -{ -/* check that session exists */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - if (!pgm_transport_set_fec (sess->transport, - FALSE /* pro-active */, - TRUE /* on-demand */, - TRUE /* varpkt-len */, - default_n, - default_k)) - { - puts ("FAILED: pgm_transport_set_fec"); - } - else - { - puts ("READY"); - } -} - -static -void -session_bind ( - char* name - ) -{ - const guint spm_heartbeat[] = { pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(1300), pgm_secs(7), pgm_secs(16), pgm_secs(25), pgm_secs(30) }; - pgm_error_t* err = NULL; - -/* check that session exists */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - if (!pgm_transport_set_nonblocking (sess->transport, TRUE)) - puts ("FAILED: pgm_transport_set_nonblocking"); - if (!pgm_transport_set_max_tpdu (sess->transport, g_max_tpdu)) - puts ("FAILED: pgm_transport_set_max_tpdu"); - if (!pgm_transport_set_txw_sqns (sess->transport, g_sqns)) - puts ("FAILED: pgm_transport_set_txw_sqns"); - if (!pgm_transport_set_rxw_sqns (sess->transport, g_sqns)) - puts ("FAILED: pgm_transport_set_rxw_sqns"); - if (!pgm_transport_set_hops (sess->transport, 16)) - puts ("FAILED: pgm_transport_set_hops"); - if (!pgm_transport_set_ambient_spm (sess->transport, pgm_secs(30))) - puts ("FAILED: pgm_transport_set_ambient_spm"); - if (!pgm_transport_set_heartbeat_spm (sess->transport, spm_heartbeat, G_N_ELEMENTS(spm_heartbeat))) - puts ("FAILED: pgm_transport_set_heartbeat_spm"); - if (!pgm_transport_set_peer_expiry (sess->transport, pgm_secs(300))) - puts ("FAILED: pgm_transport_set_peer_expiry"); - if (!pgm_transport_set_spmr_expiry (sess->transport, pgm_msecs(250))) - puts ("FAILED: pgm_transport_set_spmr_expiry"); - if (!sess->transport->nak_bo_ivl && !pgm_transport_set_nak_bo_ivl (sess->transport, pgm_msecs(50))) - puts ("FAILED: pgm_transport_set_nak_bo_ivl"); - if (!sess->transport->nak_rpt_ivl && !pgm_transport_set_nak_rpt_ivl (sess->transport, pgm_secs(2))) - puts ("FAILED: pgm_transport_set_nak_rpt_ivl"); - if (!sess->transport->nak_rdata_ivl && !pgm_transport_set_nak_rdata_ivl (sess->transport, pgm_secs(2))) - puts ("FAILED: pgm_transport_set_nak_rdata_ivl"); - if (!sess->transport->nak_data_retries && !pgm_transport_set_nak_data_retries (sess->transport, 50)) - puts ("FAILED: pgm_transport_set_nak_data_retries"); - if (!sess->transport->nak_ncf_retries && !pgm_transport_set_nak_ncf_retries (sess->transport, 50)) - puts ("FAILED: pgm_transport_set_nak_ncf_retries"); - -printf ("pgm_transport_bind (transport:%p err:%p)\n", (gpointer)sess->transport, (gpointer)&err); - if (!pgm_transport_bind (sess->transport, &err)) { - printf ("FAILED: pgm_transport_bind(): %s\n", (err && err->message) ? err->message : "(null)"); - pgm_error_free (err); - } else - puts ("READY"); -} - -static -void -session_send ( - char* name, - char* string - ) -{ -/* check that session exists */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - -/* send message */ - int status; - gsize stringlen = strlen(string) + 1; - int n_fds = 1; - struct pollfd fds[ n_fds ]; - struct timeval tv; - int timeout; -again: -printf ("pgm_send (transport:%p string:\"%s\" stringlen:%" G_GSIZE_FORMAT " NULL)\n", (gpointer)sess->transport, string, stringlen); - status = pgm_send (sess->transport, string, stringlen, NULL); - switch (status) { - case PGM_IO_STATUS_NORMAL: - puts ("READY"); - break; - case PGM_IO_STATUS_TIMER_PENDING: - pgm_transport_get_timer_pending (sess->transport, &tv); - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - pgm_transport_get_rate_remaining (sess->transport, &tv); -/* fall through */ - case PGM_IO_STATUS_WOULD_BLOCK: -block: - timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - memset (fds, 0, sizeof(fds)); - pgm_transport_poll_info (sess->transport, fds, &n_fds, POLLOUT); - poll (fds, n_fds, timeout /* ms */); - goto again; - default: - puts ("FAILED: pgm_send()"); - break; - } -} - -static -void -session_listen ( - char* name - ) -{ - GError* err = NULL; - -/* check that session exists */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - -/* listen */ -printf ("pgm_async_create (async:%p transport:%p err:%p)\n", (gpointer)&sess->async, (gpointer)sess->transport, (gpointer)&err); - if (!pgm_async_create (&sess->async, sess->transport, &err)) { - printf ("FAILED: pgm_async_create(): %s", err->message); - g_error_free (err); - return; - } - pgm_async_add_watch (sess->async, on_data, sess); - puts ("READY"); -} - -static -void -session_destroy ( - char* name - ) -{ -/* check that session exists */ - struct app_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - -/* remove from hash table */ - g_hash_table_remove (g_sessions, name); - -/* stop any async thread */ - if (sess->async) { - pgm_async_destroy (sess->async); - sess->async = NULL; - } - - pgm_transport_destroy (sess->transport, TRUE); - sess->transport = NULL; - g_free (sess->name); - sess->name = NULL; - g_free (sess); - - puts ("READY"); -} - -/* process input commands from stdin/fd - */ - -static -gboolean -on_stdin_data ( - GIOChannel* source, - G_GNUC_UNUSED GIOCondition condition, - G_GNUC_UNUSED gpointer data - ) -{ - gchar* str = NULL; - gsize len = 0; - gsize term = 0; - GError* err = NULL; - - g_io_channel_read_line (source, &str, &len, &term, &err); - if (len > 0) { - if (term) str[term] = 0; - -/* quit */ - if (strcmp(str, "quit") == 0) - { - g_main_loop_quit(g_loop); - goto out; - } - - regex_t preg; - regmatch_t pmatch[10]; - -/* create transport */ - const char *re = "^create[[:space:]]+([[:alnum:]]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - session_create (name); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* set NAK_BO_IVL */ - re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+NAK_BO_IVL[[:space:]]+([0-9]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - char *p = str + pmatch[2].rm_so; - guint nak_bo_ivl = strtol (p, &p, 10); - - session_set_nak_bo_ivl (name, nak_bo_ivl); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* set NAK_RPT_IVL */ - re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+NAK_RPT_IVL[[:space:]]+([0-9]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - char *p = str + pmatch[2].rm_so; - guint nak_rpt_ivl = strtol (p, &p, 10); - - session_set_nak_rpt_ivl (name, nak_rpt_ivl); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* set NAK_RDATA_IVL */ - re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+NAK_RDATA_IVL[[:space:]]+([0-9]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - char *p = str + pmatch[2].rm_so; - guint nak_rdata_ivl = strtol (p, &p, 10); - - session_set_nak_rdata_ivl (name, nak_rdata_ivl); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* set NAK_NCF_RETRIES */ - re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+NAK_NCF_RETRIES[[:space:]]+([0-9]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - char *p = str + pmatch[2].rm_so; - guint nak_ncf_retries = strtol (p, &p, 10); - - session_set_nak_ncf_retries (name, nak_ncf_retries); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* set NAK_DATA_RETRIES */ - re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+NAK_DATA_RETRIES[[:space:]]+([0-9]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - char *p = str + pmatch[2].rm_so; - guint nak_data_retries = strtol (p, &p, 10); - - session_set_nak_data_retries (name, nak_data_retries); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* set TXW_MAX_RTE */ - re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+TXW_MAX_RTE[[:space:]]+([0-9]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - char *p = str + pmatch[2].rm_so; - guint txw_max_rte = strtol (p, &p, 10); - - session_set_txw_max_rte (name, txw_max_rte); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* enable Reed-Solomon Forward Error Correction */ - re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+FEC[[:space:]]+RS[[:space:]]*\\([[:space:]]*([0-9]+)[[:space:]]*,[[:space:]]*([0-9]+)[[:space:]]*\\)$"; - regcomp (&preg, re, REG_EXTENDED); - - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - char *p = str + pmatch[2].rm_so; - *(str + pmatch[2].rm_eo) = 0; - guint n = strtol (p, &p, 10); - p = str + pmatch[3].rm_so; - *(str + pmatch[3].rm_eo) = 0; - guint k = strtol (p, &p, 10); - session_set_fec (name, n, k); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* bind transport */ - re = "^bind[[:space:]]+([[:alnum:]]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - session_bind (name); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* send packet */ - re = "^send[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - char *string = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); - string[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; - - session_send (name, string); - - g_free (name); - g_free (string); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* listen */ - re = "^listen[[:space:]]+([[:alnum:]]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - session_listen (name); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* destroy transport */ - re = "^destroy[[:space:]]+([[:alnum:]]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - session_destroy (name); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* set PGM network */ - re = "^set[[:space:]]+network[[:space:]]+([[:print:]]*;[[:print:]]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char* pgm_network = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - pgm_network[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - g_network = pgm_network; - puts ("READY"); - - regfree (&preg); - goto out; - } - regfree (&preg); - - printf ("unknown command: %s\n", str); - } - -out: - fflush (stdout); - g_free (str); - return TRUE; -} - -/* idle log notification - */ - -static -gboolean -on_mark ( - G_GNUC_UNUSED gpointer data - ) -{ - g_message ("-- MARK --"); - return TRUE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/async.c b/3rdparty/openpgm-svn-r1085/pgm/test/async.c deleted file mode 100644 index cc2c1ba..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/async.c +++ /dev/null @@ -1,572 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Asynchronous queue for receiving packets in a separate managed thread. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include "async.h" - - -//#define ASYNC_DEBUG - -#ifndef ASYNC_DEBUG -# define g_trace(...) while (0) -#else -#include -# define g_trace(...) g_debug(__VA_ARGS__) -#endif - - -/* globals */ - - -/* global locals */ - -typedef struct pgm_event_t pgm_event_t; - -struct pgm_event_t { - gpointer data; - guint len; -}; - - -/* external: Glib event loop GSource of pgm contiguous data */ -struct pgm_watch_t { - GSource source; - GPollFD pollfd; - pgm_async_t* async; -}; - -typedef struct pgm_watch_t pgm_watch_t; - - -static gboolean pgm_src_prepare (GSource*, gint*); -static gboolean pgm_src_check (GSource*); -static gboolean pgm_src_dispatch (GSource*, GSourceFunc, gpointer); - -static GSourceFuncs g_pgm_watch_funcs = { - .prepare = pgm_src_prepare, - .check = pgm_src_check, - .dispatch = pgm_src_dispatch, - .finalize = NULL, - .closure_callback = NULL -}; - - -static inline gpointer pgm_event_alloc (pgm_async_t* const) G_GNUC_MALLOC; -static PGMAsyncError pgm_async_error_from_errno (const gint); - - -static inline -gpointer -pgm_event_alloc ( - pgm_async_t* const async - ) -{ - g_return_val_if_fail (async != NULL, NULL); - return g_slice_alloc (sizeof(pgm_event_t)); -} - -/* release event memory for custom async queue dispatch handlers - */ - -static inline -void -pgm_event_unref ( - pgm_async_t* const async, - pgm_event_t* const event - ) -{ - g_return_if_fail (async != NULL); - g_return_if_fail (event != NULL); - g_slice_free1 (sizeof(pgm_event_t), event); -} - -/* internal receiver thread, sits in a loop processing incoming packets - */ - -static -gpointer -pgm_receiver_thread ( - gpointer data - ) -{ - g_assert (NULL != data); - - pgm_async_t* async = (pgm_async_t*)data; - g_async_queue_ref (async->commit_queue); - -/* incoming message buffer */ - struct pgm_msgv_t msgv; - gsize bytes_read = 0; - struct timeval tv; - - do { -/* blocking read */ - const int status = pgm_recvmsg (async->transport, &msgv, 0, &bytes_read, NULL); - switch (status) { - case PGM_IO_STATUS_NORMAL: - { -/* queue a copy to receiver */ - pgm_event_t* event = pgm_event_alloc (async); - event->data = bytes_read > 0 ? g_malloc (bytes_read) : NULL; - event->len = bytes_read; - gpointer dst = event->data; - guint i = 0; - while (bytes_read) { - const struct pgm_sk_buff_t* skb = msgv.msgv_skb[i++]; - g_assert (NULL != skb); - g_assert (skb->len > 0); - g_assert (skb->len <= bytes_read); - memcpy (dst, skb->data, skb->len); - dst = (char*)dst + skb->len; - bytes_read -= skb->len; - } -/* prod pipe on edge */ - g_async_queue_lock (async->commit_queue); - g_async_queue_push_unlocked (async->commit_queue, event); - if (g_async_queue_length_unlocked (async->commit_queue) == 1) - pgm_notify_send (&async->commit_notify); - g_async_queue_unlock (async->commit_queue); - break; - } - - case PGM_IO_STATUS_TIMER_PENDING: - { - pgm_transport_get_timer_pending (async->transport, &tv); - goto block; - } - - case PGM_IO_STATUS_RATE_LIMITED: - { - pgm_transport_get_rate_remaining (async->transport, &tv); - } -/* fall through */ - case PGM_IO_STATUS_WOULD_BLOCK: -block: - { -#ifdef CONFIG_HAVE_POLL - const int timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - int n_fds = 3; - struct pollfd fds[1+n_fds]; - memset (fds, 0, sizeof(fds)); - fds[0].fd = pgm_notify_get_fd (&async->destroy_notify); - fds[0].events = POLLIN; - if (-1 == pgm_transport_poll_info (async->transport, &fds[1], &n_fds, POLLIN)) { - g_trace ("poll_info returned errno=%i",errno); - goto cleanup; - } - const int ready = poll (fds, 1 + n_fds, timeout); -#else /* HAVE_SELECT */ - fd_set readfds; - int fd = pgm_notify_get_fd (&async->destroy_notify), n_fds = 1 + fd; - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - if (-1 == pgm_transport_select_info (async->transport, &readfds, NULL, &n_fds)) { - g_trace ("select_info returned errno=%i",errno); - goto cleanup; - } - const int ready = select (n_fds, &readfds, NULL, NULL, PGM_IO_STATUS_RATE_LIMITED == status ? &tv : NULL); -#endif - if (-1 == ready) { - g_trace ("block returned errno=%i",errno); - goto cleanup; - } -#ifdef CONFIG_HAVE_POLL - if (ready > 0 && fds[0].revents) -#else - if (ready > 0 && FD_ISSET(fd, &readfds)) -#endif - goto cleanup; - break; - } - - case PGM_IO_STATUS_ERROR: - case PGM_IO_STATUS_EOF: - goto cleanup; - - case PGM_IO_STATUS_RESET: - if (async->transport->is_abort_on_reset) - goto cleanup; - break; - -/* TODO: report to user */ - case PGM_IO_STATUS_FIN: - break; - - default: - g_assert_not_reached(); - } - } while (!async->is_destroyed); - -cleanup: - g_async_queue_unref (async->commit_queue); - return NULL; -} - -/* create asynchronous thread handler - * - * on success, 0 is returned. on error, -1 is returned, and errno set appropriately. - * on invalid parameters, -EINVAL is returned. - */ - -gboolean -pgm_async_create ( - pgm_async_t** async, - pgm_transport_t* const transport, - GError** error - ) -{ - pgm_async_t* new_async; - - g_return_val_if_fail (NULL != async, FALSE); - g_return_val_if_fail (NULL != transport, FALSE); - - g_trace ("create (async:%p transport:%p error:%p)", - (gpointer)async, (gpointer)transport, (gpointer)error); - - if (!g_thread_supported()) - g_thread_init (NULL); - - new_async = g_new0 (pgm_async_t, 1); - new_async->transport = transport; - if (0 != pgm_notify_init (&new_async->commit_notify) || - 0 != pgm_notify_init (&new_async->destroy_notify)) - { - g_set_error (error, - PGM_ASYNC_ERROR, - pgm_async_error_from_errno (errno), - _("Creating async notification channels: %s"), - g_strerror (errno)); - g_free (new_async); - return FALSE; - } - new_async->commit_queue = g_async_queue_new(); -/* setup new thread */ - new_async->thread = g_thread_create_full (pgm_receiver_thread, - new_async, - 0, - TRUE, - TRUE, - G_THREAD_PRIORITY_HIGH, - error); - if (NULL == new_async->thread) { - g_async_queue_unref (new_async->commit_queue); - pgm_notify_destroy (&new_async->commit_notify); - g_free (new_async); - return FALSE; - } - -/* return new object */ - *async = new_async; - return TRUE; -} - -/* tell async thread to stop, wait for it to stop, then cleanup. - * - * on success, 0 is returned. if async is invalid, -EINVAL is returned. - */ - -gboolean -pgm_async_destroy ( - pgm_async_t* const async - ) -{ - g_return_val_if_fail (NULL != async, FALSE); - g_return_val_if_fail (!async->is_destroyed, FALSE); - - async->is_destroyed = TRUE; - pgm_notify_send (&async->destroy_notify); - if (async->thread) - g_thread_join (async->thread); - if (async->commit_queue) { - g_async_queue_unref (async->commit_queue); - async->commit_queue = NULL; - } - pgm_notify_destroy (&async->destroy_notify); - pgm_notify_destroy (&async->commit_notify); - g_free (async); - return TRUE; -} - -/* queue to GSource and GMainLoop */ - -GSource* -pgm_async_create_watch ( - pgm_async_t* async - ) -{ - g_return_val_if_fail (async != NULL, NULL); - - GSource *source = g_source_new (&g_pgm_watch_funcs, sizeof(pgm_watch_t)); - pgm_watch_t *watch = (pgm_watch_t*)source; - - watch->async = async; - watch->pollfd.fd = pgm_async_get_fd (async); - watch->pollfd.events = G_IO_IN; - - g_source_add_poll (source, &watch->pollfd); - - return source; -} - -/* pgm transport attaches to the callees context: the default context instead of - * any internal contexts. - */ - -int -pgm_async_add_watch_full ( - pgm_async_t* async, - gint priority, - pgm_eventfn_t function, - gpointer user_data, - GDestroyNotify notify - ) -{ - g_return_val_if_fail (async != NULL, -EINVAL); - g_return_val_if_fail (function != NULL, -EINVAL); - - GSource* source = pgm_async_create_watch (async); - - if (priority != G_PRIORITY_DEFAULT) - g_source_set_priority (source, priority); - - g_source_set_callback (source, (GSourceFunc)function, user_data, notify); - - guint id = g_source_attach (source, NULL); - g_source_unref (source); - - return id; -} - -int -pgm_async_add_watch ( - pgm_async_t* async, - pgm_eventfn_t function, - gpointer user_data - ) -{ - return pgm_async_add_watch_full (async, G_PRIORITY_HIGH, function, user_data, NULL); -} - -/* returns TRUE if source has data ready, i.e. async queue is not empty - * - * called before event loop poll() - */ - -static -gboolean -pgm_src_prepare ( - GSource* source, - gint* timeout - ) -{ - pgm_watch_t* watch = (pgm_watch_t*)source; - -/* infinite timeout */ - *timeout = -1; - - return ( g_async_queue_length(watch->async->commit_queue) > 0 ); -} - -/* called after event loop poll() - * - * return TRUE if ready to dispatch. - */ - -static -gboolean -pgm_src_check ( - GSource* source - ) -{ - pgm_watch_t* watch = (pgm_watch_t*)source; - - return ( g_async_queue_length(watch->async->commit_queue) > 0 ); -} - -/* called when TRUE returned from prepare or check - */ - -static gboolean -pgm_src_dispatch ( - GSource* source, - GSourceFunc callback, - gpointer user_data - ) -{ - g_trace ("pgm_src_dispatch (source:%p callback:() user-data:%p)", - (gpointer)source, user_data); - - const pgm_eventfn_t function = (pgm_eventfn_t)callback; - pgm_watch_t* watch = (pgm_watch_t*)source; - pgm_async_t* async = watch->async; - -/* empty pipe */ - pgm_notify_read (&async->commit_notify); - -/* purge only one message from the asynchronous queue */ - pgm_event_t* event = g_async_queue_try_pop (async->commit_queue); - if (event) - { -/* important that callback occurs out of lock to allow PGM layer to add more messages */ - (*function) (event->data, event->len, user_data); - -/* return memory to receive window */ - if (event->len) g_free (event->data); - pgm_event_unref (async, event); - } - - return TRUE; -} - -/* synchronous reading from the queue. - * - * returns GIOStatus with success, error, again, or eof. - */ - -GIOStatus -pgm_async_recv ( - pgm_async_t* const async, - gpointer data, - const gsize len, - gsize* const bytes_read, - const int flags, /* MSG_DONTWAIT for non-blocking */ - GError** error - ) -{ - g_return_val_if_fail (NULL != async, G_IO_STATUS_ERROR); - if (len) g_return_val_if_fail (NULL != data, G_IO_STATUS_ERROR); - - g_trace ("pgm_async_recv (async:%p data:%p len:%" G_GSIZE_FORMAT" bytes-read:%p flags:%d error:%p)", - (gpointer)async, data, len, (gpointer)bytes_read, flags, (gpointer)error); - - pgm_event_t* event = NULL; - g_async_queue_lock (async->commit_queue); - if (g_async_queue_length_unlocked (async->commit_queue) == 0) - { - g_async_queue_unlock (async->commit_queue); - if (flags & MSG_DONTWAIT || async->is_nonblocking) - return G_IO_STATUS_AGAIN; -#ifdef CONFIG_HAVE_POLL - struct pollfd fds[1]; - int ready; - do { - memset (fds, 0, sizeof(fds)); - fds[0].fd = pgm_notify_get_fd (&async->commit_notify); - fds[0].events = POLLIN; - ready = poll (fds, G_N_ELEMENTS(fds), -1); - if (-1 == ready || async->is_destroyed) /* errno = EINTR */ - return G_IO_STATUS_ERROR; - } while (ready <= 0); -#else - fd_set readfds; - int n_fds, ready, fd = pgm_notify_get_fd (&async->commit_notify); - do { - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - n_fds = fd + 1; - ready = select (n_fds, &readfds, NULL, NULL, NULL); - if (-1 == ready || async->is_destroyed) /* errno = EINTR */ - return G_IO_STATUS_ERROR; - } while (ready <= 0); -#endif - pgm_notify_read (&async->commit_notify); - g_async_queue_lock (async->commit_queue); - } - event = g_async_queue_pop_unlocked (async->commit_queue); - g_async_queue_unlock (async->commit_queue); - -/* pass data back to callee */ - if (event->len > len) { - *bytes_read = len; - memcpy (data, event->data, *bytes_read); - g_set_error (error, - PGM_ASYNC_ERROR, - PGM_ASYNC_ERROR_OVERFLOW, - _("Message too large to be stored in buffer.")); - pgm_event_unref (async, event); - return G_IO_STATUS_ERROR; - } - - if (bytes_read) - *bytes_read = event->len; - memcpy (data, event->data, event->len); - -/* cleanup */ - if (event->len) g_free (event->data); - pgm_event_unref (async, event); - return G_IO_STATUS_NORMAL; -} - -gboolean -pgm_async_set_nonblocking ( - pgm_async_t* const async, - const gboolean nonblocking - ) -{ - g_return_val_if_fail (NULL != async, FALSE); - async->is_nonblocking = nonblocking; - return TRUE; -} - -GQuark -pgm_async_error_quark (void) -{ - return g_quark_from_static_string ("pgm-async-error-quark"); -} - -static -PGMAsyncError -pgm_async_error_from_errno ( - const gint err_no - ) -{ - switch (err_no) { -#ifdef EFAULT - case EFAULT: - return PGM_ASYNC_ERROR_FAULT; - break; -#endif - -#ifdef EMFILE - case EMFILE: - return PGM_ASYNC_ERROR_MFILE; - break; -#endif - -#ifdef ENFILE - case ENFILE: - return PGM_ASYNC_ERROR_NFILE; - break; -#endif - - default : - return PGM_ASYNC_ERROR_FAILED; - break; - } -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/async.h b/3rdparty/openpgm-svn-r1085/pgm/test/async.h deleted file mode 100644 index c2b91a7..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/async.h +++ /dev/null @@ -1,76 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * Asynchronous receive thread helper - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_ASYNC_H__ -#define __PGM_ASYNC_H__ - -#include -#include -#include - - -#define PGM_ASYNC_ERROR pgm_async_error_quark () - -typedef enum -{ - /* Derived from errno */ - PGM_ASYNC_ERROR_FAULT, - PGM_ASYNC_ERROR_MFILE, - PGM_ASYNC_ERROR_NFILE, - PGM_ASYNC_ERROR_OVERFLOW, - PGM_ASYNC_ERROR_FAILED -} PGMAsyncError; - -typedef struct pgm_async_t pgm_async_t; - -struct pgm_async_t { - pgm_transport_t* transport; - GThread* thread; - GAsyncQueue* commit_queue; - pgm_notify_t commit_notify; - pgm_notify_t destroy_notify; - gboolean is_destroyed; - gboolean is_nonblocking; -}; - -typedef int (*pgm_eventfn_t)(gpointer, guint, gpointer); - - -G_BEGIN_DECLS - -int pgm_async_create (pgm_async_t**, pgm_transport_t* const, GError**); -int pgm_async_destroy (pgm_async_t* const); -GIOStatus pgm_async_recv (pgm_async_t* const, gpointer, const gsize, gsize* const, const int, GError**); -gboolean pgm_async_set_nonblocking (pgm_async_t* const, const gboolean); -GSource* pgm_async_create_watch (pgm_async_t* const) G_GNUC_WARN_UNUSED_RESULT; -int pgm_async_add_watch_full (pgm_async_t*, gint, pgm_eventfn_t, gpointer, GDestroyNotify); -int pgm_async_add_watch (pgm_async_t*, pgm_eventfn_t, gpointer); -GQuark pgm_async_error_quark (void); - -static inline int pgm_async_get_fd (pgm_async_t* async) -{ - g_return_val_if_fail (async != NULL, -EINVAL); - return pgm_notify_get_fd (&async->commit_notify); -} - -G_END_DECLS - -#endif /* __PGM_ASYNC_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/dump-json.c b/3rdparty/openpgm-svn-r1085/pgm/test/dump-json.c deleted file mode 100644 index 70a7442..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/dump-json.c +++ /dev/null @@ -1,1292 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * JSON packet dump. - * - * Copyright (c) 2006-2008 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "dump-json.h" - - -/* globals */ - -#define OPTIONS_TOTAL_LEN(x) *(guint16*)( ((char*)(x)) + sizeof(guint16) ) - - -int verify_ip_header (struct pgm_ip*, guint); -void print_ip_header (struct pgm_ip*); -int verify_pgm_header (struct pgm_header*, guint); -void print_pgm_header (struct pgm_header*); -int verify_spm (struct pgm_header*, char*, guint); -void print_spm (struct pgm_header*, char*); -int verify_poll (struct pgm_header*, char*, guint); -void print_poll (struct pgm_header*, char*); -int verify_polr (struct pgm_header*, char*, guint); -void print_polr (struct pgm_header*, char*); -int verify_odata (struct pgm_header*, char*, guint); -void print_odata (struct pgm_header*, char*); -int verify_rdata (struct pgm_header*, char*, guint); -void print_rdata (struct pgm_header*, char*); -static int generic_verify_nak (const char*, struct pgm_header*, char*, guint); -static void generic_print_nak (const char*, struct pgm_header*, char*); -int verify_nak (struct pgm_header*, char*, guint); -void print_nak (struct pgm_header*, char*); -int verify_nnak (struct pgm_header*, char*, guint); -void print_nnak (struct pgm_header*, char*); -int verify_ncf (struct pgm_header*, char*, guint); -void print_ncf (struct pgm_header*, char*); -int verify_spmr (struct pgm_header*, char*, guint); -void print_spmr (struct pgm_header*, char*); -int verify_options (char*, guint); -void print_options (char*); - - -int -monitor_packet ( - char* data, - guint len - ) -{ - static int count = 0; - - puts ("{"); - printf ("\t\"id\": %i,\n", ++count); - - int retval = 0; - - struct pgm_ip* ip = (struct pgm_ip*)data; - if (verify_ip_header (ip, len) < 0) { - puts ("\t\"valid\": false"); - retval = -1; - goto out; - } - - struct pgm_header* pgm = (struct pgm_header*)(data + (ip->ip_hl * 4)); - guint pgm_len = len - (ip->ip_hl * 4); - if (verify_pgm_header (pgm, pgm_len) < 0) { - puts ("\t\"valid\": false"); - retval = -1; - goto out; - } - - char* pgm_data = (char*)(pgm + 1); - guint pgm_data_len = pgm_len - sizeof(struct pgm_header); - switch (pgm->pgm_type) { - case PGM_SPM: retval = verify_spm (pgm, pgm_data, pgm_data_len); break; - case PGM_POLL: retval = verify_poll (pgm, pgm_data, pgm_data_len); break; - case PGM_POLR: retval = verify_polr (pgm, pgm_data, pgm_data_len); break; - case PGM_ODATA: retval = verify_odata (pgm, pgm_data, pgm_data_len); break; - case PGM_RDATA: retval = verify_rdata (pgm, pgm_data, pgm_data_len); break; - case PGM_NAK: retval = verify_nak (pgm, pgm_data, pgm_data_len); break; - case PGM_NNAK: retval = verify_nnak (pgm, pgm_data, pgm_data_len); break; - case PGM_NCF: retval = verify_ncf (pgm, pgm_data, pgm_data_len); break; - case PGM_SPMR: retval = verify_spmr (pgm, pgm_data, pgm_data_len); break; - } - - if (retval < 0) { - puts ("\t\"valid\": false"); - goto out; - } - -/* packet verified correct */ - puts ("\t\"valid\": true,"); - - print_ip_header (ip); - print_pgm_header (pgm); - - switch (pgm->pgm_type) { - case PGM_SPM: print_spm (pgm, pgm_data); break; - case PGM_POLL: print_poll (pgm, pgm_data); break; - case PGM_POLR: print_polr (pgm, pgm_data); break; - case PGM_ODATA: print_odata (pgm, pgm_data); break; - case PGM_RDATA: print_rdata (pgm, pgm_data); break; - case PGM_NAK: print_nak (pgm, pgm_data); break; - case PGM_NNAK: print_nnak (pgm, pgm_data); break; - case PGM_NCF: print_ncf (pgm, pgm_data); break; - case PGM_SPMR: print_spmr (pgm, pgm_data); break; - } - -out: - puts ("}"); - return retval; -} - - -int -verify_ip_header ( - struct pgm_ip* ip, - guint len - ) -{ -/* minimum size should be IP header plus PGM header */ - if (len < (sizeof(struct pgm_ip) + sizeof(struct pgm_header))) - { - printf ("\t\"message\": \"IP: packet size too small: %i bytes, expecting at least %" G_GSIZE_FORMAT " bytes.\",\n", len, sizeof(struct pgm_header)); - return -1; - } - -/* IP packet header: IPv4 - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |Version| HL | ToS | Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Fragment ID |R|D|M| Fragment Offset | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | TTL | Protocol | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source IP Address | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Destination IP Address | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | IP Options when present ... - * +-+-+-+-+-+-+-+-+-+-+-+-+ ... - * | Data ... - * +-+-+- ... - * - * IPv6: n/a - */ - -/* decode IP header */ - if (ip->ip_v != 4 && ip->ip_v != 6) { /* IP version, 4 or 6 */ - printf ("\t\"message\": \"IP: unknown IP version %i.\",\n", ip->ip_v); - return -1; - } - - guint ip_header_length = ip->ip_hl * 4; /* IP header length in 32bit octets */ - if (ip_header_length < sizeof(struct ip)) { - printf ("\t\"message\": \"IP: bad IP header length %i, should be at least %" G_GSIZE_FORMAT "lu bytes.\",\n", ip_header_length, sizeof(struct ip)); - return -1; - } - -/* ip_len can equal packet_length - ip_header_length in FreeBSD/NetBSD - * Stevens/Fenner/Rudolph, Unix Network Programming Vol.1, p.739 - * - * RFC3828 allows partial packets such that len < packet_length with UDP lite - */ - guint packet_length = g_ntohs(ip->ip_len); /* total packet length */ - if (len < packet_length) { /* redundant: often handled in kernel */ - printf ("\t\"message\": \"IP: truncated IP packet: header reports %i actual length %i bytes.\",\n", (int)len, (int)packet_length); - return -1; - } - -/* TCP Segmentation Offload (TSO) might have zero length here */ - if (packet_length < ip_header_length) { - printf ("\t\"message\": \"IP: header reports %i less than IP header length %i.\",\n", (int)packet_length, (int)ip_header_length); - return -1; - } - -/* packets that fail checksum will generally not be passed upstream except with rfc3828 - */ - int sum = pgm_inet_checksum((char*)ip, ip_header_length, 0); - if (sum != 0) { - int ip_sum = g_ntohs(ip->ip_sum); - printf ("\t\"message\": \"IP: IP header checksum incorrect: 0x%x.\",\n", ip_sum); - return -2; - } - - if (ip->ip_p != IPPROTO_PGM) { - printf ("\t\"message\": \"IP: packet IP protocol not PGM: %i.\",\n", ip->ip_p); - return -1; - } - -/* fragmentation offset, bit 0: 0, bit 1: do-not-fragment, bit 2: more-fragments */ - int offset = g_ntohs(ip->ip_off); - if ((offset & 0x1fff) != 0) { - printf ("\t\"message\": \"IP: fragmented IP packet, ignoring.\",\n"); - return -1; - } - - return 0; -} - -void -print_ip_header ( - struct pgm_ip* ip - ) -{ - puts ("\t\"IP\": {"); - printf ("\t\t\"version\": %i,\n", - ip->ip_v - ); - printf ("\t\t\"headerLength\": %i,\n", - ip->ip_hl - ); - printf ("\t\t\"ToS\": %i,\n", - ip->ip_tos & 0x3 - ); - printf ("\t\t\"length\": %i,\n", - g_ntohs(ip->ip_len) - ); - printf ("\t\t\"fragmentId\": %i,\n", - g_ntohs(ip->ip_id) - ); - printf ("\t\t\"DF\": %s,\n", - (g_ntohs(ip->ip_off) & 0x4000) ? "true" : "false" - ); - printf ("\t\t\"MF\": %s,\n", - (g_ntohs(ip->ip_off) & 0x2000) ? "true" : "false" - ); - printf ("\t\t\"fragmentOffset\": %i,\n", - g_ntohs(ip->ip_off) & 0x1fff - ); - printf ("\t\t\"TTL\": %i,\n", - ip->ip_ttl - ); - printf ("\t\t\"protocol\": %i,\n", - ip->ip_p - ); - printf ("\t\t\"sourceIp\": \"%s\",\n", - inet_ntoa(*(struct in_addr*)&ip->ip_src) - ); - printf ("\t\t\"destinationIp\": \"%s\",\n", - inet_ntoa(*(struct in_addr*)&ip->ip_dst) - ); - puts ("\t\t\"IpOptions\": {"); - puts ("\t\t}"); - puts ("\t},"); -} - -int -verify_pgm_header ( - struct pgm_header* pgm, - guint pgm_len - ) -{ - -/* PGM payload, header looks as follows: - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source Port | Destination Port | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Options | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Global Source ID ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ... Global Source ID | TSDU Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type specific data ... - * +-+-+-+-+-+-+-+-+-+- ... - */ - if (pgm_len < sizeof(pgm)) { - printf ("\t\"message\": \"PGM: packet size less than PGM header: %i bytes.\",\n", pgm_len); - return -1; - } - - if (pgm->pgm_checksum) - { - int sum = pgm->pgm_checksum; - pgm->pgm_checksum = 0; - int pgm_sum = pgm_csum_fold (pgm_csum_partial ((const char*)pgm, pgm_len, 0)); - pgm->pgm_checksum = sum; - if (pgm_sum != sum) { - printf ("\t\"message\": \"PGM: PGM packet checksum incorrect, packet 0x%x calculated 0x%x.\",\n", sum, pgm_sum); - return -2; - } - } else { - if (pgm->pgm_type != PGM_ODATA && pgm->pgm_type != PGM_RDATA) { - printf ("\t\"message\": \"PGM: No PGM checksum value, mandatory for ODATA/RDATA.\",\n"); - return -1; - } - } - - if ( pgm->pgm_type != PGM_SPM && - pgm->pgm_type != PGM_POLL && - pgm->pgm_type != PGM_POLR && - pgm->pgm_type != PGM_ODATA && - pgm->pgm_type != PGM_RDATA && - pgm->pgm_type != PGM_NAK && - pgm->pgm_type != PGM_NNAK && - pgm->pgm_type != PGM_NCF && - pgm->pgm_type != PGM_SPMR ) - { - printf ("\t\"message\": \"PGM: Not a valid PGM packet type: %i.\",\n", pgm->pgm_type); - return -1; - } - - return 0; -} - -/* note: output trails tsdu length line to allow for comma - */ - -void -print_pgm_header ( - struct pgm_header* pgm - ) -{ - puts ("\t\"PGM\": {"); - printf ("\t\t\"sourcePort\": %i,\n", g_ntohs(pgm->pgm_sport)); - printf ("\t\t\"destinationPort\": %i,\n", g_ntohs(pgm->pgm_dport)); - printf ("\t\t\"type\": \"%s\",\n", pgm_type_string(pgm->pgm_type & 0xf)); - printf ("\t\t\"version\": %i,\n", (pgm->pgm_type & 0xc0) >> 6); - puts ("\t\t\"options\": {"); - printf ("\t\t\t\"networkSignificant\": %s,\n", (pgm->pgm_options & PGM_OPT_NETWORK) ? "true" : "false"); - printf ("\t\t\t\"parityPacket\": %s,\n", (pgm->pgm_options & PGM_OPT_PARITY) ? "true" : "false"); - printf ("\t\t\t\"variableLength\": %s\n", (pgm->pgm_options & PGM_OPT_VAR_PKTLEN) ? "true" : "false"); - puts ("\t\t},"); - printf ("\t\t\"checksum\": %i,\n", pgm->pgm_checksum); - printf ("\t\t\"gsi\": \"%i.%i.%i.%i.%i.%i\",\n", - pgm->pgm_gsi[0], - pgm->pgm_gsi[1], - pgm->pgm_gsi[2], - pgm->pgm_gsi[3], - pgm->pgm_gsi[4], - pgm->pgm_gsi[5]); - printf ("\t\t\"tsduLength\": %i", g_ntohs(pgm->pgm_tsdu_length)); -} - -/* 8.1. Source Path Messages (SPM) - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | SPM's Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Trailing Edge Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Leading Edge Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Path NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * NLA = Network Layer Address - * NLA AFI = NLA Address Family Indicator: rfc 1700 (ADDRESS FAMILY NUMBERS) - * => Path NLA = IP address of last network element - */ - -int -verify_spm ( - struct pgm_header* header, - char* data, - guint len - ) -{ - int retval = 0; - -/* truncated packet */ - if (len < sizeof(struct pgm_spm)) { - printf ("\t\"message\": \"SPM: packet length: %i less than minimum SPM length: %" G_GSIZE_FORMAT "lu bytes.\",\n", len, sizeof(struct pgm_spm)); - retval = -1; - goto out; - } - - struct pgm_spm* spm = (struct pgm_spm*)data; - char* opt_offset = (char*)(spm + 1); - guint opt_len = len - sizeof(spm); - - switch (g_ntohs(spm->spm_nla_afi)) { - case AFI_IP6: - if (len < sizeof(struct pgm_spm6)) { - printf ("\t\"message\": \"SPM: packet length: %i less than minimum IPv6 SPM length: %" G_GSIZE_FORMAT "lu bytes.\",\n", len, sizeof(struct pgm_spm6)); - retval = -1; - goto out; - } - opt_offset += sizeof(struct pgm_spm6) - sizeof(struct pgm_spm); - opt_len -= sizeof(struct pgm_spm6) - sizeof(struct pgm_spm); - - case AFI_IP: - break; - - default: - printf ("\t\"message\": \"SPM: invalid AFI of source NLA: %i.\",\n", g_ntohs(spm->spm_nla_afi)); - retval = -1; - goto out; - } - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT) - { - retval = verify_options (opt_offset, opt_len); - } - -out: - return retval; -} - -void -print_spm ( - struct pgm_header* header, - char* data - ) -{ - struct pgm_spm* spm = (struct pgm_spm*)data; - struct pgm_spm6* spm6 = (struct pgm_spm6*)data; - char* opt_offset = (char*)(spm + 1); - - puts (","); - printf ("\t\t\"spmSqn\": %i,\n", g_ntohl(spm->spm_sqn)); - printf ("\t\t\"spmTrail\": %i,\n", g_ntohl(spm->spm_trail)); - printf ("\t\t\"spmLead\": %i,\n", g_ntohl(spm->spm_lead)); - printf ("\t\t\"spmNlaAfi\": %i,\n", g_ntohs (spm->spm_nla_afi)); - - char s[INET6_ADDRSTRLEN]; - switch (g_ntohs(spm->spm_nla_afi)) { - case AFI_IP: - inet_ntop ( AF_INET, &spm->spm_nla, s, sizeof (s) ); - break; - - case AFI_IP6: - inet_ntop ( AF_INET6, &spm6->spm6_nla, s, sizeof (s) ); - opt_offset += sizeof(struct pgm_spm6) - sizeof(struct pgm_spm); - break; - } - - printf ("\t\t\"spmNla\": \"%s\"", s); - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT) - { - puts (","); - print_options (opt_offset); - } - - puts ("\n\t}"); -} - -/* 14.7.1. Poll Request - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLL's Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLL's Round | POLL's Sub-type | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Path NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | POLL's Back-off Interval | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Random String | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Matching Bit-Mask | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * Sent to ODATA multicast group with IP Router Alert option. - */ - -#define PGM_MIN_POLL_SIZE ( sizeof(struct pgm_poll) ) - -int -verify_poll ( - G_GNUC_UNUSED struct pgm_header* header, - G_GNUC_UNUSED char* data, - G_GNUC_UNUSED guint len - ) -{ - return -1; -} - -void -print_poll ( - G_GNUC_UNUSED struct pgm_header* header, - G_GNUC_UNUSED char* data - ) -{ -} - -/* 14.7.2. Poll Response - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLR's Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | POLR's Round | reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -int -verify_polr ( - G_GNUC_UNUSED struct pgm_header* header, - G_GNUC_UNUSED char* data, - G_GNUC_UNUSED guint len - ) -{ - return -1; -} - -void -print_polr ( - G_GNUC_UNUSED struct pgm_header* header, - G_GNUC_UNUSED char* data - ) -{ -} - -/* 8.2. Data Packet - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Data Packet Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Trailing Edge Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Data ... - * +-+-+- ... - */ - -int -verify_odata ( - struct pgm_header* header, - char* data, - guint len - ) -{ - int retval = 0; - - if (len < sizeof(struct pgm_data)) { - printf ("\t\"message\": \"ODATA: packet length: %i less than minimum ODATA length: %" G_GSIZE_FORMAT " bytes.\",\n", len, sizeof(struct pgm_data)); - retval = -1; - goto out; - } - - char* tsdu = data + sizeof(struct pgm_data); - guint tsdu_len = len - sizeof(struct pgm_data); - if (header->pgm_options & PGM_OPT_PRESENT) - { - retval = verify_options (tsdu, tsdu_len); - - guint opt_total_len = g_ntohs( OPTIONS_TOTAL_LEN(tsdu) ); - tsdu += opt_total_len; - tsdu_len -= opt_total_len; - } - - if (!retval && g_ntohs(header->pgm_tsdu_length) != tsdu_len) { - printf ("\t\"message\": \"ODATA: TSDU truncated expected %i, found %i bytes.\",\n", g_ntohs(header->pgm_tsdu_length), tsdu_len); - retval = -1; - } -out: - return retval; -} - -void -print_odata ( - struct pgm_header* header, - char* data - ) -{ - struct pgm_data* odata = (struct pgm_data*)data; - char* tsdu = data + sizeof(struct pgm_data); - - puts (","); - printf ("\t\t\"odSqn\": %lu,\n", (gulong)g_ntohl(odata->data_sqn)); - printf ("\t\t\"odTrail\": %lu,\n", (gulong)g_ntohl(odata->data_trail)); - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT) - { - print_options (tsdu); - tsdu += g_ntohs( OPTIONS_TOTAL_LEN(tsdu) ); - puts (","); - } - -/* data */ - printf ("\t\t\"data\": \""); - char* end = tsdu + g_ntohs (header->pgm_tsdu_length); - while (tsdu < end) { - if (isprint(*tsdu)) - putchar(*tsdu); - else - putchar('.'); - tsdu++; - } - - puts ("\""); - puts ("\t}"); -} - -/* 8.2. Repair Data - */ - -int -verify_rdata ( - struct pgm_header* header, - char* data, - guint len - ) -{ - int retval = 0; - - if (len < sizeof(struct pgm_data)) { - printf ("\t\"message\": \"RDATA: packet length: %i less than minimum RDATA length: %" G_GSIZE_FORMAT " bytes.\",\n", len, sizeof(struct pgm_data)); - retval = -1; - goto out; - } - - char* tsdu = data + sizeof(struct pgm_data); - guint tsdu_len = len - sizeof(struct pgm_data); - if (header->pgm_options & PGM_OPT_PRESENT) - { - retval = verify_options (tsdu, tsdu_len); - - guint opt_total_len = g_ntohs( OPTIONS_TOTAL_LEN(tsdu) ); - tsdu += opt_total_len; - tsdu_len -= opt_total_len; - } - - if (!retval && g_ntohs(header->pgm_tsdu_length) != tsdu_len) { - printf ("\t\"message\": \"RDATA: tsdu truncated expected %i, found %i bytes.\",\n", g_ntohs(header->pgm_tsdu_length), tsdu_len); - retval = -1; - } -out: - return retval; -} - -void -print_rdata ( - struct pgm_header* header, - char* data - ) -{ - struct pgm_data* rdata = (struct pgm_data*)data; - char* tsdu = data + sizeof(struct pgm_data); - - puts (","); - printf ("\t\t\"rdSqn\": %lu,\n", (gulong)g_ntohl(rdata->data_sqn)); - printf ("\t\t\"rdTrail\": %lu,\n", (gulong)g_ntohl(rdata->data_trail)); - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT) - { - print_options (tsdu); - tsdu += g_ntohs( OPTIONS_TOTAL_LEN(tsdu) ); - puts (","); - } - -/* data */ - printf ("\t\t\"data\": \""); - char* end = tsdu + g_ntohs (header->pgm_tsdu_length); - while (tsdu < end) { - if (isprint(*tsdu)) - putchar(*tsdu); - else - putchar('.'); - tsdu++; - } - - puts ("\""); - puts ("\t}"); -} - -/* 8.3. NAK - * - * Technically the AFI of the source and multicast group can be different - * but that would be very wibbly wobbly. One example is using a local DLR - * with a IPv4 address to reduce NAK cost for recovery on wide IPv6 - * distribution. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Requested Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | NLA AFI | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Multicast Group NLA ... | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ - * | Option Extensions when present ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... - */ - -int -verify_nak ( - struct pgm_header* header, - char* data, - guint len - ) -{ - return generic_verify_nak ("NAK", header, data, len); -} - -int -verify_ncf ( - struct pgm_header* header, - char* data, - guint len - ) -{ - return generic_verify_nak ("NCF", header, data, len); -} - -int -verify_nnak ( - struct pgm_header* header, - char* data, - guint len - ) -{ - return generic_verify_nak ("NNAK", header, data, len); -} - -static int -generic_verify_nak ( - const char* name, /* upper case */ - G_GNUC_UNUSED struct pgm_header* header, - char* data, - guint len - ) -{ - int retval = 0; - -/* truncated packet */ - if (len < sizeof(struct pgm_nak)) { - printf ("\t\"message\": \"%s: packet length: %i less than minimum %s length: %" G_GSIZE_FORMAT " bytes.\",\n", - name, len, name, sizeof(struct pgm_nak)); - retval = -1; - goto out; - } - - struct pgm_nak* nak = (struct pgm_nak*)data; - int nak_src_nla_afi = g_ntohs (nak->nak_src_nla_afi); - int nak_grp_nla_afi = -1; - -/* check source NLA: unicast address of the ODATA sender */ - switch (nak_src_nla_afi) { - case AFI_IP: - nak_grp_nla_afi = g_ntohs (nak->nak_grp_nla_afi); - break; - - case AFI_IP6: - nak_grp_nla_afi = g_ntohs (((struct pgm_nak6*)nak)->nak6_grp_nla_afi); - break; - - default: - printf ("\t\"message\": \"%s: invalid AFI of source NLA: %i.\",\n", - name, nak_src_nla_afi); - retval = -1; - goto out; - } - -/* check multicast group NLA */ - switch (nak_grp_nla_afi) { - case AFI_IP6: - switch (nak_src_nla_afi) { -/* IPv4 + IPv6 NLA */ - case AFI_IP: - if (len < ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) )) { - printf ("\t\"message\": \"%s: packet length: %i less than joint IPv4/6 %s length: %" G_GSIZE_FORMAT " bytes.\",\n", - name, len, name, ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) )); - retval = -1; - } - break; - -/* IPv6 + IPv6 NLA */ - case AFI_IP6: - if (len < sizeof(struct pgm_nak6)) { - printf ("\t\"message\": \"%s: packet length: %i less than IPv6 %s length: %" G_GSIZE_FORMAT " bytes.\",\n", - name, len, name, sizeof(struct pgm_nak6)); - retval = -1; - } - break; - } - break; - - case AFI_IP: - if (nak_src_nla_afi == AFI_IP6) { - if (len < ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) )) { - printf ("\t\"message\": \"%s: packet length: %i less than joint IPv6/4 %s length: %" G_GSIZE_FORMAT " bytes.\",\n", - name, len, name, ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) )); - retval = -1; - } - } - break; - - default: - printf ("\t\"message\": \"%s: invalid AFI of group NLA: %i.\",\n", - name, nak_grp_nla_afi); - retval = -1; - break; - } - -out: - return retval; -} - -void -print_nak ( - struct pgm_header* header, - char* data - ) -{ - generic_print_nak ("nak", header, data); -} - -void -print_ncf ( - struct pgm_header* header, - char* data - ) -{ - generic_print_nak ("ncf", header, data); -} - -void -print_nnak ( - struct pgm_header* header, - char* data - ) -{ - generic_print_nak ("nnak", header, data); -} - -static void -generic_print_nak ( - const char* name, /* lower case */ - struct pgm_header* header, - char* data - ) -{ - struct pgm_nak* nak = (struct pgm_nak*)data; - struct pgm_nak6* nak6 = (struct pgm_nak6*)data; - char* opt_offset = (char*)(nak + 1); - - puts (","); - printf ("\t\t\"%sSqn\": %lu,\n", name, (gulong)g_ntohl(nak->nak_sqn)); - - guint16 nak_src_nla_afi = g_ntohs (nak->nak_src_nla_afi); - guint16 nak_grp_nla_afi = 0; - char s[INET6_ADDRSTRLEN]; - - printf ("\t\t\"%sSourceNlaAfi\": %i,\n", name, nak_src_nla_afi); - -/* source nla */ - switch (nak_src_nla_afi) { - case AFI_IP: - inet_ntop ( AF_INET, &nak->nak_src_nla, s, sizeof(s) ); - nak_grp_nla_afi = g_ntohs (nak->nak_grp_nla_afi); - break; - - case AFI_IP6: - inet_ntop ( AF_INET6, &nak6->nak6_src_nla, s, sizeof(s) ); - nak_grp_nla_afi = g_ntohs (nak6->nak6_grp_nla_afi); - opt_offset += sizeof(struct in6_addr) - sizeof(struct in_addr); - break; - } - - printf ("\t\t\"%sSourceNla\": \"%s\",\n", name, s); - printf ("\t\t\"%sGroupNlaAfi\": %i,\n", name, nak_grp_nla_afi); - - switch (nak_grp_nla_afi) { - case AFI_IP6: - switch (nak_src_nla_afi) { -/* IPv4 + IPv6 NLA */ - case AFI_IP: - inet_ntop ( AF_INET6, &nak->nak_grp_nla, s, sizeof(s) ); - break; - -/* IPv6 + IPv6 NLA */ - case AFI_IP6: - inet_ntop ( AF_INET6, &nak6->nak6_grp_nla, s, sizeof(s) ); - break; - } - opt_offset += sizeof(struct in6_addr) - sizeof(struct in_addr); - break; - - case AFI_IP: - switch (nak_src_nla_afi) { -/* IPv4 + IPv4 NLA */ - case AFI_IP: - inet_ntop ( AF_INET, &nak->nak_grp_nla, s, sizeof(s) ); - break; - -/* IPv6 + IPv4 NLA */ - case AFI_IP6: - inet_ntop ( AF_INET, &nak6->nak6_grp_nla, s, sizeof(s) ); - break; - } - break; - } - - printf ("\t\t\"%sGroupNla\": \"%s\"", name, s); - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT) - { - puts (","); - print_options (opt_offset); - } - - puts ("\n\t}"); -} - - -/* 13.6. SPM Request - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Option Extensions when present ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... - */ - -int -verify_spmr ( - struct pgm_header* header, - char* data, - guint len - ) -{ - int retval = 0; - - char* opt_offset = data; - guint opt_len = len; - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT) - { - retval = verify_options (opt_offset, opt_len); - } - - return retval; -} - -void -print_spmr ( - struct pgm_header* header, - char* data - ) -{ - char* opt_offset = data; - -/* option extensions */ - if (header->pgm_options & PGM_OPT_PRESENT) - { - print_options (opt_offset); - puts (""); - } - - puts ("\t}"); -} - -/* Parse PGM options fields: - * - * assume at least two options, one the mandatory OPT_LENGTH - */ - -#define PGM_MIN_OPT_SIZE ( sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_length) ) - -int -verify_options ( - char* data, - guint len - ) -{ - int retval = 0; - - if (len < PGM_MIN_OPT_SIZE) { - printf ("\t\"message\": \"PGM options: packet size too small for options.\",\n"); - retval = -1; - goto out; - } - -/* OPT_LENGTH first */ - struct pgm_opt_length* opt_len = (struct pgm_opt_length*)data; - if ((opt_len->opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) { - printf ("\t\"message\": \"PGM options: first option not OPT_LENGTH.\",\n"); - retval = -1; - goto out; - } - - if (opt_len->opt_length != sizeof(struct pgm_opt_length)) { - printf ("\t\"message\": \"PGM options: OPT_LENGTH incorrect option length: %i, expecting %" G_GSIZE_FORMAT " bytes.\",\n", opt_len->opt_length, sizeof(struct pgm_opt_length)); - retval = -1; - goto out; - } - - if (g_ntohs(opt_len->opt_total_length) < PGM_MIN_OPT_SIZE) { - printf ("\t\"message\": \"PGM options: OPT_LENGTH total length too short: %i bytes.\",\n", g_ntohs(opt_len->opt_total_length)); - retval = -1; - goto out; - } - - if (g_ntohs(opt_len->opt_total_length) > len) { - printf ("\t\"message\": \"PGM options: OPT_LENGTH total length longer than packet allows: %i bytes.\",\n", g_ntohs(opt_len->opt_total_length)); - retval = -1; - goto out; - } - -/* iterate through options (max 16) */ - guint count = 0; - guint total_length = g_ntohs(opt_len->opt_total_length); - - guint opt_counters[256]; - memset (&opt_counters, 0, sizeof(opt_counters)); - - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)data; - for (;;) { - total_length -= opt_header->opt_length; - if (total_length < sizeof(struct pgm_opt_header)) { - printf ("\t\"message\": \"PGM options: option #%i shorter than minimum option size.\",\n", count + 1); - retval = -1; - goto out; - } - opt_header = (struct pgm_opt_header*)( ((char*)opt_header) + opt_header->opt_length ); - if (((int)total_length - (int)opt_header->opt_length) < 0) { - printf ("\t\"message\": \"PGM options: option #%i shorter than embedded size.\",\n", count + 1); - retval = -1; - goto out; - } - - if (opt_counters[opt_header->opt_type]++) { - printf ("\t\"message\": \"PGM options: duplicate option %i.\",\n", opt_header->opt_type); - retval = -1; - goto out; - } - -/* check option types */ - switch (opt_header->opt_type & PGM_OPT_MASK) { - case PGM_OPT_FRAGMENT: - { - if (opt_header->opt_length != sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fragment)) { - printf ("\t\"message\": \"PGM options: OPT_FRAGMENT incorrect size: %i bytes.\",\n", opt_header->opt_length); - retval = -1; - goto out; - } - - struct pgm_opt_fragment* opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); - if (g_ntohl(opt_fragment->opt_frag_off) > g_ntohl(opt_fragment->opt_frag_len)) { - printf ("\t\"message\": \"PGM options: fragment offset longer than original packet.\",\n"); - retval = -1; - goto out; - } - break; - } - - case PGM_OPT_NAK_LIST: - { - guint list_len = opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(guint8); - if (list_len & 1) { - printf ("\t\"message\": \"PGM options: OPT_NAK_LIST invalid odd length: %i bytes.\",\n", opt_header->opt_length); - retval = -1; - goto out; - } - - list_len /= 2; - if (list_len == 0) { - printf ("\t\"message\": \"PGM options: OPT_NAK_LIST empty.\",\n"); - retval = -1; - goto out; - } - - if (list_len > 62) { - printf ("\t\"message\": \"PGM options: OPT_NAK_LIST too long: %i sqns.\",\n", list_len); - retval = -1; - goto out; - } - break; - } - - case PGM_OPT_PARITY_PRM: - { - struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1); - if ((opt_parity_prm->opt_reserved & PGM_PARITY_PRM_MASK) == 0) { - printf ("\t\"message\": \"PGM options: neither pro-active or on-demand parity set in OPT_PARITY_PRM.\",\n"); - retval = -1; - goto out; - } - guint32 parity_prm_tgs = g_ntohl (opt_parity_prm->parity_prm_tgs); - if (parity_prm_tgs < 2 || parity_prm_tgs > 128) { - printf ("\t\"message\": \"PGM options: transmission group size out of bounds: %i.\",\n", parity_prm_tgs); - retval = -1; - goto out; - } - break; - } - - default: -/* unknown option, skip */ - break; - } -/* end option types */ - - if (opt_header->opt_type & PGM_OPT_END) { - break; - } - - if (count++ == 16) { - printf ("\t\"message\": \"PGM options: more than 16 options found.\",\n"); - retval = -1; - goto out; - } - } - -out: - return retval; -} - -static const char *opx_text[4] = { - "OPX_IGNORE", - "OPX_INVALIDATE", - "OPX_DISCARD", - "OPX_UNKNOWN" -}; - -void -print_options ( - char* data - ) -{ - struct pgm_opt_length* opt_len = (struct pgm_opt_length*)data; - - puts ("\t\t\"pgmOptions\": ["); - puts ("\t\t\t{"); - printf ("\t\t\t\t\"length\": 0x%x,\n", opt_len->opt_length); - puts ("\t\t\t\t\"type\": \"OPT_LENGTH\","); - printf ("\t\t\t\t\"totalLength\": %i\n", g_ntohs (opt_len->opt_total_length)); - printf ("\t\t\t}"); - -/* iterate through options */ - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)data; - do { - opt_header = (struct pgm_opt_header*)( ((char*)opt_header) + opt_header->opt_length ); - - puts (","); - puts ("\t\t\t{"); - printf ("\t\t\t\t\"length\": 0x%x,\n", opt_header->opt_length); - - switch (opt_header->opt_type & PGM_OPT_MASK) { - case PGM_OPT_FRAGMENT: - { - struct pgm_opt_fragment* opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); - printf ("\t\t\t\t\"type\": \"OPT_FRAGMENT%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); - printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); - printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); - printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_fragment->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); - printf ("\t\t\t\t\"firstSqn\": %i,\n", g_ntohl(opt_fragment->opt_sqn)); - printf ("\t\t\t\t\"fragmentOffset\": %i,\n", g_ntohl(opt_fragment->opt_frag_off)); - printf ("\t\t\t\t\"originalLength\": %i\n", g_ntohl(opt_fragment->opt_frag_len)); - break; - } - - case PGM_OPT_NAK_LIST: - { - struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); - char* end = (char*)opt_header + opt_header->opt_length; - printf ("\t\t\t\t\"type\": \"OPT_NAK_LIST%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); - printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); - printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); - printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_nak_list->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); - char sqns[1024] = ""; - guint i = 0; - do { - char sqn[1024]; - sprintf (sqn, "%s%i", (i>0)?", ":"", g_ntohl(opt_nak_list->opt_sqn[i])); - strcat (sqns, sqn); - i++; - } while ((char*)&opt_nak_list->opt_sqn[i] < end); - printf ("\t\t\t\t\"sqn\": [%s]\n", sqns); - break; - } - - case PGM_OPT_PARITY_PRM: - { - struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1); - printf ("\t\t\t\t\"type\": \"OPT_PARITY_PRM%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); - printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); - printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); - printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_parity_prm->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); - printf ("\t\t\t\t\"P-bit\": %s,\n", (opt_parity_prm->opt_reserved & PGM_PARITY_PRM_PRO) ? "true" : "false"); - printf ("\t\t\t\t\"O-bit\": %s,\n", (opt_parity_prm->opt_reserved & PGM_PARITY_PRM_OND) ? "true" : "false"); - printf ("\t\t\t\t\"transmissionGroupSize\": %i\n", g_ntohl(opt_parity_prm->parity_prm_tgs)); - break; - } - - case PGM_OPT_CURR_TGSIZE: - { - struct pgm_opt_curr_tgsize* opt_curr_tgsize = (struct pgm_opt_curr_tgsize*)(opt_header + 1); - printf ("\t\t\t\t\"type\": \"OPT_CURR_TGSIZE%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); - printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); - printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); - printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_curr_tgsize->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); - printf ("\t\t\t\t\"actualTransmissionGroupSize\": %i\n", g_ntohl(opt_curr_tgsize->prm_atgsize)); - break; - } - - case PGM_OPT_SYN: - { - struct pgm_opt_syn* opt_syn = (struct pgm_opt_syn*)(opt_header + 1); - printf ("\t\t\t\t\"type\": \"OPT_SYN%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); - printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); - printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); - printf ("\t\t\t\t\"U-bit\": %s\n", (opt_syn->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); - break; - } - - case PGM_OPT_FIN: - { - struct pgm_opt_fin* opt_fin = (struct pgm_opt_fin*)(opt_header + 1); - printf ("\t\t\t\t\"type\": \"OPT_FIN%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); - printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); - printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); - printf ("\t\t\t\t\"U-bit\": %s\n", (opt_fin->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); - break; - } - - default: - { - guint8 opt_reserved = *(guint8*)(opt_header + 1); - printf ("\t\t\t\t\"type\": \"0x%x%s\",\n", opt_header->opt_type & PGM_OPT_MASK, (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); - printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); - printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); - printf ("\t\t\t\t\"U-bit\": %s\n", (opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); - break; - } - } - printf ("\t\t\t}"); - - } while (!(opt_header->opt_type & PGM_OPT_END)); - - printf ("\n\t\t]"); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/dump-json.h b/3rdparty/openpgm-svn-r1085/pgm/test/dump-json.h deleted file mode 100644 index 6fa0f9d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/dump-json.h +++ /dev/null @@ -1,33 +0,0 @@ -/* vim:ts=8:sts=4:sw=4:noai:noexpandtab - * - * JSON packet dump. - * - * Copyright (c) 2006-2007 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __PGM_DUMP_JSON_H__ -#define __PGM_DUMP_JSON_H__ - - -G_BEGIN_DECLS - -int monitor_packet (char*, guint); - - -G_END_DECLS - -#endif /* __PGM_DUMP_JSON_H__ */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/heartbeat_spm.pl b/3rdparty/openpgm-svn-r1085/pgm/test/heartbeat_spm.pl deleted file mode 100755 index 60f6266..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/heartbeat_spm.pl +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/perl -# heartbeat_spm.pl -# 5.1.5. Heartbeat SPMs - -use strict; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$app->connect; - -sub close_ssh { - $mon = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -print "app: publish test data.\n"; -$app->say ("send ao ringo"); - -print "mon: wait for odata ...\n"; -$mon->wait_for_odata; -my $t0 = [gettimeofday]; - -for (1..4) # look for four consecutive heartbeat SPMs less than 5000ms apart -{ - print "mon: wait for spm ...\n"; - $mon->wait_for_spm ({ 'timeout' => 5 }); - my $tn = [gettimeofday]; - my $elapsed = tv_interval ( $t0, $tn ); - $t0 = $tn; - - print "mon: spm received after $elapsed seconds.\n"; -} - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/monitor.c b/3rdparty/openpgm-svn-r1085/pgm/test/monitor.c deleted file mode 100644 index 6569a55..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/monitor.c +++ /dev/null @@ -1,349 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM link monitor. - * - * Copyright (c) 2006-2007 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "dump-json.h" - - -/* globals */ - -static const char* g_network = "239.192.0.1"; -static struct in_addr g_filter /* = { 0 } */; - -static GIOChannel* g_io_channel = NULL; -static GIOChannel* g_stdin_channel = NULL; -static GMainLoop* g_loop = NULL; - - -static void on_signal (int, gpointer); -static gboolean on_startup (gpointer); -static gboolean on_mark (gpointer); - -static gboolean on_io_data (GIOChannel*, GIOCondition, gpointer); -static gboolean on_io_error (GIOChannel*, GIOCondition, gpointer); - -static gboolean on_stdin_data (GIOChannel*, GIOCondition, gpointer); - -int -main ( - G_GNUC_UNUSED int argc, - G_GNUC_UNUSED char *argv[] - ) -{ -/* pre-initialise PGM messages module to add hook for GLib logging */ - pgm_messages_init(); - log_init (); - puts ("monitor"); - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); - signal (SIGHUP, SIG_IGN); - pgm_signal_install (SIGINT, on_signal, g_loop); - pgm_signal_install (SIGTERM, on_signal, g_loop); - - g_filter.s_addr = 0; - -/* delayed startup */ - puts ("scheduling startup."); - g_timeout_add(0, (GSourceFunc)on_startup, NULL); - -/* dispatch loop */ - g_loop = g_main_loop_new(NULL, FALSE); - - puts ("entering main event loop ... "); - g_main_loop_run(g_loop); - - puts ("event loop terminated, cleaning up."); - -/* cleanup */ - g_main_loop_unref(g_loop); - g_loop = NULL; - - if (g_io_channel) { - puts ("closing socket."); - - GError *err = NULL; - g_io_channel_shutdown (g_io_channel, FALSE, &err); - g_io_channel = NULL; - } - - if (g_stdin_channel) { - puts ("unbinding stdin."); - g_io_channel_unref (g_stdin_channel); - g_stdin_channel = NULL; - } - - puts ("finished."); - pgm_messages_shutdown(); - return 0; -} - -static void -on_signal ( - int signum, - gpointer user_data - ) -{ - GMainLoop* loop = (GMainLoop*)user_data; - g_message ("on_signal (signum:%d user-data:%p)", signum, user_data); - g_main_loop_quit (loop); -} - -static gboolean -on_startup ( - G_GNUC_UNUSED gpointer data - ) -{ - int e; - - puts ("startup."); - -/* find PGM protocol id */ -// TODO: fix valgrind errors - int ipproto_pgm = IPPROTO_PGM; -#if HAVE_GETPROTOBYNAME_R - char b[1024]; - struct protoent protobuf, *proto; - e = getprotobyname_r("pgm", &protobuf, b, sizeof(b), &proto); - if (e != -1 && proto != NULL) { - if (proto->p_proto != ipproto_pgm) { - printf("Setting PGM protocol number to %i from /etc/protocols.\n"); - ipproto_pgm = proto->p_proto; - } - } -#else - struct protoent *proto = getprotobyname("pgm"); - if (proto != NULL) { - if (proto->p_proto != ipproto_pgm) { - printf("Setting PGM protocol number to %i from /etc/protocols.\n", proto -->p_proto); - ipproto_pgm = proto->p_proto; - } - } -#endif - -/* open socket for snooping */ - puts ("opening raw socket."); - int sock = socket(PF_INET, SOCK_RAW, ipproto_pgm); - if (sock < 0) { - int _e = errno; - perror("on_startup() failed"); - - if (_e == EPERM && 0 != getuid()) { - puts ("PGM protocol requires this program to run as superuser."); - } - g_main_loop_quit(g_loop); - return FALSE; - } - -/* drop out of setuid 0 */ - if (0 == getuid()) { - puts ("dropping superuser privileges."); - setuid((gid_t)65534); - setgid((uid_t)65534); - } - - char _t = 1; - e = setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &_t, sizeof(_t)); - if (e < 0) { - perror("on_startup() failed"); - close(sock); - g_main_loop_quit(g_loop); - return FALSE; - } - -/* buffers */ - int buffer_size = 0; - socklen_t len = 0; - e = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buffer_size, &len); - if (e == 0) { - printf ("receive buffer set at %i bytes.\n", buffer_size); - } - e = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buffer_size, &len); - if (e == 0) { - printf ("send buffer set at %i bytes.\n", buffer_size); - } - -/* bind */ - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - e = bind(sock, (struct sockaddr*)&addr, sizeof(addr)); - if (e < 0) { - perror("on_startup() failed"); - close(sock); - g_main_loop_quit(g_loop); - return FALSE; - } - -/* multicast */ - struct ip_mreq mreq; - memset(&mreq, 0, sizeof(mreq)); - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - printf ("listening on interface %s.\n", inet_ntoa(mreq.imr_interface)); - mreq.imr_multiaddr.s_addr = inet_addr(g_network); - printf ("subscription on multicast address %s.\n", inet_ntoa(mreq.imr_multiaddr)); - e = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); - if (e < 0) { - perror("on_startup() failed"); - close(sock); - g_main_loop_quit(g_loop); - return FALSE; - } - -/* multicast loopback */ -/* multicast ttl */ - -/* add socket to event manager */ - g_io_channel = g_io_channel_unix_new (sock); - printf ("socket opened with encoding %s.\n", g_io_channel_get_encoding(g_io_channel)); - - /* guint event = */ g_io_add_watch (g_io_channel, G_IO_IN | G_IO_PRI, on_io_data, NULL); - /* guint event = */ g_io_add_watch (g_io_channel, G_IO_ERR | G_IO_HUP | G_IO_NVAL, on_io_error, NULL); - -/* add stdin to event manager */ - g_stdin_channel = g_io_channel_unix_new (fileno(stdin)); - printf ("binding stdin with encoding %s.\n", g_io_channel_get_encoding(g_stdin_channel)); - - g_io_add_watch (g_stdin_channel, G_IO_IN | G_IO_PRI, on_stdin_data, NULL); - -/* period timer to indicate some form of life */ -// TODO: Gnome 2.14: replace with g_timeout_add_seconds() - g_timeout_add(10 * 1000, (GSourceFunc)on_mark, NULL); - - puts ("READY"); - fflush (stdout); - return FALSE; -} - -static gboolean -on_mark ( - G_GNUC_UNUSED gpointer data - ) -{ - g_message ("-- MARK --"); - return TRUE; -} - -static gboolean -on_io_data ( - GIOChannel* source, - G_GNUC_UNUSED GIOCondition condition, - G_GNUC_UNUSED gpointer data - ) -{ - char buffer[4096]; - int fd = g_io_channel_unix_get_fd(source); - struct sockaddr_in addr; - socklen_t addr_len = sizeof(addr); - int len = recvfrom(fd, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len); - - if (g_filter.s_addr && g_filter.s_addr != addr.sin_addr.s_addr) { - return TRUE; - } - - printf ("%i bytes received from %s.\n", len, inet_ntoa(addr.sin_addr)); - - monitor_packet (buffer, len); - fflush (stdout); - - return TRUE; -} - -static gboolean -on_io_error ( - GIOChannel* source, - G_GNUC_UNUSED GIOCondition condition, - G_GNUC_UNUSED gpointer data - ) -{ - puts ("on_error."); - - GError *err; - g_io_channel_shutdown (source, FALSE, &err); - -/* remove event */ - return FALSE; -} - -/* process input commands from stdin/fd - */ - -static gboolean -on_stdin_data ( - GIOChannel* source, - G_GNUC_UNUSED GIOCondition condition, - G_GNUC_UNUSED gpointer data - ) -{ - gchar* str = NULL; - gsize len = 0; - gsize term = 0; - GError* err = NULL; - - g_io_channel_read_line (source, &str, &len, &term, &err); - if (len > 0) { - if (term) str[term] = 0; - - if (strcmp(str, "quit") == 0) { - g_main_loop_quit(g_loop); - } else if (strncmp(str, "filter ", strlen("filter ")) == 0) { - unsigned a, b, c, d; - int retval = sscanf(str, "filter %u.%u.%u.%u", &a, &b, &c, &d); - if (retval == 4) { - g_filter.s_addr = (d << 24) | (c << 16) | (b << 8) | a; - puts ("READY"); - } else { - printf ("invalid syntax for filter command."); - } - } else { - printf ("unknown command: %s\n", str); - } - } - - fflush (stdout); - g_free (str); - return TRUE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/nak.pl b/3rdparty/openpgm-svn-r1085/pgm/test/nak.pl deleted file mode 100755 index cb75609..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/nak.pl +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/perl -# nak.pl -# 5.3. Repairs - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$sim->say ("create ao"); -$sim->say ("bind ao"); -print "sim: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); # to process NAK requests - -print "app: publish test data.\n"; -$app->say ("send ao ringo"); -$app->say ("send ao ichigo"); -$app->say ("send ao momo"); - -my $odata = undef; -my $ocnt = 0; -for (1..3) { - print "mon: wait for odata ...\n"; - $odata = $mon->wait_for_odata; - $ocnt++; - print "mon: received $ocnt x odata.\n"; -} - -print "sim: send nak to app.\n"; -$sim->say ("net send nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 2"); - -print "mon: wait for rdata ...\n"; -$mon->wait_for_rdata; -print "mon: rdata received.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/nak_cancellation.pl b/3rdparty/openpgm-svn-r1085/pgm/test/nak_cancellation.pl deleted file mode 100755 index 6ad36fe..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/nak_cancellation.pl +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/perl -# nak_cancellation.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use IO::Handle; -use JSON; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -pipe(FROM_PARENT, TO_CHILD) or die "pipe: $!"; -FROM_PARENT->autoflush(1); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - close FROM_PARENT; close TO_CHILD; - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("set ao NAK_BO_IVL 5000"); # increase to count for test system latency -$app->say ("set ao NAK_RPT_IVL 10000"); -$app->say ("set ao NAK_RDATA_IVL 10000"); -$app->say ("set ao NAK_NCF_RETRIES 15"); -$app->say ("set ao NAK_DATA_RETRIES 10"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -## capture GSI of test spp -$app->say ("send ao nashi"); -print "mon: wait for odata ...\n"; -my $odata = $mon->wait_for_odata; -print "mon: odata received.\n"; - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; -$sim->say ("net send spm ao 3200 90001 90000"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90001 ringo"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,003.\n"; -$sim->say ("net send odata ao 90003 90001 ichigo"); -my $t0 = [gettimeofday]; - -if (my $pid = fork) { -# parent - close FROM_PARENT; - - sleep 10; - - print "app: wait for data ...\n"; - my $data = $app->wait_for_data({ 'timeout' => 0 }); - print "app: data received [$data].\n"; - - print TO_CHILD "die\n"; - - close TO_CHILD; - waitpid($pid,0); -} else { -# child - die "cannot fork: $!" unless defined $pid; - close TO_CHILD; - - print "sim: loop waiting for NAKs ...\n"; - - my $fh = $sim->{in}; - vec(my $rin, fileno(FROM_PARENT), 1) = 1; - vec($rin, fileno($fh), 1) = 1; - my $rout = undef; - - my $b = ''; - my $state = 0; - my $json = new JSON; - my $io = IO::Handle->new_from_fd( fileno($fh), "r" ); - my $cnt = 0; - while (select($rout = $rin, undef, undef, undef)) - { - last if( vec($rout, fileno(FROM_PARENT), 1) ); - while (defined($_ = $io->getline)) - { - chomp; - my $l = $_; - if ($state == 0) { - if ($l =~ /{$/) { - $state = 1; - } else { - print "sim [$l]\n"; - last; - } - } - - if ($state == 1) { - $b .= $l; - - if ($l =~ /^}$/) { - $state = 0; - - my $obj = $json->jsonToObj($b); - if ($obj->{PGM}->{type} =~ /NAK/) { - $cnt++; - my $elapsed = tv_interval ( $t0, [gettimeofday] ); - print "sim: $cnt x NAK received in $elapsed seconds.\n"; - $sim->say ("net send ncf ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 90002"); - } - -# reset - $b = ''; - last; - } - } - } - last if ($io->eof); - } - - print "sim: loop finished.\n"; - close FROM_PARENT; - exit; -} - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/nak_list.pl b/3rdparty/openpgm-svn-r1085/pgm/test/nak_list.pl deleted file mode 100755 index 838dfd5..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/nak_list.pl +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/perl -# nak_list.pl -# 9.3. NAK List Option - OPT_NAK_LIST - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$sim->say ("create ao"); -$sim->say ("bind ao"); -print "sim: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -print "app: publish test data.\n"; -$app->say ("send ao ringo"); -$app->say ("send ao ichigo"); -$app->say ("send ao momo"); - -my $odata = undef; -my $ocnt = 0; -for (1..3) { - print "mon: wait for odata ...\n"; - $odata = $mon->wait_for_odata; - $ocnt++; - print "mon: received $ocnt x odata.\n"; -} - -print "sim: send nak to app.\n"; -$sim->say ("net send nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 0,1,2"); - -my $rcnt = 0; -for (1..3) { - print "mon: wait for rdata ...\n"; - $mon->wait_for_rdata; - $rcnt++; - print "mon: received $rcnt x rdata.\n"; -} - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/nak_parity.pl b/3rdparty/openpgm-svn-r1085/pgm/test/nak_parity.pl deleted file mode 100755 index 50f961b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/nak_parity.pl +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/perl -# nak_parity.pl -# 5.3. Repairs - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$sim->say ("create ao"); -$sim->say ("set ao FEC RS(255,4)"); -$sim->say ("bind ao"); -print "sim: ready.\n"; - -$app->say ("create ao"); -$app->say ("set ao FEC RS(255,4)"); -$app->say ("bind ao"); -$app->say ("listen ao"); # to process NAK requests - -print "app: publish test data.\n"; -$app->say ("send ao ringo"); -$app->say ("send ao ichigo"); -$app->say ("send ao momo"); -$app->say ("send ao budo"); -$app->say ("send ao nashi"); -$app->say ("send ao anzu"); -$app->say ("send ao kaki"); - -my $odata = undef; -my $ocnt = 0; -for (1..7) { - print "mon: wait for odata ...\n"; - $odata = $mon->wait_for_odata; - $ocnt++; - print "mon: received $ocnt x odata.\n"; -} - -print "sim: send nak to app (transmission group = 0, packet count = 1).\n"; -$sim->say ("net send parity nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 1"); - -print "mon: wait for rdata ...\n"; -my $rdata = $mon->wait_for_rdata; -print "mon: rdata received.\n"; - -die "Selective RDATA received, parityPacket=false\n" unless $rdata->{PGM}->{options}->{parityPacket}; -print "Parity RDATA received.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/nak_repeat.pl b/3rdparty/openpgm-svn-r1085/pgm/test/nak_repeat.pl deleted file mode 100755 index b811fa8..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/nak_repeat.pl +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/perl -# nak_repeat.pl -# 5.3. Repairs - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$sim->say ("create ao"); -$sim->say ("bind ao"); -print "sim: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); # to process NAK requests - -print "app: publish test data.\n"; -$app->say ("send ao " . ("ringo" x 200)); -$app->say ("send ao " . ("ichigo" x 200)); -$app->say ("send ao " . ("momo" x 200)); - -my $odata = undef; -my $ocnt = 0; -for (1..3) { - print "mon: wait for odata ...\n"; - $odata = $mon->wait_for_odata; - $ocnt++; - print "mon: received $ocnt x odata.\n"; -} - -for (1..1000) { - my $i = $_; - print "sim: $i# send nak to app.\n"; - $sim->say ("net send nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 2"); - - print "mon: $i# wait for rdata ...\n"; - $mon->wait_for_rdata; - print "mon: $i# rdata received.\n"; -} - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/ncf.pl b/3rdparty/openpgm-svn-r1085/pgm/test/ncf.pl deleted file mode 100755 index e26145f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/ncf.pl +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/perl -# ncf.pl -# 5.2. Negative Acknowledgment Confirmation - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$sim->say ("create ao"); -$sim->say ("bind ao"); -print "sim: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -print "app: publish test data.\n"; -$app->say ("send ao ringo"); -$app->say ("send ao ichigo"); -$app->say ("send ao momo"); - -my $odata = undef; -my $ocnt = 0; -for (1..3) { - print "mon: wait for odata ...\n"; - $odata = $mon->wait_for_odata; - $ocnt++; - print "mon: received $ocnt x odata.\n"; -} - -print "sim: send nak to app.\n"; -$sim->say ("net send nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 2"); - -print "mon: wait for ncf ...\n"; -$mon->wait_for_ncf; -print "mon: ncf received.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/ncf_cancellation.pl b/3rdparty/openpgm-svn-r1085/pgm/test/ncf_cancellation.pl deleted file mode 100755 index ca23b22..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/ncf_cancellation.pl +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/perl -# ncf_cancellation.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use IO::Handle; -use JSON; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -pipe(FROM_PARENT, TO_CHILD) or die "pipe: $!"; -FROM_PARENT->autoflush(1); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - close FROM_PARENT; close TO_CHILD; - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -## capture GSI of test spp -$app->say ("send ao nashi"); -print "mon: wait for odata ...\n"; -my $odata = $mon->wait_for_odata; -print "mon: odata received.\n"; - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; -$sim->say ("net send spm ao 3200 90001 90000"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90001 ringo"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,003.\n"; -$sim->say ("net send odata ao 90003 90001 ichigo"); -my $t0 = [gettimeofday]; - -if (my $pid = fork) { -# parent - close FROM_PARENT; - - print "app: wait for data ...\n"; - my $data = $app->wait_for_data({ 'timeout' => 0 }); - print "app: data received [$data].\n"; - - print TO_CHILD "die\n"; - - close TO_CHILD; - waitpid($pid,0); -} else { -# child - die "cannot fork: $!" unless defined $pid; - close TO_CHILD; - print "sim: loop waiting for NAKs ...\n"; - - my $fh = $sim->{in}; - vec(my $rin, fileno(FROM_PARENT), 1) = 1; - vec($rin, fileno($fh), 1) = 1; - my $rout = undef; - - my $b = ''; - my $state = 0; - my $json = new JSON; - my $io = IO::Handle->new_from_fd( fileno($fh), "r" ); - my $cnt = 0; - while (select($rout = $rin, undef, undef, undef)) - { - last if( vec($rout, fileno(FROM_PARENT), 1) ); - last unless (defined($_ = $io->getline)); - chomp; - my $l = $_; - if ($state == 0) { - if ($l =~ /{$/) { - $state = 1; - } else { - print "sim [$l]\n"; - } - } - - if ($state == 1) { - $b .= $l; - - if ($l =~ /^}$/) { - $state = 0; - - my $obj = $json->jsonToObj($b); - if ($obj->{PGM}->{type} =~ /NAK/) { - $cnt++; - my $elapsed = tv_interval ( $t0, [gettimeofday] ); - print "sim: $cnt x NAK received in $elapsed seconds.\n"; - } - -# reset - $b = ''; - } - } - } - - print "sim: loop finished.\n"; - close FROM_PARENT; - exit; -} - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/ncf_list.pl b/3rdparty/openpgm-svn-r1085/pgm/test/ncf_list.pl deleted file mode 100755 index 55b1d81..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/ncf_list.pl +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/perl -# ncf_list.pl -# 9.3. NAK List Option - OPT_NAK_LIST - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$sim->say ("create ao"); -$sim->say ("bind ao"); -print "sim: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -print "app: publish test data.\n"; -$app->say ("send ao ringo"); -$app->say ("send ao ichigo"); -$app->say ("send ao momo"); - -my $odata = undef; -my $ocnt = 0; -for (1..3) { - print "mon: wait for odata ...\n"; - $odata = $mon->wait_for_odata; - $ocnt++; - print "mon: received $ocnt x odata.\n"; -} - -print "sim: send nak to app.\n"; -$sim->say ("net send nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 1,2,3"); - -print "mon: wait for ncf ...\n"; -my $ncf = $mon->wait_for_ncf; -print "mon: ncf received.\n"; -die "ncfSqn != 1\n" unless $ncf->{PGM}->{ncfSqn} == 1; -die "NCF list incorrect\n" unless ( - $ncf->{PGM}->{pgmOptions}[1]->{sqn}[0] == 2 - && $ncf->{PGM}->{pgmOptions}[1]->{sqn}[1] == 3 - ); -print "mon: ncf list correct: $ncf->{PGM}->{ncfSqn} + [$ncf->{PGM}->{pgmOptions}[1]->{sqn}[0], $ncf->{PGM}->{pgmOptions}[1]->{sqn}[1]]\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/ncf_suppression.pl b/3rdparty/openpgm-svn-r1085/pgm/test/ncf_suppression.pl deleted file mode 100755 index c1d42a8..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/ncf_suppression.pl +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/perl -# ncf_suppression.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -## capture GSI of test spp -$app->say ("send ao nashi"); -print "mon: wait for odata ...\n"; -my $odata = $mon->wait_for_odata; -print "mon: odata received.\n"; - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; -$sim->say ("net send spm ao 3200 90001 90000"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90001 ringo"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -## first run through with regular NAK generation to get regular backoff interval -print "sim: publish ODATA sqn 90,003.\n"; -$sim->say ("net send odata ao 90003 90001 ichigo"); -my $t0 = [gettimeofday]; -print "sim: waiting for valid NAK.\n"; -$sim->wait_for_nak; -my $normal_backoff = tv_interval ( $t0, [gettimeofday] ); -print "sim: NAK received in $normal_backoff seconds.\n"; - -## cleanup by publishing repair data -print "sim: publish RDATA sqn 90,002.\n"; -$sim->say ("net send odata ao 90002 90001 momo"); -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -## second run with NAK suppression -$t0 = [gettimeofday]; -print "sim: publish ODATA sqn 90,005.\n"; -$sim->say ("net send odata ao 90005 90001 anzu"); -print "sim: publish NCF sqn 90,004.\n"; -$sim->say ("net send ncf ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 90004"); - -print "sim: waiting for valid NAK.\n"; -$sim->wait_for_nak; -my $suppressed_backoff = tv_interval ( $t0, [gettimeofday] ); -print "sim: NAK received in $suppressed_backoff seconds.\n"; - -die "NAK suppression failed.\n" unless ($suppressed_backoff > $normal_backoff); - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/odata.pl b/3rdparty/openpgm-svn-r1085/pgm/test/odata.pl deleted file mode 100755 index 50bcec0..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/odata.pl +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/perl -# odata.pl -# 3.6.2.1. ODATA - Original Data - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$app->connect; - -sub close_ssh { - $mon = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); - -print "app: publish test data.\n"; -$app->say ("send ao ringo"); - -print "mon: wait for odata ...\n"; -$mon->wait_for_odata; -print "mon: received odata.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/odata_completion.pl b/3rdparty/openpgm-svn-r1085/pgm/test/odata_completion.pl deleted file mode 100755 index 6b45a47..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/odata_completion.pl +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/perl -# odata_completion.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -## capture GSI of test spp -$app->say ("send ao nashi"); -print "mon: wait for odata ...\n"; -my $odata = $mon->wait_for_odata; -print "mon: odata received.\n"; - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; -$sim->say ("net send spm ao 3200 90001 90000"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90001 ringo"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,003.\n"; -$sim->say ("net send odata ao 90003 90001 ichigo"); -print "sim: waiting for valid NAK.\n"; -$sim->wait_for_nak; -print "sim: NAK received.\n"; - -print "sim: publish ODATA sqn 90,002.\n"; -$sim->say ("net send odata ao 90002 90001 momo"); - -for (1..2) -{ - print "app: wait for data ...\n"; - my $data = $app->wait_for_data; - print "app: data received [$data].\n"; -} - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/odata_jump.pl b/3rdparty/openpgm-svn-r1085/pgm/test/odata_jump.pl deleted file mode 100755 index aec4d82..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/odata_jump.pl +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/perl -# odata_jump.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; -$sim->say ("net send spm ao 3200 90001 90000"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90001 ringo"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,003.\n"; -$sim->say ("net send odata ao 90003 90001 ichigo"); - -print "sim: waiting for valid NAK.\n"; -$sim->wait_for_nak; -print "sim: NAK received.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/odata_jump_parity.pl b/3rdparty/openpgm-svn-r1085/pgm/test/odata_jump_parity.pl deleted file mode 100755 index 99179cc..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/odata_jump_parity.pl +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/perl -# odata_jump_parity.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 32,769 txw_lead 32,768 at spm_sqn 3200, advertise on-demand parity, k=4.\n"; -$sim->say ("net send spm ao 3200 32769 32768 on-demand 4"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 32,769.\n"; -$sim->say ("net send odata ao 32769 32769 ringo"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -# force window into next transmission group -print "sim: publish ODATA sqn 32,771.\n"; -$sim->say ("net send odata ao 32771 32769 ichigo"); -print "sim: publish ODATA sqn 32,772.\n"; -$sim->say ("net send odata ao 32772 32769 momo"); -print "sim: publish ODATA sqn 32,773.\n"; -$sim->say ("net send odata ao 32773 32769 yakitori"); -print "sim: publish ODATA sqn 32,774.\n"; -$sim->say ("net send odata ao 32774 32769 sasami"); -print "sim: publish ODATA sqn 32,775.\n"; -$sim->say ("net send odata ao 32775 32769 tebasaki"); - -print "sim: waiting for valid NAK.\n"; -my $nak = $sim->wait_for_nak; -print "sim: NAK received.\n"; - -die "Selective NAK received, parityPacket=false\n" unless $nak->{PGM}->{options}->{parityPacket}; -print "Parity NAK received.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/odata_number.pl b/3rdparty/openpgm-svn-r1085/pgm/test/odata_number.pl deleted file mode 100755 index 2d442dc..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/odata_number.pl +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/perl -# odata_number.pl -# 5.1.1. Maximum Cumulative Transmit Rate - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$app->connect; - -sub close_ssh { - $mon = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -print "app: send 1000 data packets ...\n"; -# hide stdout -open(OLDOUT, ">&STDOUT"); -open(STDOUT, ">/dev/null") or die "Can't redirect stdout: $!"; - -for (0..999) -{ - my $i = $_; - $app->say ("send ao $i"); - my $odata = $mon->wait_for_odata; - - die "out of sequence ODATA, received $odata->{PGM}->{odSqn} expected $i\n" unless $odata->{PGM}->{odSqn} == $i; -} - -# restore stdout -close(STDOUT) or die "Can't close STDOUT: $!"; -open(STDOUT, ">&OLDOUT") or die "Can't restore stdout: $!"; -close(OLDOUT) or die "Can't close OLDOUT: $!"; - -print "mon: received 1000 x odata.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/odata_rate.pl b/3rdparty/openpgm-svn-r1085/pgm/test/odata_rate.pl deleted file mode 100755 index fb8c7e0..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/odata_rate.pl +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/perl -# odata_number.pl -# 5.1.1. Maximum Cumulative Transmit Rate - -use strict; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$app->connect; - -sub close_ssh { - $mon = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("set ao TXW_MAX_RTE 1500"); -$app->say ("bind ao"); - -print "app: send 50 data packets ...\n"; -my $t0 = [gettimeofday]; - -# hide stdout -open(OLDOUT, ">&STDOUT"); -open(STDOUT, ">/dev/null") or die "Can't redirect stdout: $!"; - -my $payload = "ringo" x 100; -my $bytes = 0; -for (1..50) -{ - $app->say ("send ao $payload"); - my $odata = $mon->wait_for_odata; - $bytes += $odata->{IP}->{length}; -} - -close(STDOUT) or die "Can't close STDOUT: $!"; -open(STDOUT, ">&OLDOUT") or die "Can't restore stdout: $!"; -close(OLDOUT) or die "Can't close OLDOUT: $!"; - -my $elapsed = tv_interval ( $t0, [gettimeofday] ); -print "mon: received 50 x odata, $bytes bytes in $elapsed seconds.\n"; - -my $rate = $bytes / $elapsed; -$rate = $bytes if ($rate > $bytes); -print "mon: incoming data rate $rate bps.\n"; - -die "incoming rate exceeds set TXW_MAX_RTE\n" unless $rate < 1650; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/odata_reception.pl b/3rdparty/openpgm-svn-r1085/pgm/test/odata_reception.pl deleted file mode 100755 index ef95974..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/odata_reception.pl +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/perl -# odata_reception.pl -# 6.1. Data Reception - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish ODATA sqn 90,000.\n"; -$sim->say ("net send odata ao 90000 90000 ringo"); -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: received data [$data].\n"; - -# no NAKs should be generated. -# TODO: test for silence in {mon} - -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90000 ichigo"); -print "app: wait for data ...\n"; -$data = $app->wait_for_data; -print "app: received data [$data].\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/on-demand_spm.pl b/3rdparty/openpgm-svn-r1085/pgm/test/on-demand_spm.pl deleted file mode 100755 index eb86cf9..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/on-demand_spm.pl +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/perl -# on-demand_spm.pl -# 5.1.4. Ambient SPMs with on-demand parity flag - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$app->connect; - -sub close_ssh { - $mon = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("set ao FEC RS(255,64)"); -$app->say ("bind ao"); -print "app: ready.\n"; - -print "mon: wait for spm ...\n"; -my $spm = $mon->wait_for_spm; -print "mon: received spm.\n"; - -die "SPM does not contain any PGM options\n" unless $spm->{PGM}->{pgmOptions}; -die "SPM does not contain a PGM_OPT_PARITY_PRM option\n" unless $spm->{PGM}->{pgmOptions}[1]->{type} =~ /OPT_PARITY_PRM/; -print "pro-active parity " . ($spm->{PGM}->{pgmOptions}[1]->{'P-bit'} ? 'enabled' : 'disabled') . ", P-bit " . ($spm->{PGM}->{pgmOptions}[1]->{'P-bit'} ? 'true' : 'false') . "\n"; -die "on-demand parity disabled, O-bit false\n" unless $spm->{PGM}->{pgmOptions}[1]->{'O-bit'}; -print "on-demand parity enabled, O-bit true\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/outofwindow_ncf.pl b/3rdparty/openpgm-svn-r1085/pgm/test/outofwindow_ncf.pl deleted file mode 100755 index 4849e36..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/outofwindow_ncf.pl +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/perl -# outofwindow_ncf.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -## capture GSI of test spp -$app->say ("send ao nashi"); -print "mon: wait for odata ...\n"; -my $odata = $mon->wait_for_odata; -print "mon: odata received.\n"; - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; -$sim->say ("net send spm ao 3200 90001 90000"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90001 ringo"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -## first run through with regular NAK generation to get regular backoff interval -print "sim: publish ODATA sqn 90,003.\n"; -$sim->say ("net send odata ao 90003 90001 ichigo"); -my $t0 = [gettimeofday]; -print "sim: waiting for valid NAK.\n"; -$sim->wait_for_nak; -my $normal_backoff = tv_interval ( $t0, [gettimeofday] ); -print "sim: NAK received in $normal_backoff seconds.\n"; - -## cleanup by publishing repair data -print "sim: publish RDATA sqn 90,002.\n"; -$sim->say ("net send odata ao 90002 90001 momo"); -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -## second run with NAK suppression -$t0 = [gettimeofday]; -print "sim: publish ODATA sqn 90,005.\n"; -$sim->say ("net send odata ao 90005 90001 anzu"); -print "sim: publish NCF sqn 90,004.\n"; -$sim->say ("net send ncf ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 90002"); - -print "sim: waiting for valid NAK.\n"; -$sim->wait_for_nak; -my $outofwindow_backoff = tv_interval ( $t0, [gettimeofday] ); -print "sim: NAK received in $outofwindow_backoff seconds.\n"; - -# allow 100ms tolerance -my $fabs = abs( ($outofwindow_backoff - $normal_backoff) * 1000 ); -die "Out-of-window NCF altered back-off interval by $fabs ms.\n" unless ($fabs < 100); - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion.pl b/3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion.pl deleted file mode 100755 index 8a0cc60..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion.pl +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/perl -# rdata_completion.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -## capture GSI of test spp -$app->say ("send ao nashi"); -print "mon: wait for odata ...\n"; -my $odata = $mon->wait_for_odata; -print "mon: odata received.\n"; - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; -$sim->say ("net send spm ao 3200 90001 90000"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90001 ringo"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,003.\n"; -$sim->say ("net send odata ao 90003 90001 ichigo"); -print "sim: waiting for valid NAK.\n"; -$sim->wait_for_nak; -print "sim: NAK received.\n"; - -print "sim: publish RDATA sqn 90,002.\n"; -$sim->say ("net send rdata ao 90002 90001 momo"); - -for (1..2) -{ - print "app: wait for data ...\n"; - my $data = $app->wait_for_data; - print "app: data received [$data].\n"; -} - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion_parity.pl b/3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion_parity.pl deleted file mode 100755 index 95a6f7b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion_parity.pl +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/perl -# rdata_completion_parity.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("set ao FEC RS(255,4)"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -## capture GSI of test spp -$app->say ("send ao nashi"); -print "mon: wait for odata ...\n"; -my $odata = $mon->wait_for_odata; -print "mon: odata received.\n"; - -$sim->say ("create fake ao"); -$sim->say ("set ao FEC RS(255,4)"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 32,769 txw_lead 32,768 at spm_sqn 3200, advertise on-demand parity, k=4.\n"; -$sim->say ("net send spm ao 3200 32768 32767 on-demand 4"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 32,768.\n"; -$sim->say ("net send odata ao 32768 32768 ringo000"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 32,770.\n"; -$sim->say ("net send odata ao 32770 32768 momo0000"); -print "sim: publish ODATA sqn 32,771.\n"; -$sim->say ("net send odata ao 32771 32768 yakitori"); -print "sim: publish ODATA sqn 32,772.\n"; -$sim->say ("net send odata ao 32772 32768 sasami00"); -print "sim: publish ODATA sqn 32,773.\n"; -$sim->say ("net send odata ao 32773 32768 tebasaki"); - -print "sim: waiting for valid parity NAK.\n"; -my $nak = $sim->wait_for_nak; -die "Selective NAK received, parityPacket=false\n" unless $nak->{PGM}->{options}->{parityPacket}; -print "sim: Parity NAK received.\n"; - -print "sim: publish parity RDATA, tg_sqn 32,768, pkt_cnt 1 (sqn 32,768).\n"; -$sim->say ("net send parity rdata ao 32768 32768 ringo000 ichigo00 momo0000 yakitori"); - -for (1..5) -{ - print "app: wait for data ...\n"; - my $data = $app->wait_for_data; - print "app: data received [$data].\n"; -} - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion_parity_var_pktlen.pl b/3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion_parity_var_pktlen.pl deleted file mode 100755 index 9011ea1..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/rdata_completion_parity_var_pktlen.pl +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/perl -# rdata_completion_parity_var_pktlen.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("set ao FEC RS(255,4)"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -## capture GSI of test spp -$app->say ("send ao nashi"); -print "mon: wait for odata ...\n"; -my $odata = $mon->wait_for_odata; -print "mon: odata received.\n"; - -$sim->say ("create fake ao"); -$sim->say ("set ao FEC RS(255,4)"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 32,769 txw_lead 32,768 at spm_sqn 3200, advertise on-demand parity, k=4.\n"; -$sim->say ("net send spm ao 3200 32768 32767 on-demand 4"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 32,768.\n"; -$sim->say ("net send odata ao 32768 32768 ringo"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak ({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 32,770.\n"; -$sim->say ("net send odata ao 32770 32768 momo"); -print "sim: publish ODATA sqn 32,771.\n"; -$sim->say ("net send odata ao 32771 32768 yakitori"); -print "sim: publish ODATA sqn 32,772.\n"; -$sim->say ("net send odata ao 32772 32768 sasami"); -print "sim: publish ODATA sqn 32,773.\n"; -$sim->say ("net send odata ao 32773 32768 tebasaki"); - -print "sim: waiting for valid parity NAK.\n"; -my $nak = $sim->wait_for_nak; -die "Selective NAK received, parityPacket=false\n" unless $nak->{PGM}->{options}->{parityPacket}; -print "sim: Parity NAK received.\n"; - -print "sim: publish parity RDATA, tg_sqn 32,768, pkt_cnt 1 (sqn 32,768).\n"; -$sim->say ("net send parity rdata ao 32768 32768 ringo ichigo momo yakitori"); - -for (1..5) -{ - print "app: wait for data ...\n"; - my $data = $app->wait_for_data; - print "app: data received [$data].\n"; -} - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/rdata_jump.pl b/3rdparty/openpgm-svn-r1085/pgm/test/rdata_jump.pl deleted file mode 100755 index f472b33..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/rdata_jump.pl +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/perl -# rdata_jump.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; -$sim->say ("net send spm ao 3200 90001 90000"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90001 ringo"); - -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: data received [$data].\n"; - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish RDATA sqn 90,003.\n"; -$sim->say ("net send rdata ao 90003 90001 ichigo"); - -print "sim: waiting for valid NAK.\n"; -$sim->wait_for_nak; -print "sim: NAK received.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/rdata_reception.pl b/3rdparty/openpgm-svn-r1085/pgm/test/rdata_reception.pl deleted file mode 100755 index a26bb4e..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/rdata_reception.pl +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/perl -# rdata_reception.pl -# 6.1. Data Reception - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish RDATA sqn 90,000.\n"; -$sim->say ("net send rdata ao 90000 90000 ringo"); -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: received data [$data].\n"; - -# no NAKs should be generated. -# TODO: test for silence in {mon} - -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90000 ichigo"); -print "app: wait for data ...\n"; -$data = $app->wait_for_data; -print "app: received data [$data].\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/sim.c b/3rdparty/openpgm-svn-r1085/pgm/test/sim.c deleted file mode 100644 index b0e473b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/sim.c +++ /dev/null @@ -1,1924 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM conformance endpoint simulator. - * - * Copyright (c) 2006-2008 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "dump-json.h" -#include "async.h" - - -/* typedefs */ - -struct idle_source { - GSource source; - guint64 expiration; -}; - -struct sim_session { - char* name; - pgm_transport_t* transport; - gboolean is_transport_fake; - GIOChannel* recv_channel; - pgm_async_t* async; -}; - -/* globals */ -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "sim" - -#ifndef SOL_IP -# define SOL_IP IPPROTO_IP -#endif -#ifndef SOL_IPV6 -# define SOL_IPV6 IPPROTO_IPV6 -#endif - - -static int g_port = 7500; -static const char* g_network = ";239.192.0.1"; - -static int g_max_tpdu = 1500; -static int g_sqns = 100 * 1000; - -static GList* g_sessions_list = NULL; -static GHashTable* g_sessions = NULL; -static GMainLoop* g_loop = NULL; -static GIOChannel* g_stdin_channel = NULL; - - -static void on_signal (int, gpointer); -static gboolean on_startup (gpointer); -static gboolean on_mark (gpointer); -static void destroy_session (struct sim_session*); -static int on_data (gpointer, guint, gpointer); -static gboolean on_stdin_data (GIOChannel*, GIOCondition, gpointer); -void generic_net_send_nak (guint8, char*, pgm_tsi_t*, struct pgm_sqn_list_t*); - - -G_GNUC_NORETURN static -void -usage (const char* bin) -{ - fprintf (stderr, "Usage: %s [options]\n", bin); - fprintf (stderr, " -n : Multicast group or unicast IP address\n"); - fprintf (stderr, " -s : IP port\n"); - exit (1); -} - -int -main ( - int argc, - char *argv[] - ) -{ - pgm_error_t* err = NULL; - -/* pre-initialise PGM messages module to add hook for GLib logging */ - pgm_messages_init(); - log_init (); - g_message ("sim"); - - if (!pgm_init (&err)) { - g_error ("Unable to start PGM engine: %s", (err && err->message) ? err->message : "(null)"); - pgm_error_free (err); - pgm_messages_shutdown(); - return EXIT_FAILURE; - } - -/* parse program arguments */ - const char* binary_name = strrchr (argv[0], '/'); - int c; - while ((c = getopt (argc, argv, "s:n:h")) != -1) - { - switch (c) { - case 'n': g_network = optarg; break; - case 's': g_port = atoi (optarg); break; - - case 'h': - case '?': - pgm_messages_shutdown(); - usage (binary_name); - } - } - - g_loop = g_main_loop_new (NULL, FALSE); - -/* setup signal handlers */ - signal (SIGSEGV, on_sigsegv); - signal (SIGHUP, SIG_IGN); - pgm_signal_install (SIGINT, on_signal, g_loop); - pgm_signal_install (SIGTERM, on_signal, g_loop); - -/* delayed startup */ - g_message ("scheduling startup."); - g_timeout_add (0, (GSourceFunc)on_startup, NULL); - -/* dispatch loop */ - g_message ("entering main event loop ... "); - g_main_loop_run (g_loop); - - g_message ("event loop terminated, cleaning up."); - -/* cleanup */ - g_main_loop_unref(g_loop); - g_loop = NULL; - - if (g_sessions) { - g_message ("destroying sessions."); - while (g_sessions_list) { - destroy_session (g_sessions_list->data); - g_sessions_list = g_list_delete_link (g_sessions_list, g_sessions_list); - } - g_hash_table_unref (g_sessions); - g_sessions = NULL; - } - - if (g_stdin_channel) { - puts ("unbinding stdin."); - g_io_channel_unref (g_stdin_channel); - g_stdin_channel = NULL; - } - - g_message ("PGM engine shutdown."); - pgm_shutdown(); - g_message ("finished."); - pgm_messages_shutdown(); - return EXIT_SUCCESS; -} - -static -void -destroy_session ( - struct sim_session* sess - ) -{ - printf ("destroying transport \"%s\"\n", sess->name); - pgm_transport_destroy (sess->transport, TRUE); - sess->transport = NULL; - g_free (sess->name); - sess->name = NULL; - g_free (sess); -} - -static -void -on_signal ( - int signum, - gpointer user_data - ) -{ - GMainLoop* loop = (GMainLoop*)user_data; - g_message ("on_signal (signum:%d user-data:%p)", signum, user_data); - g_main_loop_quit (loop); -} - -static -gboolean -on_startup ( - G_GNUC_UNUSED gpointer data - ) -{ - g_message ("startup."); - - g_sessions = g_hash_table_new (g_str_hash, g_str_equal); - -/* add stdin to event manager */ - g_stdin_channel = g_io_channel_unix_new (fileno(stdin)); - printf ("binding stdin with encoding %s.\n", g_io_channel_get_encoding(g_stdin_channel)); - - g_io_add_watch (g_stdin_channel, G_IO_IN | G_IO_PRI, on_stdin_data, NULL); - -/* period timer to indicate some form of life */ -// TODO: Gnome 2.14: replace with g_timeout_add_seconds() - g_timeout_add(10 * 1000, (GSourceFunc)on_mark, NULL); - - puts ("READY"); - fflush (stdout); - return FALSE; -} - -static -bool -fake_pgm_transport_create ( - pgm_transport_t** transport, - struct pgm_transport_info_t* tinfo, - G_GNUC_UNUSED pgm_error_t** error - ) -{ - pgm_transport_t* new_transport; - - g_return_val_if_fail (NULL != transport, FALSE); - g_return_val_if_fail (NULL != tinfo, FALSE); - if (tinfo->ti_sport) g_return_val_if_fail (tinfo->ti_sport != tinfo->ti_dport, FALSE); - if (tinfo->ti_udp_encap_ucast_port) - g_return_val_if_fail (tinfo->ti_udp_encap_mcast_port, FALSE); - else if (tinfo->ti_udp_encap_mcast_port) - g_return_val_if_fail (tinfo->ti_udp_encap_ucast_port, FALSE); - g_return_val_if_fail (tinfo->ti_recv_addrs_len > 0, FALSE); - g_return_val_if_fail (tinfo->ti_recv_addrs_len <= IP_MAX_MEMBERSHIPS, FALSE); - g_return_val_if_fail (NULL != tinfo->ti_recv_addrs, FALSE); - g_return_val_if_fail (1 == tinfo->ti_send_addrs_len, FALSE); - g_return_val_if_fail (NULL != tinfo->ti_send_addrs, FALSE); - for (unsigned i = 0; i < tinfo->ti_recv_addrs_len; i++) - { - g_return_val_if_fail (tinfo->ti_recv_addrs[i].gsr_group.ss_family == tinfo->ti_recv_addrs[0].gsr_group.ss_family, -FALSE); - g_return_val_if_fail (tinfo->ti_recv_addrs[i].gsr_group.ss_family == tinfo->ti_recv_addrs[i].gsr_source.ss_family, -FALSE); - } - g_return_val_if_fail (tinfo->ti_send_addrs[0].gsr_group.ss_family == tinfo->ti_send_addrs[0].gsr_source.ss_family, -FALSE); - -/* create transport object */ - new_transport = g_new0 (pgm_transport_t, 1); - -/* transport defaults */ - new_transport->can_send_data = TRUE; - new_transport->can_send_nak = FALSE; - new_transport->can_recv_data = TRUE; - - memcpy (&new_transport->tsi.gsi, &tinfo->ti_gsi, sizeof(pgm_gsi_t)); - new_transport->dport = g_htons (tinfo->ti_dport); - if (tinfo->ti_sport) { - new_transport->tsi.sport = tinfo->ti_sport; - } else { - do { - new_transport->tsi.sport = g_htons (g_random_int_range (0, UINT16_MAX)); - } while (new_transport->tsi.sport == new_transport->dport); - } - -/* network data ports */ - new_transport->udp_encap_ucast_port = tinfo->ti_udp_encap_ucast_port; - new_transport->udp_encap_mcast_port = tinfo->ti_udp_encap_mcast_port; - -/* copy network parameters */ - memcpy (&new_transport->send_gsr, &tinfo->ti_send_addrs[0], sizeof(struct group_source_req)); - for (unsigned i = 0; i < tinfo->ti_recv_addrs_len; i++) - { - memcpy (&new_transport->recv_gsr[i], &tinfo->ti_recv_addrs[i], sizeof(struct group_source_req)); - ((struct sockaddr_in*)&new_transport->recv_gsr[i].gsr_group)->sin_port = g_htons (new_transport->udp_encap_mcast_port); - } - new_transport->recv_gsr_len = tinfo->ti_recv_addrs_len; - -/* open sockets to implement PGM */ - int socket_type, protocol; - if (new_transport->udp_encap_ucast_port) { - puts ("opening UDP encapsulated sockets."); - socket_type = SOCK_DGRAM; - protocol = IPPROTO_UDP; - } else { - puts ("opening raw sockets."); - socket_type = SOCK_RAW; - protocol = IPPROTO_PGM; - } - - if ((new_transport->recv_sock = socket (new_transport->recv_gsr[0].gsr_group.ss_family, - socket_type, - protocol)) < 0) - { - if (errno == EPERM && 0 != getuid()) { - g_critical ("PGM protocol requires this program to run as superuser."); - } - goto err_destroy; - } - - if ((new_transport->send_sock = socket (new_transport->send_gsr.gsr_group.ss_family, - socket_type, - protocol)) < 0) - { - goto err_destroy; - } - - if ((new_transport->send_with_router_alert_sock = socket (new_transport->send_gsr.gsr_group.ss_family, - socket_type, - protocol)) < 0) - { - goto err_destroy; - } - - *transport = new_transport; - return TRUE; - -err_destroy: - if (new_transport->recv_sock) { - close(new_transport->recv_sock); - new_transport->recv_sock = 0; - } - if (new_transport->send_sock) { - close(new_transport->send_sock); - new_transport->send_sock = 0; - } - if (new_transport->send_with_router_alert_sock) { - close(new_transport->send_with_router_alert_sock); - new_transport->send_with_router_alert_sock = 0; - } - - g_free (new_transport); - new_transport = NULL; - return FALSE; -} - -static -gboolean -on_io_data ( - GIOChannel* source, - G_GNUC_UNUSED GIOCondition condition, - gpointer data - ) -{ - pgm_transport_t* transport = data; - - struct pgm_sk_buff_t* skb = pgm_alloc_skb (transport->max_tpdu); - int fd = g_io_channel_unix_get_fd(source); - struct sockaddr_storage src_addr; - socklen_t src_addr_len = sizeof(src_addr); - skb->len = recvfrom(fd, skb->head, transport->max_tpdu, MSG_DONTWAIT, (struct sockaddr*)&src_addr, &src_addr_len); - - printf ("%i bytes received from %s.\n", skb->len, inet_ntoa(((struct sockaddr_in*)&src_addr)->sin_addr)); - - monitor_packet (skb->data, skb->len); - fflush (stdout); - -/* parse packet to maintain peer database */ - if (transport->udp_encap_ucast_port) { - if (!pgm_parse_udp_encap (skb, NULL)) - goto out; - } else { - struct sockaddr_storage addr; - if (!pgm_parse_raw (skb, (struct sockaddr*)&addr, NULL)) - goto out; - } - - if (pgm_is_upstream (skb->pgm_header->pgm_type) || - pgm_is_peer (skb->pgm_header->pgm_type)) - goto out; /* ignore */ - -/* downstream = source to receivers */ - if (!pgm_is_downstream (skb->pgm_header->pgm_type)) - goto out; - -/* pgm packet DPORT contains our transport DPORT */ - if (skb->pgm_header->pgm_dport != transport->dport) - goto out; - -/* search for TSI peer context or create a new one */ - pgm_peer_t* sender = pgm_hashtable_lookup (transport->peers_hashtable, &skb->tsi); - if (sender == NULL) - { - printf ("new peer, tsi %s, local nla %s\n", - pgm_tsi_print (&skb->tsi), - inet_ntoa(((struct sockaddr_in*)&src_addr)->sin_addr)); - - pgm_peer_t* peer = g_new0 (pgm_peer_t, 1); - peer->transport = transport; - memcpy (&peer->tsi, &skb->tsi, sizeof(pgm_tsi_t)); - ((struct sockaddr_in*)&peer->nla)->sin_addr.s_addr = INADDR_ANY; - memcpy (&peer->local_nla, &src_addr, src_addr_len); - - pgm_hashtable_insert (transport->peers_hashtable, &peer->tsi, peer); - sender = peer; - } - -/* handle SPMs for advertised NLA */ - if (skb->pgm_header->pgm_type == PGM_SPM) - { - char *pgm_data = (char*)(skb->pgm_header + 1); - struct pgm_spm* spm = (struct pgm_spm*)pgm_data; - guint32 spm_sqn = g_ntohl (spm->spm_sqn); - - if ( pgm_uint32_gte (spm_sqn, sender->spm_sqn) - || ( ((struct sockaddr*)&sender->nla)->sa_family == 0 ) ) - { - pgm_nla_to_sockaddr (&spm->spm_nla_afi, (struct sockaddr*)&sender->nla); - sender->spm_sqn = spm_sqn; - } - } - -out: - return TRUE; -} - -static -bool -fake_pgm_transport_bind ( - pgm_transport_t* transport, - G_GNUC_UNUSED pgm_error_t** error - ) -{ - g_return_val_if_fail (NULL != transport, FALSE); - g_return_val_if_fail (!transport->is_bound, FALSE); - -/* create peer list */ - transport->peers_hashtable = pgm_hashtable_new (pgm_tsi_hash, pgm_tsi_equal); - -/* bind udp unicast sockets to interfaces, note multicast on a bound interface is - * fruity on some platforms so callee should specify any interface. - * - * after binding default interfaces (0.0.0.0) are resolved - */ - struct sockaddr_storage recv_addr; - memset (&recv_addr, 0, sizeof(recv_addr)); - ((struct sockaddr*)&recv_addr)->sa_family = AF_INET; - ((struct sockaddr_in*)&recv_addr)->sin_port = transport->udp_encap_ucast_port; - ((struct sockaddr_in*)&recv_addr)->sin_addr.s_addr = INADDR_ANY; - - int retval = bind (transport->recv_sock, - (struct sockaddr*)&recv_addr, - pgm_sockaddr_len((struct sockaddr*)&recv_addr)); - if (retval < 0) { - goto out; - } - - struct sockaddr_storage send_addr, send_with_router_alert_addr; - memset (&send_addr, 0, sizeof(send_addr)); - if (!pgm_if_indextoaddr (transport->send_gsr.gsr_interface, - transport->send_gsr.gsr_group.ss_family, - pgm_sockaddr_scope_id((struct sockaddr*)&transport->send_gsr.gsr_group), - (struct sockaddr*)&send_addr, - NULL)) - { - goto out; - } - memcpy (&send_with_router_alert_addr, &send_addr, pgm_sockaddr_len((struct sockaddr*)&send_addr)); - retval = bind (transport->send_sock, - (struct sockaddr*)&send_addr, - pgm_sockaddr_len((struct sockaddr*)&send_addr)); - if (retval < 0) - goto out; - -/* resolve bound address if 0.0.0.0 */ - if (((struct sockaddr_in*)&send_addr)->sin_addr.s_addr == INADDR_ANY) - { - if (!pgm_if_getnodeaddr (AF_INET, (struct sockaddr*)&send_addr, sizeof(send_addr), NULL)) - goto out; - } - - retval = bind (transport->send_with_router_alert_sock, - (struct sockaddr*)&send_with_router_alert_addr, - pgm_sockaddr_len((struct sockaddr*)&send_with_router_alert_addr)); - if (retval < 0) - goto out; - - memcpy (&transport->send_addr, &send_addr, pgm_sockaddr_len((struct sockaddr*)&send_addr)); - -/* receiving groups (multiple) */ - for (unsigned i = 0; i < transport->recv_gsr_len; i++) - { - struct group_source_req* p = &transport->recv_gsr[i]; - int optname = (pgm_sockaddr_cmp ((struct sockaddr*)&p->gsr_group, (struct sockaddr*)&p->gsr_source) == 0) - ? MCAST_JOIN_GROUP : MCAST_JOIN_SOURCE_GROUP; - socklen_t plen = MCAST_JOIN_GROUP == optname ? sizeof(struct group_req) : sizeof(struct group_source_req); - retval = setsockopt(transport->recv_sock, SOL_IP, optname, p, plen); - if (retval < 0) - goto out; - } - -/* send group (singular) */ - retval = pgm_sockaddr_multicast_if (transport->send_sock, (struct sockaddr*)&transport->send_addr, transport->send_gsr.gsr_interface); - if (retval < 0) - goto out; - - retval = pgm_sockaddr_multicast_if (transport->send_with_router_alert_sock, (struct sockaddr*)&transport->send_addr, transport->send_gsr.gsr_interface); - if (retval < 0) - goto out; - -/* multicast loopback */ - retval = pgm_sockaddr_multicast_loop (transport->recv_sock, transport->recv_gsr[0].gsr_group.ss_family, FALSE); - if (retval < 0) - goto out; - retval = pgm_sockaddr_multicast_loop (transport->send_sock, transport->send_gsr.gsr_group.ss_family, FALSE); - if (retval < 0) - goto out; - retval = pgm_sockaddr_multicast_loop (transport->send_with_router_alert_sock, transport->send_gsr.gsr_group.ss_family, FALSE); - if (retval < 0) - goto out; - -/* multicast ttl: many crappy network devices go CPU ape with TTL=1, 16 is a popular alternative */ - retval = pgm_sockaddr_multicast_hops (transport->recv_sock, transport->recv_gsr[0].gsr_group.ss_family, transport->hops); - if (retval < 0) - goto out; - retval = pgm_sockaddr_multicast_hops (transport->send_sock, transport->send_gsr.gsr_group.ss_family, transport->hops); - if (retval < 0) - goto out; - retval = pgm_sockaddr_multicast_hops (transport->send_with_router_alert_sock, transport->send_gsr.gsr_group.ss_family, transport->hops); - if (retval < 0) - goto out; - -/* set Expedited Forwarding PHB for network elements, no ECN. - * - * codepoint 101110 (RFC 3246) - */ - int dscp = 0x2e << 2; - retval = pgm_sockaddr_tos (transport->send_sock, transport->send_gsr.gsr_group.ss_family, dscp); - if (retval < 0) - goto out; - retval = pgm_sockaddr_tos (transport->send_with_router_alert_sock, transport->send_gsr.gsr_group.ss_family, dscp); - if (retval < 0) - goto out; - -/* cleanup */ - transport->is_bound = TRUE; - return TRUE; - -out: - return FALSE; -} - -static -bool -fake_pgm_transport_destroy ( - pgm_transport_t* transport, - G_GNUC_UNUSED bool flush - ) -{ - g_return_val_if_fail (transport != NULL, FALSE); - - if (transport->recv_sock) { - puts ("closing receive socket."); - close(transport->recv_sock); - transport->recv_sock = 0; - } - if (transport->send_sock) { - puts ("closing send socket."); - close(transport->send_sock); - transport->send_sock = 0; - } - if (transport->send_with_router_alert_sock) { - puts ("closing send with router alert socket."); - close(transport->send_with_router_alert_sock); - transport->send_with_router_alert_sock = 0; - } - g_free (transport); - return TRUE; -} - -static -void -session_create ( - char* name, - gboolean is_fake - ) -{ - struct pgm_transport_info_t hints = { - .ti_family = AF_INET - }, *res = NULL; - pgm_error_t* err = NULL; - gboolean status; - -/* check for duplicate */ - struct sim_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess != NULL) { - puts ("FAILED: duplicate session"); - return; - } - -/* create new and fill in bits */ - sess = g_new0(struct sim_session, 1); - sess->name = g_memdup (name, strlen(name)+1); - - if (!pgm_if_get_transport_info (g_network, &hints, &res, &err)) { - printf ("FAILED: pgm_if_get_transport_info(): %s\n", (err && err->message) ? err->message : "(null)"); - pgm_error_free (err); - goto err_free; - } - - if (!pgm_gsi_create_from_hostname (&res->ti_gsi, &err)) { - printf ("FAILED: pgm_gsi_create_from_hostname(): %s\n", (err && err->message) ? err->message : "(null)"); - pgm_error_free (err); - pgm_if_free_transport_info (res); - goto err_free; - } - - res->ti_dport = g_port; - res->ti_sport = 0; - if (is_fake) { - sess->is_transport_fake = TRUE; - status = fake_pgm_transport_create (&sess->transport, res, &err); - } else - status = pgm_transport_create (&sess->transport, res, &err); - if (!status) { - printf ("FAILED: pgm_transport_create(): %s\n", (err && err->message) ? err->message : "(null)"); - pgm_error_free (err); - pgm_if_free_transport_info (res); - goto err_free; - } - - pgm_if_free_transport_info (res); - -/* success */ - g_hash_table_insert (g_sessions, sess->name, sess); - g_sessions_list = g_list_prepend (g_sessions_list, sess); - printf ("created new session \"%s\"\n", sess->name); - puts ("READY"); - return; - -err_free: - g_free(sess->name); - g_free(sess); -} - -static -void -session_set_fec ( - char* name, - guint default_n, - guint default_k - ) -{ -/* check that session exists */ - struct sim_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - pgm_transport_set_fec (sess->transport, FALSE /* pro-active */, TRUE /* on-demand */, TRUE /* varpkt-len */, default_n, default_k); - puts ("READY"); -} - -static -void -session_bind ( - char* name - ) -{ -/* check that session exists */ - struct sim_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - pgm_transport_set_nonblocking (sess->transport, TRUE); - pgm_sockaddr_nonblocking (sess->transport->send_sock, FALSE); - pgm_transport_set_max_tpdu (sess->transport, g_max_tpdu); - pgm_transport_set_txw_sqns (sess->transport, g_sqns); - pgm_transport_set_rxw_sqns (sess->transport, g_sqns); - pgm_transport_set_hops (sess->transport, 16); - pgm_transport_set_ambient_spm (sess->transport, pgm_secs(30)); - guint spm_heartbeat[] = { pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(1300), pgm_secs(7), pgm_secs(16), pgm_secs(25), pgm_secs(30) }; - pgm_transport_set_heartbeat_spm (sess->transport, spm_heartbeat, G_N_ELEMENTS(spm_heartbeat)); - pgm_transport_set_peer_expiry (sess->transport, pgm_secs(300)); - pgm_transport_set_spmr_expiry (sess->transport, pgm_msecs(250)); - pgm_transport_set_nak_bo_ivl (sess->transport, pgm_msecs(50)); - pgm_transport_set_nak_rpt_ivl (sess->transport, pgm_secs(2)); - pgm_transport_set_nak_rdata_ivl (sess->transport, pgm_secs(2)); - pgm_transport_set_nak_data_retries (sess->transport, 50); - pgm_transport_set_nak_ncf_retries (sess->transport, 50); - - pgm_error_t* err = NULL; - gboolean status; - if (sess->is_transport_fake) - status = fake_pgm_transport_bind (sess->transport, &err); - else - status = pgm_transport_bind (sess->transport, &err); - if (!status) { - printf ("FAILED: pgm_transport_bind(): %s\n", err->message); - pgm_error_free (err); - return; - } - - if (sess->is_transport_fake) - { -/* add receive socket(s) to event manager */ - sess->recv_channel = g_io_channel_unix_new (sess->transport->recv_sock); - - GSource *source; - source = g_io_create_watch (sess->recv_channel, G_IO_IN); - g_source_set_callback (source, (GSourceFunc)on_io_data, sess->transport, NULL); - g_source_attach (source, NULL); - g_source_unref (source); - } - else - { - pgm_async_create (&sess->async, sess->transport, 0); - pgm_async_add_watch (sess->async, on_data, sess); - } - - puts ("READY"); -} - -static inline -gssize -pgm_sendto ( - pgm_transport_t* transport, - gboolean rl, - gboolean ra, - const void* buf, - gsize len, - const struct sockaddr* to, - socklen_t tolen - ) -{ - int sock = ra ? transport->send_with_router_alert_sock : transport->send_sock; - pgm_mutex_lock (&transport->send_mutex); - ssize_t sent = sendto (sock, buf, len, 0, to, tolen); - pgm_mutex_unlock (&transport->send_mutex); - return sent > 0 ? (gssize)len : (gssize)sent; -} - -static -int -pgm_reset_heartbeat_spm (pgm_transport_t* transport) -{ - int retval = 0; - - pgm_mutex_lock (&transport->timer_mutex); - -/* re-set spm timer */ - transport->spm_heartbeat_state = 1; - transport->next_heartbeat_spm = pgm_time_update_now() + transport->spm_heartbeat_interval[transport->spm_heartbeat_state++]; - -/* prod timer thread if sleeping */ - if (pgm_time_after( transport->next_poll, transport->next_heartbeat_spm )) - transport->next_poll = transport->next_heartbeat_spm; - - pgm_mutex_unlock (&transport->timer_mutex); - - return retval; -} - -static inline -int -brokn_send_apdu_unlocked ( - pgm_transport_t* transport, - const gchar* buf, - gsize count, - gsize* bytes_written - ) -{ - guint32 opt_sqn = pgm_txw_next_lead(transport->window); - guint packets = 0; - guint bytes_sent = 0; - guint data_bytes_sent = 0; - - pgm_mutex_lock (&transport->source_mutex); - - do { -/* retrieve packet storage from transmit window */ - int header_length = sizeof(struct pgm_header) + sizeof(struct pgm_data) + - sizeof(struct pgm_opt_length) + /* includes header */ - sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fragment); - int tsdu_length = MIN(transport->max_tpdu - transport->iphdr_len - header_length, count - data_bytes_sent); - int tpdu_length = header_length + tsdu_length; - - struct pgm_sk_buff_t* skb = pgm_alloc_skb (tsdu_length); - pgm_skb_put (skb, tpdu_length); - - skb->pgm_header = (struct pgm_header*)skb->data; - memcpy (skb->pgm_header->pgm_gsi, &transport->tsi.gsi, sizeof(pgm_gsi_t)); - skb->pgm_header->pgm_sport = transport->tsi.sport; - skb->pgm_header->pgm_dport = transport->dport; - skb->pgm_header->pgm_type = PGM_ODATA; - skb->pgm_header->pgm_options = PGM_OPT_PRESENT; - skb->pgm_header->pgm_tsdu_length = g_htons (tsdu_length); - -/* ODATA */ - skb->pgm_data = (struct pgm_data*)(skb->pgm_header + 1); - skb->pgm_data->data_sqn = g_htonl (pgm_txw_next_lead(transport->window)); - skb->pgm_data->data_trail = g_htonl (pgm_txw_trail(transport->window)); - -/* OPT_LENGTH */ - struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(skb->pgm_data + 1); - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = g_htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fragment) ); -/* OPT_FRAGMENT */ - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fragment); - skb->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); - skb->pgm_opt_fragment->opt_reserved = 0; - skb->pgm_opt_fragment->opt_sqn = g_htonl (opt_sqn); - skb->pgm_opt_fragment->opt_frag_off = g_htonl (data_bytes_sent); - skb->pgm_opt_fragment->opt_frag_len = g_htonl (count); - -/* TODO: the assembly checksum & copy routine is faster than memcpy & pgm_cksum on >= opteron hardware */ - skb->pgm_header->pgm_checksum = 0; - - int pgm_header_len = (char*)(skb->pgm_opt_fragment + 1) - (char*)skb->pgm_header; - guint32 unfolded_header = pgm_csum_partial ((const void*)skb->pgm_header, pgm_header_len, 0); - guint32 unfolded_odata = pgm_csum_partial_copy ((const void*)(buf + data_bytes_sent), (void*)(skb->pgm_opt_fragment + 1), tsdu_length, 0); - skb->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, unfolded_odata, pgm_header_len)); - -/* add to transmit window */ - pgm_spinlock_lock (&transport->txw_spinlock); - pgm_txw_add (transport->window, skb); - pgm_spinlock_unlock (&transport->txw_spinlock); - -/* do not send send packet */ - if (packets != 1) - pgm_sendto (transport, - TRUE, - FALSE, - skb->data, - tpdu_length, - (struct sockaddr*)&transport->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&transport->send_gsr.gsr_group)); - -/* save unfolded odata for retransmissions */ - *(guint32*)&skb->cb = unfolded_odata; - - packets++; - bytes_sent += tpdu_length + transport->iphdr_len; - data_bytes_sent += tsdu_length; - - } while (data_bytes_sent < count); - - if (data_bytes_sent > 0 && bytes_written) - *bytes_written = data_bytes_sent; - -/* release txw lock here in order to allow spms to lock mutex */ - pgm_mutex_unlock (&transport->source_mutex); - pgm_reset_heartbeat_spm (transport); - return PGM_IO_STATUS_NORMAL; -} - -static -int -brokn_send ( - pgm_transport_t* transport, - const gchar* data, - gsize len, - gsize* bytes_written - ) -{ - if ( len <= ( transport->max_tpdu - ( sizeof(struct pgm_header) + - sizeof(struct pgm_data) ) ) ) - { - puts ("FAILED: cannot send brokn single TPDU length APDU"); - return PGM_IO_STATUS_ERROR; - } - - return brokn_send_apdu_unlocked (transport, data, len, bytes_written); -} - -static -void -session_send ( - char* name, - char* string, - gboolean is_brokn /* send broken apdu */ - ) -{ -/* check that session exists */ - struct sim_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - -/* send message */ - int status; - gsize stringlen = strlen(string) + 1; - int n_fds = 1; - struct pollfd fds[ n_fds ]; - struct timeval tv; - int timeout; -again: - if (is_brokn) - status = brokn_send (sess->transport, string, stringlen, NULL); - else - status = pgm_send (sess->transport, string, stringlen, NULL); - switch (status) { - case PGM_IO_STATUS_NORMAL: - puts ("READY"); - break; - case PGM_IO_STATUS_TIMER_PENDING: - pgm_transport_get_timer_pending (sess->transport, &tv); - goto block; - case PGM_IO_STATUS_RATE_LIMITED: - pgm_transport_get_rate_remaining (sess->transport, &tv); -/* fall through */ - case PGM_IO_STATUS_WOULD_BLOCK: -block: - timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); - memset (fds, 0, sizeof(fds)); - pgm_transport_poll_info (sess->transport, fds, &n_fds, POLLOUT); - poll (fds, n_fds, timeout /* ms */); - goto again; - default: - puts ("FAILED: pgm_send()"); - break; - } -} - -static -void -session_destroy ( - char* name - ) -{ -/* check that session exists */ - struct sim_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - -/* remove from hash table */ - g_hash_table_remove (g_sessions, name); - -/* close down receive side first to stop new data incoming */ - if (sess->recv_channel) { - puts ("closing receive channel."); - - GError *err = NULL; - g_io_channel_shutdown (sess->recv_channel, TRUE, &err); - - if (err) { - g_warning ("i/o shutdown error %i %s", err->code, err->message); - } - -/* TODO: flush GLib main loop with context specific to the recv channel */ - - sess->recv_channel = NULL; - } - - if (sess->is_transport_fake) - { - fake_pgm_transport_destroy (sess->transport, TRUE); - } - else - { - pgm_transport_destroy (sess->transport, TRUE); - } - sess->transport = NULL; - g_free (sess->name); - sess->name = NULL; - g_free (sess); - - puts ("READY"); -} - -static -void -net_send_data ( - char* name, - guint8 pgm_type, /* PGM_ODATA or PGM_RDATA */ - guint32 data_sqn, - guint32 txw_trail, - char* string - ) -{ -/* check that session exists */ - struct sim_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - pgm_transport_t* transport = sess->transport; - -/* payload is string including terminating null. */ - int count = strlen(string) + 1; - -/* send */ - int retval = 0; - int tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_data) + count; - - gchar buf[ tpdu_length ]; - - struct pgm_header *header = (struct pgm_header*)buf; - struct pgm_data *data = (struct pgm_data*)(header + 1); - memcpy (header->pgm_gsi, &transport->tsi.gsi, sizeof(pgm_gsi_t)); - header->pgm_sport = transport->tsi.sport; - header->pgm_dport = transport->dport; - header->pgm_type = pgm_type; - header->pgm_options = 0; - header->pgm_tsdu_length = g_htons (count); - -/* O/RDATA */ - data->data_sqn = g_htonl (data_sqn); - data->data_trail = g_htonl (txw_trail); - - memcpy (data + 1, string, count); - - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); - - pgm_mutex_lock (&transport->send_mutex); - retval = sendto (transport->send_sock, - header, - tpdu_length, - 0, /* not expecting a reply */ - (struct sockaddr*)&transport->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&transport->send_gsr.gsr_group)); - pgm_mutex_unlock (&transport->send_mutex); - - puts ("READY"); -} - -/* differs to net_send_data in that the string parameters contains every payload - * for the transmission group. this is required to calculate the correct parity - * as the fake transport does not own a transmission window. - * - * all payloads must be the same length unless variable TSDU support is enabled. - */ -static -void -net_send_parity ( - char* name, - guint8 pgm_type, /* PGM_ODATA or PGM_RDATA */ - guint32 data_sqn, - guint32 txw_trail, - char* string - ) -{ -/* check that session exists */ - struct sim_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - pgm_transport_t* transport = sess->transport; - -/* split string into individual payloads */ - guint16 parity_length = 0; - gchar** src; - src = g_strsplit (string, " ", transport->rs_k); - -/* payload is string including terminating null. */ - parity_length = strlen(*src) + 1; - -/* check length of payload array */ - gboolean is_var_pktlen = FALSE; - guint i; - for (i = 0; src[i]; i++) - { - guint tsdu_length = strlen(src[i]) + 1; - if (tsdu_length != parity_length) { - is_var_pktlen = TRUE; - - if (tsdu_length > parity_length) - parity_length = tsdu_length; - } - } - - if ( i != transport->rs_k ) { - printf ("FAILED: payload array length %u, whilst rs_k is %u.\n", i, transport->rs_k); - return; - } - -/* add padding and append TSDU lengths */ - if (is_var_pktlen) - { - for (i = 0; src[i]; i++) - { - guint tsdu_length = strlen(src[i]) + 1; - gchar* new_string = g_new0 (gchar, parity_length + 2); - strncpy (new_string, src[i], parity_length); - *(guint16*)(new_string + parity_length) = tsdu_length; - g_free (src[i]); - src[i] = new_string; - } - parity_length += 2; - } - -/* calculate FEC block offset */ - guint32 tg_sqn_mask = 0xffffffff << transport->tg_sqn_shift; - guint rs_h = data_sqn & ~tg_sqn_mask; - -/* send */ - int retval = 0; - int tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_data) + parity_length; - - gchar buf[ tpdu_length ]; - - struct pgm_header *header = (struct pgm_header*)buf; - struct pgm_data *data = (struct pgm_data*)(header + 1); - memcpy (header->pgm_gsi, &transport->tsi.gsi, sizeof(pgm_gsi_t)); - header->pgm_sport = transport->tsi.sport; - header->pgm_dport = transport->dport; - header->pgm_type = pgm_type; - header->pgm_options = is_var_pktlen ? (PGM_OPT_PARITY | PGM_OPT_VAR_PKTLEN) : PGM_OPT_PARITY; - header->pgm_tsdu_length = g_htons (parity_length); - -/* O/RDATA */ - data->data_sqn = g_htonl (data_sqn); - data->data_trail = g_htonl (txw_trail); - - memset (data + 1, 0, parity_length); - pgm_rs_t rs; - pgm_rs_create (&rs, transport->rs_n, transport->rs_k); - pgm_rs_encode (&rs, (const pgm_gf8_t**)src, transport->rs_k + rs_h, (pgm_gf8_t*)(data + 1), parity_length); - pgm_rs_destroy (&rs); - - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); - - pgm_mutex_lock (&transport->send_mutex); - retval = sendto (transport->send_sock, - header, - tpdu_length, - 0, /* not expecting a reply */ - (struct sockaddr*)&transport->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&transport->send_gsr.gsr_group)); - pgm_mutex_unlock (&transport->send_mutex); - - g_strfreev (src); - src = NULL; - - puts ("READY"); -} - -static -void -net_send_spm ( - char* name, - guint32 spm_sqn, - guint32 txw_trail, - guint32 txw_lead, - gboolean proactive_parity, - gboolean ondemand_parity, - guint k - ) -{ -/* check that session exists */ - struct sim_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - pgm_transport_t* transport = sess->transport; - -/* send */ - int retval = 0; - int tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_spm); - - if (proactive_parity || ondemand_parity) { - tpdu_length += sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_parity_prm); - } - - gchar buf[ tpdu_length ]; - - struct pgm_header *header = (struct pgm_header*)buf; - struct pgm_spm *spm = (struct pgm_spm*)(header + 1); - memcpy (header->pgm_gsi, &transport->tsi.gsi, sizeof(pgm_gsi_t)); - header->pgm_sport = transport->tsi.sport; - header->pgm_dport = transport->dport; - header->pgm_type = PGM_SPM; - header->pgm_options = (proactive_parity || ondemand_parity) ? (PGM_OPT_PRESENT | PGM_OPT_NETWORK) : 0; - header->pgm_tsdu_length = 0; - -/* SPM */ - spm->spm_sqn = g_htonl (spm_sqn); - spm->spm_trail = g_htonl (txw_trail); - spm->spm_lead = g_htonl (txw_lead); - pgm_sockaddr_to_nla ((struct sockaddr*)&transport->send_addr, (char*)&spm->spm_nla_afi); - - if (proactive_parity || ondemand_parity) { - struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(spm + 1); - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = g_htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_parity_prm) ); - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_PARITY_PRM | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_parity_prm); - struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1); - opt_parity_prm->opt_reserved = (proactive_parity ? PGM_PARITY_PRM_PRO : 0) | - (ondemand_parity ? PGM_PARITY_PRM_OND : 0); - opt_parity_prm->parity_prm_tgs = g_htonl (k); - } - - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); - - retval = sendto (transport->send_sock, - header, - tpdu_length, - 0, /* not expecting a reply */ - (struct sockaddr*)&transport->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&transport->send_gsr.gsr_group)); - puts ("READY"); -} - -static -void -net_send_spmr ( - char* name, - pgm_tsi_t* tsi - ) -{ -/* check that session exists */ - struct sim_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - - pgm_transport_t* transport = sess->transport; - -/* check that the peer exists */ - pgm_peer_t* peer = pgm_hashtable_lookup (transport->peers_hashtable, tsi); - struct sockaddr_storage peer_nla; - pgm_gsi_t* peer_gsi; - guint16 peer_sport; - - if (peer == NULL) { -/* ourself */ - if (pgm_tsi_equal (tsi, &transport->tsi)) - { - peer_gsi = &transport->tsi.gsi; - peer_sport = transport->tsi.sport; - } - else - { - printf ("FAILED: peer \"%s\" not found\n", pgm_tsi_print (tsi)); - return; - } - } - else - { - memcpy (&peer_nla, &peer->local_nla, sizeof(struct sockaddr_storage)); - peer_gsi = &peer->tsi.gsi; - peer_sport = peer->tsi.sport; - } - -/* send */ - int retval = 0; - int tpdu_length = sizeof(struct pgm_header); - gchar buf[ tpdu_length ]; - - struct pgm_header *header = (struct pgm_header*)buf; - memcpy (header->pgm_gsi, peer_gsi, sizeof(pgm_gsi_t)); - header->pgm_sport = transport->dport; - header->pgm_dport = peer_sport; - header->pgm_type = PGM_SPMR; - header->pgm_options = 0; - header->pgm_tsdu_length = 0; - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); - - pgm_mutex_lock (&transport->send_mutex); -/* TTL 1 */ - pgm_sockaddr_multicast_hops (transport->send_sock, transport->send_gsr.gsr_group.ss_family, 1); - retval = sendto (transport->send_sock, - header, - tpdu_length, - 0, /* not expecting a reply */ - (struct sockaddr*)&transport->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&transport->send_gsr.gsr_group)); -/* default TTL */ - pgm_sockaddr_multicast_hops (transport->send_sock, transport->send_gsr.gsr_group.ss_family, transport->hops); - - if (!pgm_tsi_equal (tsi, &transport->tsi)) - { - retval = sendto (transport->send_sock, - header, - tpdu_length, - 0, /* not expecting a reply */ - (struct sockaddr*)&peer_nla, - pgm_sockaddr_len((struct sockaddr*)&peer_nla)); - } - - pgm_mutex_unlock (&transport->send_mutex); - - puts ("READY"); -} - -/* Send a NAK on a valid transport. A fake transport would need to specify the senders NLA, - * we use the peer list to bypass extracting it from the monitor output. - */ - -static -void -net_send_ncf ( - char* name, - pgm_tsi_t* tsi, - struct pgm_sqn_list_t* sqn_list /* list of sequence numbers */ - ) -{ -/* check that session exists */ - struct sim_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - -/* check that the peer exists */ - pgm_transport_t* transport = sess->transport; - pgm_peer_t* peer = pgm_hashtable_lookup (transport->peers_hashtable, tsi); - if (peer == NULL) { - printf ("FAILED: peer \"%s\" not found\n", pgm_tsi_print (tsi)); - return; - } - -/* check for valid nla */ - if (((struct sockaddr*)&peer->nla)->sa_family == 0 ) { - puts ("FAILED: peer NLA unknown, cannot send NCF."); - return; - } - -/* send */ - int retval = 0; - int tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); - - if (sqn_list->len > 1) { - tpdu_length += sizeof(struct pgm_opt_length) + /* includes header */ - sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + - ( (sqn_list->len-1) * sizeof(guint32) ); - } - - gchar buf[ tpdu_length ]; - - struct pgm_header *header = (struct pgm_header*)buf; - struct pgm_nak *ncf = (struct pgm_nak*)(header + 1); - memcpy (header->pgm_gsi, &transport->tsi.gsi, sizeof(pgm_gsi_t)); - - struct sockaddr_storage peer_nla; - memcpy (&peer_nla, &peer->nla, sizeof(struct sockaddr_storage)); - -/* dport & sport swap over for a nak */ - header->pgm_sport = transport->tsi.sport; - header->pgm_dport = transport->dport; - header->pgm_type = PGM_NCF; - header->pgm_options = (sqn_list->len > 1) ? (PGM_OPT_PRESENT | PGM_OPT_NETWORK) : 0; - header->pgm_tsdu_length = 0; - -/* NCF */ - ncf->nak_sqn = g_htonl (sqn_list->sqn[0]); - -/* source nla */ - pgm_sockaddr_to_nla ((struct sockaddr*)&peer_nla, (char*)&ncf->nak_src_nla_afi); - -/* group nla */ - pgm_sockaddr_to_nla ((struct sockaddr*)&transport->recv_gsr[0].gsr_group, (char*)&ncf->nak_grp_nla_afi); - -/* OPT_NAK_LIST */ - if (sqn_list->len > 1) - { - struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(ncf + 1); - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = g_htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_nak_list) + - ( (sqn_list->len-1) * sizeof(guint32) ) ); - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) - + ( (sqn_list->len-1) * sizeof(guint32) ); - struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); - opt_nak_list->opt_reserved = 0; - for (guint i = 1; i < sqn_list->len; i++) { - opt_nak_list->opt_sqn[i-1] = g_htonl (sqn_list->sqn[i]); - } - } - - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); - - retval = sendto (transport->send_with_router_alert_sock, - header, - tpdu_length, - 0, /* not expecting a reply */ - (struct sockaddr*)&transport->send_gsr.gsr_group, - pgm_sockaddr_len((struct sockaddr*)&transport->send_gsr.gsr_group)); - - puts ("READY"); -} - -static -void -net_send_nak ( - char* name, - pgm_tsi_t* tsi, - struct pgm_sqn_list_t* sqn_list, /* list of sequence numbers */ - gboolean is_parity /* TRUE = parity, FALSE = selective */ - ) -{ -/* check that session exists */ - struct sim_session* sess = g_hash_table_lookup (g_sessions, name); - if (sess == NULL) { - puts ("FAILED: session not found"); - return; - } - -/* check that the peer exists */ - pgm_transport_t* transport = sess->transport; - pgm_peer_t* peer = pgm_hashtable_lookup (transport->peers_hashtable, tsi); - if (peer == NULL) { - printf ("FAILED: peer \"%s\" not found\n", pgm_tsi_print(tsi)); - return; - } - -/* send */ - int retval = 0; - int tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); - - if (sqn_list->len > 1) { - tpdu_length += sizeof(struct pgm_opt_length) + /* includes header */ - sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + - ( (sqn_list->len-1) * sizeof(guint32) ); - } - - gchar buf[ tpdu_length ]; - - struct pgm_header *header = (struct pgm_header*)buf; - struct pgm_nak *nak = (struct pgm_nak*)(header + 1); - memcpy (header->pgm_gsi, &peer->tsi.gsi, sizeof(pgm_gsi_t)); - - guint16 peer_sport = peer->tsi.sport; - struct sockaddr_storage peer_nla; - memcpy (&peer_nla, &peer->nla, sizeof(struct sockaddr_storage)); - -/* dport & sport swap over for a nak */ - header->pgm_sport = transport->dport; - header->pgm_dport = peer_sport; - header->pgm_type = PGM_NAK; - if (is_parity) { - header->pgm_options = (sqn_list->len > 1) ? (PGM_OPT_PRESENT | PGM_OPT_NETWORK | PGM_OPT_PARITY) - : PGM_OPT_PARITY; - } else { - header->pgm_options = (sqn_list->len > 1) ? (PGM_OPT_PRESENT | PGM_OPT_NETWORK) : 0; - } - header->pgm_tsdu_length = 0; - -/* NAK */ - nak->nak_sqn = g_htonl (sqn_list->sqn[0]); - -/* source nla */ - pgm_sockaddr_to_nla ((struct sockaddr*)&peer_nla, (char*)&nak->nak_src_nla_afi); - -/* group nla */ - pgm_sockaddr_to_nla ((struct sockaddr*)&transport->recv_gsr[0].gsr_group, (char*)&nak->nak_grp_nla_afi); - -/* OPT_NAK_LIST */ - if (sqn_list->len > 1) - { - struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(nak + 1); - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = g_htons ( sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_nak_list) + - ( (sqn_list->len-1) * sizeof(guint32) ) ); - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) - + ( (sqn_list->len-1) * sizeof(guint32) ); - struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); - opt_nak_list->opt_reserved = 0; - for (guint i = 1; i < sqn_list->len; i++) { - opt_nak_list->opt_sqn[i-1] = g_htonl (sqn_list->sqn[i]); - } - } - - header->pgm_checksum = 0; - header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); - - retval = sendto (transport->send_with_router_alert_sock, - header, - tpdu_length, - 0, /* not expecting a reply */ - (struct sockaddr*)&peer_nla, - pgm_sockaddr_len((struct sockaddr*)&peer_nla)); - - puts ("READY"); -} - -static -int -on_data ( - gpointer data, - G_GNUC_UNUSED guint len, - G_GNUC_UNUSED gpointer user_data - ) -{ - printf ("DATA: %s\n", (char*)data); - fflush (stdout); - - return 0; -} - -/* process input commands from stdin/fd - */ - -static -gboolean -on_stdin_data ( - GIOChannel* source, - G_GNUC_UNUSED GIOCondition condition, - G_GNUC_UNUSED gpointer data - ) -{ - gchar* str = NULL; - gsize len = 0; - gsize term = 0; - GError* err = NULL; - - g_io_channel_read_line (source, &str, &len, &term, &err); - if (len > 0) { - if (term) str[term] = 0; - -/* quit */ - if (strcmp(str, "quit") == 0) - { - g_main_loop_quit(g_loop); - goto out; - } - - regex_t preg; - regmatch_t pmatch[10]; - const char *re; - -/* endpoint simulator specific: */ - -/* send odata or rdata */ - re = "^net[[:space:]]+send[[:space:]]+([or])data[[:space:]]+" - "([[:alnum:]]+)[[:space:]]+" /* transport */ - "([0-9]+)[[:space:]]+" /* sequence number */ - "([0-9]+)[[:space:]]+" /* txw_trail */ - "([[:alnum:]]+)$"; /* payload */ - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - guint8 pgm_type = *(str + pmatch[1].rm_so) == 'o' ? PGM_ODATA : PGM_RDATA; - - char *name = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); - name[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; - - char* p = str + pmatch[3].rm_so; - guint32 data_sqn = strtoul (p, &p, 10); - - p = str + pmatch[4].rm_so; - guint txw_trail = strtoul (p, &p, 10); - - char *string = g_memdup (str + pmatch[5].rm_so, pmatch[5].rm_eo - pmatch[5].rm_so + 1 ); - string[ pmatch[5].rm_eo - pmatch[5].rm_so ] = 0; - - net_send_data (name, pgm_type, data_sqn, txw_trail, string); - - g_free (name); - g_free (string); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* send parity odata or rdata */ - re = "^net[[:space:]]+send[[:space:]]+parity[[:space:]]+([or])data[[:space:]]+" - "([[:alnum:]]+)[[:space:]]+" /* transport */ - "([0-9]+)[[:space:]]+" /* sequence number */ - "([0-9]+)[[:space:]]+" /* txw_trail */ - "([a-z0-9 ]+)$"; /* payloads */ - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - guint8 pgm_type = *(str + pmatch[1].rm_so) == 'o' ? PGM_ODATA : PGM_RDATA; - - char *name = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); - name[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; - - char* p = str + pmatch[3].rm_so; - guint32 data_sqn = strtoul (p, &p, 10); - - p = str + pmatch[4].rm_so; - guint txw_trail = strtoul (p, &p, 10); - -/* ideally confirm number of payloads matches sess->transport::rs_k ... */ - char *string = g_memdup (str + pmatch[5].rm_so, pmatch[5].rm_eo - pmatch[5].rm_so + 1 ); - string[ pmatch[5].rm_eo - pmatch[5].rm_so ] = 0; - - net_send_parity (name, pgm_type, data_sqn, txw_trail, string); - - g_free (name); - g_free (string); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* send spm */ - re = "^net[[:space:]]+send[[:space:]]+spm[[:space:]]+" - "([[:alnum:]]+)[[:space:]]+" /* transport */ - "([0-9]+)[[:space:]]+" /* spm sequence number */ - "([0-9]+)[[:space:]]+" /* txw_trail */ - "([0-9]+)" /* txw_lead */ - "([[:space:]]+pro-active)?" /* pro-active parity */ - "([[:space:]]+on-demand)?" /* on-demand parity */ - "([[:space:]]+[0-9]+)?$"; /* transmission group size */ - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - char* p = str + pmatch[2].rm_so; - guint32 spm_sqn = strtoul (p, &p, 10); - - p = str + pmatch[3].rm_so; - guint txw_trail = strtoul (p, &p, 10); - - p = str + pmatch[4].rm_so; - guint txw_lead = strtoul (p, &p, 10); - - gboolean proactive_parity = pmatch[5].rm_eo > pmatch[5].rm_so; - gboolean ondemand_parity = pmatch[6].rm_eo > pmatch[6].rm_so; - - p = str + pmatch[7].rm_so; - guint k = (pmatch[7].rm_eo > pmatch[7].rm_so) ? strtoul (p, &p, 10) : 0; - - net_send_spm (name, spm_sqn, txw_trail, txw_lead, proactive_parity, ondemand_parity, k); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* send spmr */ - re = "^net[[:space:]]+send[[:space:]]+spmr[[:space:]]+" - "([[:alnum:]]+)[[:space:]]+" /* transport */ - "([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)$"; /* TSI */ - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - pgm_tsi_t tsi; - char *p = str + pmatch[2].rm_so; - tsi.gsi.identifier[0] = strtol (p, &p, 10); - ++p; - tsi.gsi.identifier[1] = strtol (p, &p, 10); - ++p; - tsi.gsi.identifier[2] = strtol (p, &p, 10); - ++p; - tsi.gsi.identifier[3] = strtol (p, &p, 10); - ++p; - tsi.gsi.identifier[4] = strtol (p, &p, 10); - ++p; - tsi.gsi.identifier[5] = strtol (p, &p, 10); - ++p; - tsi.sport = g_htons ( strtol (p, NULL, 10) ); - - net_send_spmr (name, &tsi); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* send nak/ncf */ - re = "^net[[:space:]]+send[[:space:]](parity[[:space:]])?n(ak|cf)[[:space:]]+" - "([[:alnum:]]+)[[:space:]]+" /* transport */ - "([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)[[:space:]]+" /* TSI */ - "([0-9,]+)$"; /* sequence number or list */ - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[3].rm_so, pmatch[3].rm_eo - pmatch[3].rm_so + 1 ); - name[ pmatch[3].rm_eo - pmatch[3].rm_so ] = 0; - - pgm_tsi_t tsi; - char *p = str + pmatch[4].rm_so; - tsi.gsi.identifier[0] = strtol (p, &p, 10); - ++p; - tsi.gsi.identifier[1] = strtol (p, &p, 10); - ++p; - tsi.gsi.identifier[2] = strtol (p, &p, 10); - ++p; - tsi.gsi.identifier[3] = strtol (p, &p, 10); - ++p; - tsi.gsi.identifier[4] = strtol (p, &p, 10); - ++p; - tsi.gsi.identifier[5] = strtol (p, &p, 10); - ++p; - tsi.sport = g_htons ( strtol (p, NULL, 10) ); - -/* parse list of sequence numbers */ - struct pgm_sqn_list_t sqn_list; - sqn_list.len = 0; - { - char* saveptr = NULL; - for (p = str + pmatch[5].rm_so; ; p = NULL) { - char* token = strtok_r (p, ",", &saveptr); - if (!token) break; - sqn_list.sqn[sqn_list.len++] = strtoul (token, NULL, 10); - } - } - - if ( *(str + pmatch[2].rm_so) == 'a' ) - { - net_send_nak (name, &tsi, &sqn_list, (pmatch[1].rm_eo > pmatch[1].rm_so)); - } - else - { - net_send_ncf (name, &tsi, &sqn_list); - } - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/** same as test application: **/ - -/* create transport */ - re = "^create[[:space:]]+(fake[[:space:]]+)?([[:alnum:]]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); - name[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; - - session_create (name, (pmatch[1].rm_eo > pmatch[1].rm_so)); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* enable Reed-Solomon Forward Error Correction */ - re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+FEC[[:space:]]+RS[[:space:]]*\\([[:space:]]*([0-9]+)[[:space:]]*,[[:space:]]*([0-9]+)[[:space:]]*\\)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - char *p = str + pmatch[2].rm_so; - *(str + pmatch[2].rm_eo) = 0; - guint n = strtol (p, &p, 10); - p = str + pmatch[3].rm_so; - *(str + pmatch[3].rm_eo) = 0; - guint k = strtol (p, &p, 10); - session_set_fec (name, n, k); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* bind transport */ - re = "^bind[[:space:]]+([[:alnum:]]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - session_bind (name); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* send packet */ - re = "^send[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - char *string = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); - string[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; - - session_send (name, string, FALSE); - - g_free (name); - g_free (string); - regfree (&preg); - goto out; - } - regfree (&preg); - - re = "^send[[:space:]]+(brokn[[:space:]]+)?([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+x[[:space:]]([0-9]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); - name[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; - - char* p = str + pmatch[4].rm_so; - int factor = strtol (p, &p, 10); - int src_len = pmatch[3].rm_eo - pmatch[3].rm_so; - char *string = g_malloc ( (factor * src_len) + 1 ); - for (int i = 0; i < factor; i++) - { - memcpy (string + (i * src_len), str + pmatch[3].rm_so, src_len); - } - string[ factor * src_len ] = 0; - - session_send (name, string, (pmatch[1].rm_eo > pmatch[1].rm_so)); - - g_free (name); - g_free (string); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* destroy transport */ - re = "^destroy[[:space:]]+([[:alnum:]]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - - session_destroy (name); - - g_free (name); - regfree (&preg); - goto out; - } - regfree (&preg); - -/* set PGM network */ - re = "^set[[:space:]]+network[[:space:]]+([[:print:]]*;[[:print:]]+)$"; - regcomp (&preg, re, REG_EXTENDED); - if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) - { - char *pgm_network = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); - pgm_network[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; - g_network = pgm_network; - puts ("READY"); - - regfree (&preg); - goto out; - } - regfree (&preg); - - printf ("unknown command: %s\n", str); - } - -out: - fflush (stdout); - g_free (str); - return TRUE; -} - -/* idle log notification - */ - -static -gboolean -on_mark ( - G_GNUC_UNUSED gpointer data - ) -{ - g_message ("-- MARK --"); - return TRUE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/spm.pl b/3rdparty/openpgm-svn-r1085/pgm/test/spm.pl deleted file mode 100755 index c92b8fc..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/spm.pl +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/perl -# spm.pl -# 5.1.4. Ambient SPMs - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$app->connect; - -sub close_ssh { - $mon = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -print "app: ready.\n"; - -print "mon: wait for spm ...\n"; -$mon->wait_for_spm; -print "mon: received spm.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/spm_jump.pl b/3rdparty/openpgm-svn-r1085/pgm/test/spm_jump.pl deleted file mode 100755 index 9b89720..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/spm_jump.pl +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/perl -# spm_jump.pl -# 6.2. Source Path Messages - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; -$sim->say ("net send spm ao 3200 90001 90000"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,005 at spm_sqn 20.\n"; -$sim->say ("net send spm ao 20 90001 90005"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/spm_jump2.pl b/3rdparty/openpgm-svn-r1085/pgm/test/spm_jump2.pl deleted file mode 100755 index 4ad0562..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/spm_jump2.pl +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/perl -# spm_jump2.pl -# 6.3. Data Recovery by Negative Acknowledgment - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; -$sim->say ("net send spm ao 3200 90001 90000"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish SPM txw_trail 90,001 txw_lead 90,001 at spm_sqn 3201.\n"; -$sim->say ("net send spm ao 3201 90001 90001"); - -print "sim: waiting for valid NAK.\n"; -$sim->wait_for_nak; -print "sim: NAK received.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/spm_reception.pl b/3rdparty/openpgm-svn-r1085/pgm/test/spm_reception.pl deleted file mode 100755 index 63ea43f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/spm_reception.pl +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/perl -# spm_reception.pl -# 6.1. Data Reception - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); - -print "sim: publish SPM txw_trail 90,000.\n"; -$sim->say ("net send spm ao 1 90001 90000"); - -# no NAKs should be generated. -print "sim: waiting 2 seconds for erroneous NAKs ...\n"; -$sim->die_on_nak({ 'timeout' => 2 }); -print "sim: no NAKs received.\n"; - -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90000 ichigo"); -print "app: wait for data ...\n"; -my $data = $app->wait_for_data; -print "app: received data [$data].\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/spmr.pl b/3rdparty/openpgm-svn-r1085/pgm/test/spmr.pl deleted file mode 100755 index a22f14d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/spmr.pl +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/perl -# spmr.pl -# 13.3.1. SPM Requests - -use strict; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); -print "sim: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -## capture GSI of test spp -$app->say ("send ao nashi"); -print "mon: wait for odata ...\n"; -my $odata = $mon->wait_for_odata; -print "mon: odata received.\n"; -my $t0 = [gettimeofday]; -my $elapsed; - -$mon->disconnect (1); - -## spm hearbeats are going to clear out the data, lets wait for some quiet -print "sim: wait for SPM interval > 5 seconds ...\n"; -do { - $sim->wait_for_spm; - $elapsed = tv_interval ( $t0, [gettimeofday] ); - print "sim: received SPM after $elapsed seconds.\n"; -} while ($elapsed < 5); - -print "sim: request SPM via SPMR.\n"; -$sim->say ("net send spmr ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort}"); -$t0 = [gettimeofday]; - -print "sim: wait for SPM ...\n"; -$sim->wait_for_spm; -$elapsed = tv_interval ( $t0, [gettimeofday] ); -print "sim: SPM received after $elapsed seconds.\n"; -die "SPM interval too large, indicates heartbeat not SPMR induced.\n" unless ($elapsed < 5.0); - -print "test completed successfully.\n"; - -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/spmr_after_spm.pl b/3rdparty/openpgm-svn-r1085/pgm/test/spmr_after_spm.pl deleted file mode 100755 index a1ca5ee..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/spmr_after_spm.pl +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/perl -# spmr.pl -# 13.3.1. SPM Requests - -use strict; -use Time::HiRes qw( gettimeofday tv_interval ); -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -## capture GSI of test spp -$app->say ("send ao nashi"); -print "mon: wait for odata ...\n"; -my $odata = $mon->wait_for_odata; -print "mon: odata received.\n"; -my $t0 = [gettimeofday]; -my $elapsed; - -## spm hearbeats are going to clear out the data, lets wait for some quiet -print "mon: wait for SPM interval > 5 seconds ...\n"; -do { - $mon->wait_for_spm; - $elapsed = tv_interval ( $t0, [gettimeofday] ); - print "mon: received SPM after $elapsed seconds.\n"; -} while ($elapsed < 5); - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); -print "sim: ready.\n"; - -## app needs to send packet for sim to learn of local NLA -$app->say ("send ao budo"); -print "sim: wait for odata ...\n"; -$odata = $sim->wait_for_odata; -print "sim: odata received.\n"; - -print "sim: request SPM via SPMR.\n"; -$sim->say ("net send spmr ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort}"); -$t0 = [gettimeofday]; - -print "sim: wait for SPM ...\n"; -$sim->wait_for_spm; -$elapsed = tv_interval ( $t0, [gettimeofday] ); -print "sim: SPM received after $elapsed seconds.\n"; -die "SPM interval too large, indicates heartbeat not SPMR induced.\n" unless ($elapsed < 5.0); - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/spmr_from_odata.pl b/3rdparty/openpgm-svn-r1085/pgm/test/spmr_from_odata.pl deleted file mode 100755 index 0563b3f..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/spmr_from_odata.pl +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/perl -# spmr_from_odata.pl -# 13.3.1. SPM Requests - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$mon->say ("filter $config{app}{ip}"); -print "mon: ready.\n"; - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); -print "sim: publish ODATA sqn 90,001.\n"; -$sim->say ("net send odata ao 90001 90001 ringo"); - -my $data = $app->wait_for_data; -print "app: received data [$data].\n"; - -print "mon: wait for SPMR ...\n"; -$mon->wait_for_spmr; -print "mon: received SPMR.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/spmr_suppression.pl b/3rdparty/openpgm-svn-r1085/pgm/test/spmr_suppression.pl deleted file mode 100755 index a1df615..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/spmr_suppression.pl +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/perl -# spmr_suppression.pl -# 13.3.1. SPM Requests - -use strict; -use PGM::Test; - -BEGIN { require "test.conf.pl"; } - -$| = 1; - -my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); -my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); -my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); - -$mon->connect; -$sim->connect; -$app->connect; - -sub close_ssh { - $mon = $sim = $app = undef; - print "finished.\n"; -} - -$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; - -$sim->say ("create fake ao"); -$sim->say ("bind ao"); -print "sim: publish ODATA sqn 90,001 to monitor for GSI.\n"; -$sim->say ("net send odata ao 90001 90001 ringo"); - -## capture GSI of test sim (not app!) -my $odata = $mon->wait_for_odata; -$mon->say ("filter $config{app}{ip}"); - -$app->say ("create ao"); -$app->say ("bind ao"); -$app->say ("listen ao"); - -print "sim: re-publish ODATA sqn 90,001 to app.\n"; -$sim->say ("net send odata ao 90001 90001 ringo"); -$sim->say ("net send spmr ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort}"); - -my $data = $app->wait_for_data; -print "app: received data [$data].\n"; - -print "mon: wait for erroneous SPMR ...\n"; -$mon->die_on_spmr({ 'timeout' => 2 }); -print "mon: no SPMR received.\n"; - -print "test completed successfully.\n"; - -$mon->disconnect (1); -$sim->disconnect; -$app->disconnect; -close_ssh; - -# eof diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/sudoers.example b/3rdparty/openpgm-svn-r1085/pgm/test/sudoers.example deleted file mode 100644 index 9212139..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/sudoers.example +++ /dev/null @@ -1,26 +0,0 @@ -# /etc/sudoers -# -# This file MUST be edited with the 'visudo' command as root. -# -# See the man page for details on how to write a sudoers file. -# Host alias specification - -# User alias specification -User_Alias PGM_USER = steve-o - -# Cmnd alias specification -Cmnd_Alias PGM_CONFORMANCE = /miru/projects/openpgm/pgm/ref/debug/test/* - -# Defaults - -Defaults !lecture,tty_tickets,!fqdn - -# User privilege specification -root ALL=(ALL) ALL - -# Members of the admin group may gain root privileges -%admin ALL=(ALL) ALL - - -# PGM testing -PGM_USER ALL = NOPASSWD: PGM_CONFORMANCE diff --git a/3rdparty/openpgm-svn-r1085/pgm/test/test.conf.pl b/3rdparty/openpgm-svn-r1085/pgm/test/test.conf.pl deleted file mode 100644 index 428f49e..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/test/test.conf.pl +++ /dev/null @@ -1,27 +0,0 @@ -# test.conf.pl -use vars qw ( %config ); - -%config = ( - msapp => { - host => 'momo', - ip => '10.6.28.34', - }, - app => { -# host => 'ayaka', ip => '10.6.28.31', -# cmd => '/miru/projects/openpgm/pgm/ref/release-Linux-x86_64/test/app', -# network => 'eth0;239.192.0.1' - host => 'ryoko', ip => '10.6.28.36', - cmd => 'LD_LIBRARY_PATH=/opt/glib-sunstudio/lib:$LD_LIBRARY_PATH /miru/projects/openpgm/pgm/ref/release-SunOS-sun4u-sunstudio/test/app', - network => 'eri0;239.192.0.1' - }, - mon => { - host => 'sora', - cmd => '/miru/projects/openpgm/pgm/ref/release-Linux-x86_64/test/monitor', - network => 'eth0;239.192.0.1' - }, - sim => { - host => 'kiku', - cmd => '/miru/projects/openpgm/pgm/ref/release-Linux-x86_64/test/sim', - network => 'eth0;239.192.0.1' - }, -); diff --git a/3rdparty/openpgm-svn-r1085/pgm/thread.c b/3rdparty/openpgm-svn-r1085/pgm/thread.c deleted file mode 100644 index ad68ca3..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/thread.c +++ /dev/null @@ -1,457 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * mutexes and locks. - * - * Copyright (c) 2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -//#define THREAD_DEBUG - - -/* Globals */ - -#if defined(_WIN32) && !defined(CONFIG_HAVE_WIN_COND) -static DWORD cond_event_tls = TLS_OUT_OF_INDEXES; -#endif - -static volatile uint32_t thread_ref_count = 0; - - -#ifndef _WIN32 -# define posix_check_err(err, name) \ - do { \ - const int save_error = (err); \ - if (PGM_UNLIKELY(save_error)) { \ - pgm_error ("file %s: line %d (%s): error '%s' during '%s'", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__, \ - strerror (save_error), name); \ - } \ - } while (0) -# define posix_check_cmd(cmd) posix_check_err ((cmd), #cmd) -#else -# define win32_check_err(err, name) \ - do { \ - const bool save_error = (err); \ - if (PGM_UNLIKELY(!save_error)) { \ - pgm_error ("file %s: line %d (%s): error '%s' during '%s'", \ - __FILE__, __LINE__, __PRETTY_FUNCTION__, \ - pgm_wsastrerror (GetLastError ()), name); \ - } \ - } while (0) -# define win32_check_cmd(cmd) win32_check_err ((cmd), #cmd) -#endif /* !_WIN32 */ - - -/* only needed for Win32 pre-Vista read-write locks - */ -void -pgm_thread_init (void) -{ - if (pgm_atomic_exchange_and_add32 (&thread_ref_count, 1) > 0) - return; - -#if defined(_WIN32) && !defined(CONFIG_HAVE_WIN_COND) - win32_check_cmd (TLS_OUT_OF_INDEXES != (cond_event_tls = TlsAlloc ())); -#endif -} - -void -pgm_thread_shutdown (void) -{ - pgm_return_if_fail (pgm_atomic_read32 (&thread_ref_count) > 0); - - if (pgm_atomic_exchange_and_add32 (&thread_ref_count, (uint32_t)-1) != 1) - return; - -#if defined(_WIN32) && !defined(CONFIG_HAVE_WIN_COND) - TlsFree (cond_event_tls); -#endif -} - -void -pgm_mutex_init ( - pgm_mutex_t* mutex - ) -{ - pgm_assert (NULL != mutex); -#ifndef _WIN32 - posix_check_cmd (pthread_mutex_init (&mutex->pthread_mutex, NULL)); -#else - HANDLE handle; - win32_check_cmd (handle = CreateMutex (NULL, FALSE, NULL)); - mutex->win32_mutex = handle; -#endif /* !_WIN32 */ -} - -bool -pgm_mutex_trylock ( - pgm_mutex_t* mutex - ) -{ - pgm_assert (NULL != mutex); -#ifndef _WIN32 - const int result = pthread_mutex_trylock (&mutex->pthread_mutex); - if (EBUSY == result) - return FALSE; - posix_check_err (result, "pthread_mutex_trylock"); - return TRUE; -#else - DWORD result; - win32_check_cmd (WAIT_FAILED != (result = WaitForSingleObject (mutex->win32_mutex, 0))); - return WAIT_TIMEOUT != result; -#endif /* !_WIN32 */ -} - -void -pgm_mutex_free ( - pgm_mutex_t* mutex - ) -{ - pgm_assert (NULL != mutex); -#ifndef _WIN32 - posix_check_cmd (pthread_mutex_destroy (&mutex->pthread_mutex)); -#else - win32_check_cmd (CloseHandle (mutex->win32_mutex)); -#endif /* !_WIN32 */ -} - -void -pgm_spinlock_init ( - pgm_spinlock_t* spinlock - ) -{ - pgm_assert (NULL != spinlock); -#ifndef _WIN32 - posix_check_cmd (pthread_spin_init (&spinlock->pthread_spinlock, PTHREAD_PROCESS_PRIVATE)); -#else - InitializeCriticalSection (&spinlock->win32_spinlock); -#endif /* !_WIN32 */ -} - -bool -pgm_spinlock_trylock ( - pgm_spinlock_t* spinlock - ) -{ - pgm_assert (NULL != spinlock); -#ifndef _WIN32 - const int result = pthread_spin_trylock (&spinlock->pthread_spinlock); - if (EBUSY == result) - return FALSE; - posix_check_err (result, "pthread_spinlock_trylock"); - return TRUE; -#else - return TryEnterCriticalSection (&spinlock->win32_spinlock); -#endif /* !_WIN32 */ -} - -void -pgm_spinlock_free ( - pgm_spinlock_t* spinlock - ) -{ - pgm_assert (NULL != spinlock); -#ifndef _WIN32 -/* ignore return value */ - pthread_spin_destroy (&spinlock->pthread_spinlock); -#else - DeleteCriticalSection (&spinlock->win32_spinlock); -#endif /* !_WIN32 */ -} - -void -pgm_cond_init ( - pgm_cond_t* cond - ) -{ - pgm_assert (NULL != cond); -#ifndef _WIN32 - posix_check_cmd (pthread_cond_init (&cond->pthread_cond, NULL)); -#elif defined(CONFIG_HAVE_WIN_COND) - InitializeConditionVariable (&cond->win32_cond); -#else - cond->len = 0; - cond->allocated_len = pgm_nearest_power (1, 2 + 1); - cond->phandle = pgm_new (HANDLE, cond->allocated_len); - InitializeCriticalSection (&cond->win32_spinlock); -#endif /* !_WIN32 */ -} - -void -pgm_cond_signal ( - pgm_cond_t* cond - ) -{ - pgm_assert (NULL != cond); -#ifndef _WIN32 - pthread_cond_signal (&cond->pthread_cond); -#elif defined(CONFIG_HAVE_WIN_COND) - WakeConditionVariable (&cond->win32_cond); -#else - EnterCriticalSection (&cond->win32_spinlock); - if (cond->len > 0) { - SetEvent (cond->phandle[ 0 ]); - memmove (&cond->phandle[ 0 ], &cond->phandle[ 1 ], cond->len - 1); - cond->len--; - } - LeaveCriticalSection (&cond->win32_spinlock); -#endif /* !_WIN32 */ -} - -void -pgm_cond_broadcast ( - pgm_cond_t* cond - ) -{ - pgm_assert (NULL != cond); -#ifndef _WIN32 - pthread_cond_broadcast (&cond->pthread_cond); -#elif defined(CONFIG_HAVE_WIN_COND) - WakeAllConditionVariable (&cond->win32_cond); -#else - EnterCriticalSection (&cond->win32_spinlock); - for (unsigned i = 0; i < cond->len; i++) - SetEvent (cond->phandle[ i ]); - cond->len = 0; - LeaveCriticalSection (&cond->win32_spinlock); -#endif /* !_WIN32 */ -} - -#ifndef _WIN32 -void -pgm_cond_wait ( - pgm_cond_t* cond, - pthread_mutex_t* mutex - ) -{ - pgm_assert (NULL != cond); - pgm_assert (NULL != mutex); - pthread_cond_wait (&cond->pthread_cond, mutex); -} -#else -void -pgm_cond_wait ( - pgm_cond_t* cond, - CRITICAL_SECTION* spinlock - ) -{ - pgm_assert (NULL != cond); - pgm_assert (NULL != spinlock); -# if defined(CONFIG_HAVE_WIN_COND) - SleepConditionVariableCS (&cond->win32_cond, spinlock, INFINITE); -# else - DWORD status; - HANDLE event = TlsGetValue (cond_event_tls); - - if (!event) { - win32_check_cmd (event = CreateEvent (0, FALSE, FALSE, NULL)); - TlsSetValue (cond_event_tls, event); - } - - EnterCriticalSection (&cond->win32_spinlock); - pgm_assert (WAIT_TIMEOUT == WaitForSingleObject (event, 0)); - if ((cond->len + 1) > cond->allocated_len) { - cond->allocated_len = pgm_nearest_power (1, cond->len + 1 + 1); - cond->phandle = pgm_realloc (cond->phandle, cond->allocated_len); - } - cond->phandle[ cond->len++ ] = event; - LeaveCriticalSection (&cond->win32_spinlock); - - EnterCriticalSection (spinlock); - win32_check_cmd (WAIT_FAILED != (status = WaitForSingleObject (event, INFINITE))); - LeaveCriticalSection (spinlock); - - if (WAIT_TIMEOUT == status) { - EnterCriticalSection (&cond->win32_spinlock); - for (unsigned i = 0; i < cond->len; i++) { - if (cond->phandle[ i ] == event) { - if (i != cond->len - 1) - memmove (&cond->phandle[ i ], &cond->phandle[ i + 1 ], sizeof(HANDLE) * (cond->len - i - 1)); - cond->len--; - break; - } - } - win32_check_cmd (WAIT_FAILED != (status = WaitForSingleObject (event, 0))); - LeaveCriticalSection (&cond->win32_spinlock); - } -# endif /* !CONFIG_HAVE_WIN_COND */ -} -#endif /* !_WIN32 */ - -void -pgm_cond_free ( - pgm_cond_t* cond - ) -{ - pgm_assert (NULL != cond); -#ifndef _WIN32 - posix_check_cmd (pthread_cond_destroy (&cond->pthread_cond)); -#elif defined(CONFIG_HAVE_WIN_COND) - /* nop */ -#else - DeleteCriticalSection (&cond->win32_spinlock); - pgm_free (cond->phandle); -#endif /* !_WIN32 */ -} - -void -pgm_rwlock_init ( - pgm_rwlock_t* rwlock - ) -{ - pgm_assert (NULL != rwlock); -#ifdef CONFIG_HAVE_WIN_SRW_LOCK - InitializeSRWLock (&rwlock->win32_lock); -#elif !defined(_WIN32) - posix_check_cmd (pthread_rwlock_init (&rwlock->pthread_rwlock, NULL)); -#else - InitializeCriticalSection (&rwlock->win32_spinlock); - pgm_cond_init (&rwlock->read_cond); - pgm_cond_init (&rwlock->write_cond); - rwlock->read_counter = 0; - rwlock->have_writer = FALSE; - rwlock->want_to_read = 0; - rwlock->want_to_write = 0; -#endif /* !CONFIG_HAVE_WIN_SRW_LOCK */ -} - -void -pgm_rwlock_free ( - pgm_rwlock_t* rwlock - ) -{ - pgm_assert (NULL != rwlock); -#ifdef CONFIG_HAVE_WIN_SRW_LOCK - /* nop */ -#elif !defined(_WIN32) - pthread_rwlock_destroy (&rwlock->pthread_rwlock); -#else - pgm_cond_free (&rwlock->read_cond); - pgm_cond_free (&rwlock->write_cond); - DeleteCriticalSection (&rwlock->win32_spinlock); -#endif /* !CONFIG_HAVE_WIN_SRW_LOCK */ -} - -#if !defined(CONFIG_HAVE_WIN_SRW_LOCK) && defined(_WIN32) -static inline -void -_pgm_rwlock_signal ( - pgm_rwlock_t* rwlock - ) -{ - pgm_assert (NULL != rwlock); - if (rwlock->want_to_write) - pgm_cond_signal (&rwlock->write_cond); - else if (rwlock->want_to_read) - pgm_cond_broadcast (&rwlock->read_cond); -} - -void -pgm_rwlock_reader_lock ( - pgm_rwlock_t* rwlock - ) -{ - pgm_assert (NULL != rwlock); - EnterCriticalSection (&rwlock->win32_spinlock); - rwlock->want_to_read++; - while (rwlock->have_writer || rwlock->want_to_write) - pgm_cond_wait (&rwlock->read_cond, &rwlock->win32_spinlock); - rwlock->want_to_read--; - rwlock->read_counter++; - LeaveCriticalSection (&rwlock->win32_spinlock); -} - -bool -pgm_rwlock_reader_trylock ( - pgm_rwlock_t* rwlock - ) -{ - pgm_assert (NULL != rwlock); - bool status; - EnterCriticalSection (&rwlock->win32_spinlock); - if (!rwlock->have_writer && !rwlock->want_to_write) { - rwlock->read_counter++; - status = TRUE; - } else - status = FALSE; - LeaveCriticalSection (&rwlock->win32_spinlock); - return status; -} - -void -pgm_rwlock_reader_unlock( - pgm_rwlock_t* rwlock - ) -{ - pgm_assert (NULL != rwlock); - EnterCriticalSection (&rwlock->win32_spinlock); - rwlock->read_counter--; - if (rwlock->read_counter == 0) - _pgm_rwlock_signal (rwlock); - LeaveCriticalSection (&rwlock->win32_spinlock); -} - -void -pgm_rwlock_writer_lock ( - pgm_rwlock_t* rwlock - ) -{ - pgm_assert (NULL != rwlock); - EnterCriticalSection (&rwlock->win32_spinlock); - rwlock->want_to_write++; - while (rwlock->have_writer || rwlock->read_counter) - pgm_cond_wait (&rwlock->write_cond, &rwlock->win32_spinlock); - rwlock->want_to_write--; - rwlock->have_writer = TRUE; - LeaveCriticalSection (&rwlock->win32_spinlock); -} - -bool -pgm_rwlock_writer_trylock ( - pgm_rwlock_t* rwlock - ) -{ - pgm_assert (NULL != rwlock); - bool status; - EnterCriticalSection (&rwlock->win32_spinlock); - if (!rwlock->have_writer && !rwlock->read_counter) { - rwlock->have_writer = TRUE; - status = TRUE; - } else - status = FALSE; - LeaveCriticalSection (&rwlock->win32_spinlock); - return status; -} - -void -pgm_rwlock_writer_unlock ( - pgm_rwlock_t* rwlock - ) -{ - pgm_assert (NULL != rwlock); - EnterCriticalSection (&rwlock->win32_spinlock); - rwlock->have_writer = FALSE; - _pgm_rwlock_signal (rwlock); - LeaveCriticalSection (&rwlock->win32_spinlock); -} -#endif /* !_WIN32 && !CONFIG_HAVE_WIN_SRW_LOCK */ - - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/time.c b/3rdparty/openpgm-svn-r1085/pgm/time.c deleted file mode 100644 index 9b8eeaa..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/time.c +++ /dev/null @@ -1,770 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * high resolution timers. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define __STDC_FORMAT_MACROS -#include -#include -#include -#ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN -# include "windows.h" -#endif -#include -#include - -//#define TIME_DEBUG - - -/* globals */ - -pgm_time_update_func pgm_time_update_now PGM_GNUC_READ_MOSTLY; -pgm_time_since_epoch_func pgm_time_since_epoch PGM_GNUC_READ_MOSTLY; - - -/* locals */ - -#define msecs_to_secs(t) ( (t) / 1000 ) -#define usecs_to_secs(t) ( (t) / 1000000UL ) -#define nsecs_to_secs(t) ( (t) / 1000000000UL ) -#define secs_to_msecs(t) ( (pgm_time_t)(t) * 1000 ) -#define secs_to_usecs(t) ( (pgm_time_t)(t) * 1000000UL ) -#define secs_to_nsecs(t) ( (pgm_time_t)(t) * 1000000000UL ) -#define msecs_to_usecs(t) ( (pgm_time_t)(t) * 1000 ) -#define msecs_to_nsecs(t) ( (pgm_time_t)(t) * 1000000UL ) -#define usecs_to_msecs(t) ( (t) / 1000 ) -#define usecs_to_nsecs(t) ( (pgm_time_t)(t) * 1000 ) -#define nsecs_to_msecs(t) ( (t) / 1000000UL ) -#define nsecs_to_usecs(t) ( (t) / 1000 ) -#define fsecs_to_nsecs(t) ( (t) / 1000000UL ) -#define fsecs_to_usecs(t) ( (t) / 1000000000UL ) - -static volatile uint32_t time_ref_count = 0; -static pgm_time_t rel_offset PGM_GNUC_READ_MOSTLY = 0; - -static void pgm_time_conv (const pgm_time_t*const restrict, time_t*restrict); -static void pgm_time_conv_from_reset (const pgm_time_t*const restrict, time_t*restrict); - -#if defined(CONFIG_HAVE_CLOCK_GETTIME) -# include -static pgm_time_t pgm_clock_update (void); -#endif -#ifdef CONFIG_HAVE_FTIME -# include -# ifdef _WIN32 -# define ftime _ftime -# endif -static pgm_time_t pgm_ftime_update (void); -#endif -#ifdef CONFIG_HAVE_GETTIMEOFDAY -# include -static pgm_time_t pgm_gettimeofday_update (void); -#endif -#ifdef CONFIG_HAVE_HPET -# include -# include -# include -# include -# include -# define HPET_MMAP_SIZE 0x400 -# define HPET_GENERAL_CAPS_REGISTER 0x00 -# define HPET_COUNTER_CLK_PERIOD 0x004 -# define HPET_MAIN_COUNTER_REGISTER 0x0f0 -# define HPET_COUNT_SIZE_CAP (1 << 13) -/* HPET counter size maybe 64-bit or 32-bit */ -# if defined(__x86_64__) -typedef uint64_t hpet_counter_t; -# else -typedef uint32_t hpet_counter_t; -# endif -static int hpet_fd PGM_GNUC_READ_MOSTLY = -1; -static char* hpet_ptr PGM_GNUC_READ_MOSTLY; -static uint64_t hpet_offset = 0; -static uint64_t hpet_wrap PGM_GNUC_READ_MOSTLY; -static hpet_counter_t hpet_last = 0; - -# define HPET_NS_SCALE 22 -# define HPET_US_SCALE 34 -static uint_fast32_t hpet_ns_mul PGM_GNUC_READ_MOSTLY = 0; -static uint_fast32_t hpet_us_mul PGM_GNUC_READ_MOSTLY = 0; - -static inline -void -set_hpet_mul ( - const uint32_t hpet_period - ) -{ - hpet_ns_mul = fsecs_to_nsecs((uint64_t)hpet_period << HPET_NS_SCALE); - hpet_us_mul = fsecs_to_usecs((uint64_t)hpet_period << HPET_US_SCALE); -} - -static inline -uint64_t -hpet_to_ns ( - const uint64_t hpet - ) -{ - return (hpet * hpet_ns_mul) >> HPET_NS_SCALE; -} - -static inline -uint64_t -hpet_to_us ( - const uint64_t hpet - ) -{ - return (hpet * hpet_us_mul) >> HPET_US_SCALE; -} - -static bool pgm_hpet_init (pgm_error_t**); -static bool pgm_hpet_shutdown (void); -static pgm_time_t pgm_hpet_update (void); -#endif -#ifdef CONFIG_HAVE_RTC -# include -# include -# include -# include -# include -# include -static int rtc_fd PGM_GNUC_READ_MOSTLY = -1; -static int rtc_frequency PGM_GNUC_READ_MOSTLY = 8192; -static pgm_time_t rtc_count = 0; -static bool pgm_rtc_init (pgm_error_t**); -static bool pgm_rtc_shutdown (void); -static pgm_time_t pgm_rtc_update (void); -#endif -#ifdef CONFIG_HAVE_TSC -# include -# include -# define TSC_NS_SCALE 10 /* 2^10, carefully chosen */ -# define TSC_US_SCALE 20 -static uint_fast32_t tsc_mhz PGM_GNUC_READ_MOSTLY = 0; -static uint_fast32_t tsc_ns_mul PGM_GNUC_READ_MOSTLY = 0; -static uint_fast32_t tsc_us_mul PGM_GNUC_READ_MOSTLY = 0; - -static inline -void -set_tsc_mul ( - const unsigned khz - ) -{ - tsc_ns_mul = (1000000 << TSC_NS_SCALE) / khz; - tsc_us_mul = (1000 << TSC_US_SCALE) / khz; -} - -static inline -uint64_t -tsc_to_ns ( - const uint64_t tsc - ) -{ - return (tsc * tsc_ns_mul) >> TSC_NS_SCALE; -} - -static inline -uint64_t -ns_to_tsc ( - const uint64_t ns - ) -{ - return (ns << TSC_NS_SCALE) / tsc_ns_mul; -} - -static inline -uint64_t -tsc_to_us ( - const uint64_t tsc - ) -{ - return (tsc * tsc_us_mul) >> TSC_US_SCALE; -} - -static inline -uint64_t -us_to_tsc ( - const uint64_t us - ) -{ - return (us << TSC_US_SCALE) / tsc_us_mul; -} - -# ifndef _WIN32 -static bool pgm_tsc_init (pgm_error_t**); -# endif -static pgm_time_t pgm_tsc_update (void); -#endif - - -/* initialize time system. - * - * returns TRUE on success, returns FALSE on error such as being unable to open - * the RTC device, an unstable TSC, or system already initialized. - */ - -bool -pgm_time_init ( - pgm_error_t** error - ) -{ - if (pgm_atomic_exchange_and_add32 (&time_ref_count, 1) > 0) - return TRUE; - -/* current time */ - const char *cfg = getenv ("PGM_TIMER"); - if (cfg == NULL) { -#ifdef CONFIG_HAVE_TSC - cfg = "TSC"; -#else - cfg = "GTOD"; -#endif - } - - pgm_time_since_epoch = pgm_time_conv; - - switch (cfg[0]) { -#ifdef CONFIG_HAVE_FTIME - case 'F': - pgm_minor (_("Using ftime() timer.")); - pgm_time_update_now = pgm_ftime_update; - break; -#endif -#ifdef CONFIG_HAVE_CLOCK_GETTIME - case 'C': - pgm_minor (_("Using clock_gettime() timer.")); - pgm_time_update_now = pgm_clock_update; - break; -#endif -#ifdef CONFIG_HAVE_RTC - case 'R': - pgm_minor (_("Using /dev/rtc timer.")); - pgm_time_update_now = pgm_rtc_update; - pgm_time_since_epoch = pgm_time_conv_from_reset; - break; -#endif -#ifdef CONFIG_HAVE_TSC -# ifdef _WIN32 - default: -# endif - case 'T': - pgm_minor (_("Using TSC timer.")); - pgm_time_update_now = pgm_tsc_update; - pgm_time_since_epoch = pgm_time_conv_from_reset; - break; -#endif -#ifdef CONFIG_HAVE_HPET - case 'H': - pgm_minor (_("Using HPET timer.")); - pgm_time_update_now = pgm_hpet_update; - pgm_time_since_epoch = pgm_time_conv_from_reset; - break; -#endif - -#ifdef CONFIG_HAVE_GETTIMEOFDAY -# ifndef _WIN32 - default: -# endif - case 'G': - pgm_minor (_("Using gettimeofday() timer.")); - pgm_time_update_now = pgm_gettimeofday_update; - break; -#endif - } - -#ifdef CONFIG_HAVE_RTC - if (pgm_time_update_now == pgm_rtc_update) - { - pgm_error_t* sub_error = NULL; - if (!pgm_rtc_init (&sub_error)) { - pgm_propagate_error (error, sub_error); - goto err_cleanup; - } - } -#endif -#ifdef CONFIG_HAVE_TSC - if (pgm_time_update_now == pgm_tsc_update) - { -#ifdef CONFIG_HAVE_PROC -/* attempt to parse clock ticks from kernel - */ - FILE* fp = fopen ("/proc/cpuinfo", "r"); - char buffer[1024]; - if (fp) - { - while (!feof(fp) && fgets (buffer, sizeof(buffer), fp)) - { - if (strstr (buffer, "cpu MHz")) - { - const char *p = strchr (buffer, ':'); - if (p) tsc_mhz = atoi (p + 1); - break; - } - } - fclose (fp); - } -#elif defined(_WIN32) - uint64_t frequency; - if (QueryPerformanceFrequency ((LARGE_INTEGER*)&frequency)) - { - tsc_mhz = frequency / 1000; - } -#endif /* !_WIN32 */ - -/* e.g. export RDTSC_FREQUENCY=3200.000000 - * - * Value can be used to override kernel tick rate as well as internal calibration - */ - const char *env_mhz = getenv ("RDTSC_FREQUENCY"); - if (env_mhz) - tsc_mhz = atoi (env_mhz); - -#ifndef _WIN32 -/* calibrate */ - if (0 >= tsc_mhz) { - pgm_error_t* sub_error = NULL; - if (!pgm_tsc_init (&sub_error)) { - pgm_propagate_error (error, sub_error); - goto err_cleanup; - } - } -#endif - set_tsc_mul (tsc_mhz * 1000); - } -#endif /* CONFIG_HAVE_TSC */ - -#ifdef CONFIG_HAVE_HPET - if (pgm_time_update_now == pgm_hpet_update) - { - pgm_error_t* sub_error = NULL; - if (!pgm_hpet_init (&sub_error)) { - pgm_propagate_error (error, sub_error); - goto err_cleanup; - } - } -#endif - - pgm_time_update_now(); - -/* calculate relative time offset */ -#if defined(CONFIG_HAVE_RTC) || defined(CONFIG_HAVE_TSC) - if ( 0 -# ifdef CONFIG_HAVE_RTC - || pgm_time_update_now == pgm_rtc_update -# endif -# ifdef CONFIG_HAVE_TSC - || pgm_time_update_now == pgm_tsc_update -# endif - ) - { -# if defined( CONFIG_HAVE_GETTIMEOFDAY ) - rel_offset = pgm_gettimeofday_update() - pgm_time_update_now(); -# elif defined( CONFIG_HAVE_FTIME ) - rel_offset = pgm_ftime_update() - pgm_time_update_now(); -# else -# error "gettimeofday() or ftime() required to calculate counter offset" -# endif - } -#else - rel_offset = 0; -#endif - - return TRUE; - -err_cleanup: - pgm_atomic_dec32 (&time_ref_count); - return FALSE; -} - -/* returns TRUE if shutdown succeeded, returns FALSE on error. - */ - -bool -pgm_time_shutdown (void) -{ - pgm_return_val_if_fail (pgm_atomic_read32 (&time_ref_count) > 0, FALSE); - - if (pgm_atomic_exchange_and_add32 (&time_ref_count, (uint32_t)-1) != 1) - return TRUE; - - bool success = TRUE; -#ifdef CONFIG_HAVE_RTC - if (pgm_time_update_now == pgm_rtc_update) - success = pgm_rtc_shutdown (); -#endif -#ifdef CONFIG_HAVE_HPET - if (pgm_time_update_now == pgm_hpet_update) - success = pgm_hpet_shutdown (); -#endif - return success; -} - -#ifdef CONFIG_HAVE_GETTIMEOFDAY -static -pgm_time_t -pgm_gettimeofday_update (void) -{ - struct timeval gettimeofday_now; - static pgm_time_t last = 0; - gettimeofday (&gettimeofday_now, NULL); - const pgm_time_t now = secs_to_usecs (gettimeofday_now.tv_sec) + gettimeofday_now.tv_usec; - if (PGM_UNLIKELY(now < last)) - return last; - else - return last = now; -} -#endif /* CONFIG_HAVE_GETTIMEOFDAY */ - -#ifdef CONFIG_HAVE_CLOCK_GETTIME -static -pgm_time_t -pgm_clock_update (void) -{ - struct timespec clock_now; - static pgm_time_t last = 0; - clock_gettime (CLOCK_MONOTONIC, &clock_now); - const pgm_time_t now = secs_to_usecs (clock_now.tv_sec) + nsecs_to_usecs (clock_now.tv_nsec); - if (PGM_UNLIKELY(now < last)) - return last; - else - return last = now; -} -#endif /* CONFIG_HAVE_CLOCK_GETTIME */ - -#ifdef CONFIG_HAVE_FTIME -static -pgm_time_t -pgm_ftime_update (void) -{ - struct timeb ftime_now; - static pgm_time_t last = 0; - ftime (&ftime_now); - const pgm_time_t now = secs_to_usecs (ftime_now.time) + msecs_to_usecs (ftime_now.millitm); - if (PGM_UNLIKELY(now < last)) - return last; - else - return last = now; -} -#endif /* CONFIG_HAVE_FTIME */ - -#ifdef CONFIG_HAVE_RTC -/* Old PC/AT-Compatible driver: /dev/rtc - * - * Not so speedy 8192 Hz timer, thats 122us resolution. - * - * WARNING: time is relative to start of timer. - * WARNING: only one process is allowed to access the RTC. - */ - -static -bool -pgm_rtc_init ( - pgm_error_t** error - ) -{ - pgm_return_val_if_fail (rtc_fd == -1, FALSE); - - rtc_fd = open ("/dev/rtc", O_RDONLY); - if (-1 == rtc_fd) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_TIME, - PGM_ERROR_FAILED, - _("Cannot open /dev/rtc for reading: %s"), - strerror(errno)); - return FALSE; - } - if (-1 == ioctl (rtc_fd, RTC_IRQP_SET, rtc_frequency)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_TIME, - PGM_ERROR_FAILED, - _("Cannot set RTC frequency to %i Hz: %s"), - rtc_frequency, - strerror(errno)); - return FALSE; - } - if (-1 == ioctl (rtc_fd, RTC_PIE_ON, 0)) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_TIME, - PGM_ERROR_FAILED, - _("Cannot enable periodic interrupt (PIE) on RTC: %s"), - strerror(errno)); - return FALSE; - } - return TRUE; -} - -/* returns TRUE on success even if RTC device cannot be closed or had an IO error, - * returns FALSE if the RTC file descriptor is not set. - */ - -static -bool -pgm_rtc_shutdown (void) -{ - pgm_return_val_if_fail (rtc_fd, FALSE); - pgm_warn_if_fail (0 == close (rtc_fd)); - rtc_fd = -1; - return TRUE; -} - -/* RTC only indicates passed ticks therefore is by definition monotonic, we do not - * need to check the difference with respect to the last value. - */ - -static -pgm_time_t -pgm_rtc_update (void) -{ - uint32_t data; - -/* returned value contains interrupt type and count of interrupts since last read */ - pgm_warn_if_fail (sizeof(data) == read (rtc_fd, &data, sizeof(data))); - rtc_count += data >> 8; - return rtc_count * 1000000UL / rtc_frequency; -} -#endif /* CONFIG_HAVE_RTC */ - -#ifdef CONFIG_HAVE_TSC -/* read time stamp counter (TSC), count of ticks from processor reset. - * - * NB: On Windows this will usually be HPET or PIC timer interpolated with TSC. - */ - -static inline -pgm_time_t -rdtsc (void) -{ -# ifndef _WIN32 - uint32_t lo, hi; - -/* We cannot use "=A", since this would use %rax on x86_64 */ - asm volatile ("rdtsc" : "=a" (lo), "=d" (hi)); - - return (pgm_time_t)hi << 32 | lo; -# else - uint64_t counter; - QueryPerformanceCounter ((LARGE_INTEGER*)&counter); - return (pgm_time_t)counter; -# endif -} - -# ifndef _WIN32 -/* determine ratio of ticks to nano-seconds, use /dev/rtc for high accuracy - * millisecond timer and convert. - * - * WARNING: time is relative to start of timer. - */ - -static -bool -pgm_tsc_init ( - PGM_GNUC_UNUSED pgm_error_t** error - ) -{ -# ifdef CONFIG_HAVE_PROC -/* Test for constant TSC from kernel - */ - FILE* fp = fopen ("/proc/cpuinfo", "r"); - char buffer[1024], *flags = NULL; - if (fp) - { - while (!feof(fp) && fgets (buffer, sizeof(buffer), fp)) - { - if (strstr (buffer, "flags")) - { - flags = strchr (buffer, ':'); - break; - } - } - fclose (fp); - } - if (!flags || !strstr (flags, " tsc")) { - pgm_warn (_("Linux kernel reports no Time Stamp Counter (TSC).")); -/* force both to stable clocks even though one might be OK */ - pgm_time_update_now = pgm_gettimeofday_update; - return TRUE; - } - if (!strstr (flags, " constant_tsc")) { - pgm_warn (_("Linux kernel reports non-constant Time Stamp Counter (TSC).")); -/* force both to stable clocks even though one might be OK */ - pgm_time_update_now = pgm_gettimeofday_update; - return TRUE; - } -# endif /* CONFIG_HAVE_PROC */ - pgm_time_t start, stop; - const pgm_time_t calibration_usec = secs_to_usecs (4); - - pgm_info (_("Running a benchmark to measure system clock frequency...")); - - struct timespec req = { - .tv_sec = 4, - .tv_nsec = 0 - }; - start = rdtsc(); - while (-1 == nanosleep (&req, &req) && EINTR == errno); - stop = rdtsc(); - - if (stop < start) - { - pgm_warn (_("Finished RDTSC test. Unstable TSC detected. The benchmark resulted in a " - "non-monotonic time response rendering the TSC unsuitable for high resolution " - "timing. To prevent the start delay from this benchmark and use a stable clock " - "source set the environment variable PGM_TIMER to GTOD.")); -/* force both to stable clocks even though one might be OK */ - pgm_time_update_now = pgm_gettimeofday_update; - return TRUE; - } - -/* TODO: this math needs to be scaled to reduce rounding errors */ - const pgm_time_t tsc_diff = stop - start; - if (tsc_diff > calibration_usec) { -/* cpu > 1 Ghz */ - tsc_mhz = tsc_diff / calibration_usec; - } else { -/* cpu < 1 Ghz */ - tsc_mhz = -( calibration_usec / tsc_diff ); - } - - pgm_info (_("Finished RDTSC test. To prevent the startup delay from this benchmark, " - "set the environment variable RDTSC_FREQUENCY to %" PRIuFAST32 " on this " - "system. This value is dependent upon the CPU clock speed and " - "architecture and should be determined separately for each server."), - tsc_mhz); - return TRUE; -} -# endif - -/* TSC is monotonic on the same core but we do neither force the same core or save the count - * for each core as if the counter is unstable system wide another timing mechanism should be - * used, preferably HPET on x86/AMD64 or gettimeofday() on SPARC. - */ - -static -pgm_time_t -pgm_tsc_update (void) -{ - static pgm_time_t last = 0; - const pgm_time_t now = tsc_to_us (rdtsc()); - if (PGM_UNLIKELY(now < last)) - return last; - else - return last = now; -} -#endif - -#ifdef CONFIG_HAVE_HPET -/* High Precision Event Timer (HPET) created as a system wide stable high resolution timer - * to replace dependency on core specific counters (TSC). - * - * NB: Only available on x86/AMD64 hardware post 2007 - */ - -static -bool -pgm_hpet_init ( - pgm_error_t** error - ) -{ - pgm_return_val_if_fail (hpet_fd == -1, FALSE); - - hpet_fd = open("/dev/hpet", O_RDONLY); - if (hpet_fd < 0) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_TIME, - PGM_ERROR_FAILED, - _("Cannot open /dev/hpet for reading: %s"), - strerror(errno)); - return FALSE; - } - - hpet_ptr = mmap(NULL, HPET_MMAP_SIZE, PROT_READ, MAP_SHARED, hpet_fd, 0); - if (MAP_FAILED == hpet_ptr) { - pgm_set_error (error, - PGM_ERROR_DOMAIN_TIME, - PGM_ERROR_FAILED, - _("Error mapping HPET device: %s"), - strerror(errno)); - close (hpet_fd); - hpet_fd = -1; - return FALSE; - } - -/* HPET counter tick period is in femto-seconds, a value of 0 is not permitted, - * the value must be <= 0x05f5e100 or 100ns. - */ - const uint32_t hpet_period = *((uint32_t*)(hpet_ptr + HPET_COUNTER_CLK_PERIOD)); - set_hpet_mul (hpet_period); -#if defined( __x86_64__ ) || defined( __amd64 ) - const uint32_t hpet_caps = *((uint32_t*)(hpet_ptr + HPET_GENERAL_CAPS_REGISTER)); - hpet_wrap = hpet_caps & HPET_COUNT_SIZE_CAP ? 0 : (1ULL << 32); -#else - hpet_wrap = 1ULL << 32; -#endif - - return TRUE; -} - -static -bool -pgm_hpet_shutdown (void) -{ - pgm_return_val_if_fail (hpet_fd, FALSE); - pgm_warn_if_fail (0 == close (hpet_fd)); - hpet_fd = -1; - return TRUE; -} - -static -pgm_time_t -pgm_hpet_update (void) -{ - const hpet_counter_t hpet_count = *((hpet_counter_t*)(hpet_ptr + HPET_MAIN_COUNTER_REGISTER)); -/* 32-bit HPET counters wrap after ~4 minutes */ - if (PGM_UNLIKELY(hpet_count < hpet_last)) - hpet_offset += hpet_wrap; - hpet_last = hpet_count; - return hpet_to_us (hpet_offset + hpet_count); -} -#endif /* CONFIG_HAVE_HPET */ - -/* convert from pgm_time_t to time_t with pgm_time_t in microseconds since the epoch. - */ -static -void -pgm_time_conv ( - const pgm_time_t* const restrict pgm_time_t_time, - time_t* restrict time_t_time - ) -{ - *time_t_time = pgm_to_secs (*pgm_time_t_time); -} - -/* convert from pgm_time_t to time_t with pgm_time_t in microseconds since the core started. - */ -static -void -pgm_time_conv_from_reset ( - const pgm_time_t* const restrict pgm_time_t_time, - time_t* restrict time_t_time - ) -{ - *time_t_time = pgm_to_secs (*pgm_time_t_time + rel_offset); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/time_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/time_unittest.c deleted file mode 100644 index fd28572..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/time_unittest.c +++ /dev/null @@ -1,188 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for high resolution timers. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include - - -/* mock state */ - - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - - -#include "time.c" - - -/* target: - * boolean - * pgm_time_init (pgm_error_t** error) - */ - -/* time initialisation uses reference counting */ - -START_TEST (test_init_pass_001) -{ - fail_unless (TRUE == pgm_time_init (NULL), "init #1 failed"); - fail_unless (TRUE == pgm_time_init (NULL), "init #2 failed"); -} -END_TEST - -/* target: - * bool - * pgm_time_shutdown (void) - */ - -START_TEST (test_shutdown_pass_001) -{ - fail_unless (TRUE == pgm_time_init (NULL), "init failed"); - fail_unless (TRUE == pgm_time_shutdown (), "shutdown #1 failed"); - fail_unless (FALSE == pgm_time_shutdown (), "shutdown #2 failed"); -} -END_TEST - -START_TEST (test_shutdown_pass_002) -{ - fail_unless (TRUE == pgm_time_init (NULL), "init #1 failed"); - fail_unless (TRUE == pgm_time_init (NULL), "init #2 failed"); - fail_unless (TRUE == pgm_time_shutdown (), "shutdown #1 failed"); - fail_unless (TRUE == pgm_time_shutdown (), "shutdown #2 failed"); - fail_unless (FALSE == pgm_time_shutdown (), "shutdown #3 failed"); -} -END_TEST - -/* target: - * pgm_time_t - * pgm_time_update_now (void) - */ - -START_TEST (test_update_now_pass_001) -{ - pgm_time_t tstamps[11]; - fail_unless (TRUE == pgm_time_init (NULL), "init failed"); - const pgm_time_t start_time = pgm_time_update_now (); - for (unsigned i = 1; i <= 10; i++) - { - tstamps[i] = pgm_time_update_now(); - } - g_message ("start-time: %" PGM_TIME_FORMAT, start_time); - for (unsigned i = 1; i <= 10; i++) - { - const pgm_time_t check_time = tstamps[i]; - const gint64 elapsed_time = check_time - start_time; - -/* must be monotonic */ - fail_unless (G_LIKELY(check_time >= start_time), "non-monotonic"); - - g_message ("check-point-%2.2u: %" PGM_TIME_FORMAT " (%+" G_GINT64_FORMAT "us)", - i, check_time, pgm_to_usecs(elapsed_time)); - } - fail_unless (TRUE == pgm_time_shutdown (), "shutdown failed"); -} -END_TEST - -/* target: - * void - * pgm_time_since_epoch ( - * pgm_time_t* pgm_time, - * time_t* epoch_time - * ) - */ - -START_TEST (test_since_epoch_pass_001) -{ - char stime[1024]; - time_t t; - struct tm* tmp; - fail_unless (TRUE == pgm_time_init (NULL), "init failed"); - pgm_time_t pgm_now = pgm_time_update_now (); - pgm_time_since_epoch (&pgm_now, &t); - tmp = localtime (&t); - fail_unless (NULL != tmp, "localtime failed"); - fail_unless (0 != strftime (stime, sizeof(stime), "%X", tmp), "strftime failed"); - g_message ("pgm-time:%" PGM_TIME_FORMAT " = %s", - pgm_now, stime); - fail_unless (TRUE == pgm_time_shutdown (), "shutdown failed"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_init = tcase_create ("init"); - suite_add_tcase (s, tc_init); - tcase_add_test (tc_init, test_init_pass_001); - - TCase* tc_shutdown = tcase_create ("shutdown"); - suite_add_tcase (s, tc_shutdown); - tcase_add_test (tc_shutdown, test_shutdown_pass_001); - tcase_add_test (tc_shutdown, test_shutdown_pass_002); - - TCase* tc_update_now = tcase_create ("update-now"); - suite_add_tcase (s, tc_update_now); - tcase_add_test (tc_update_now, test_update_now_pass_001); - - TCase* tc_since_epoch = tcase_create ("since-epoch"); - suite_add_tcase (s, tc_since_epoch); - tcase_add_test (tc_since_epoch, test_since_epoch_pass_001); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/timer.c b/3rdparty/openpgm-svn-r1085/pgm/timer.c deleted file mode 100644 index 3bee14c..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/timer.c +++ /dev/null @@ -1,223 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * PGM timer thread. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include -#include -#include - - -//#define TIMER_DEBUG - - -/* determine which timer fires next: spm (ihb_tmr), nak_rb_ivl, nak_rpt_ivl, or nak_rdata_ivl - * and check whether its already due. - * - * called in sock creation so locks unrequired. - */ - -bool -pgm_timer_prepare ( - pgm_sock_t* const sock - ) -{ - int32_t msec; - -/* pre-conditions */ - pgm_assert (NULL != sock); - pgm_assert (sock->can_send_data || sock->can_recv_data); - - pgm_time_t now = pgm_time_update_now(); - pgm_time_t expiration; - - if (sock->can_send_data) - expiration = sock->next_ambient_spm; - else - expiration = now + sock->peer_expiry; - - sock->next_poll = expiration; - -/* advance time again to adjust for processing time out of the event loop, this - * could cause further timers to expire even before checking for new wire data. - */ - msec = pgm_to_msecs ((int64_t)expiration - (int64_t)now); - if (msec < 0) - msec = 0; - else - msec = MIN (INT32_MAX, msec); - pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiration in %" PRIi32 "ms"), msec); - return (msec == 0); -} - -bool -pgm_timer_check ( - pgm_sock_t* const sock - ) -{ - const pgm_time_t now = pgm_time_update_now(); - bool expired; - -/* pre-conditions */ - pgm_assert (NULL != sock); - - pgm_timer_lock (sock); - expired = pgm_time_after_eq (now, sock->next_poll); - pgm_timer_unlock (sock); - return expired; -} - -/* return next timer expiration in microseconds (μs) - */ - -pgm_time_t -pgm_timer_expiration ( - pgm_sock_t* const sock - ) -{ - const pgm_time_t now = pgm_time_update_now(); - pgm_time_t expiration; - -/* pre-conditions */ - pgm_assert (NULL != sock); - - pgm_timer_lock (sock); - expiration = pgm_time_after (sock->next_poll, now) ? pgm_to_usecs (sock->next_poll - now) : 0; - pgm_timer_unlock (sock); - return expiration; -} - -/* call all timers, assume that time_now has been updated by either pgm_timer_prepare - * or pgm_timer_check and no other method calls here. - * - * returns TRUE on success, returns FALSE on blocked send-in-receive operation. - */ - -bool -pgm_timer_dispatch ( - pgm_sock_t* const sock - ) -{ - const pgm_time_t now = pgm_time_update_now(); - pgm_time_t next_expiration = 0; - -/* pre-conditions */ - pgm_assert (NULL != sock); - - pgm_debug ("pgm_timer_dispatch (sock:%p)", (const void*)sock); - -/* find which timers have expired and call each */ - if (sock->can_recv_data) - { - if (!pgm_check_peer_state (sock, now)) - return FALSE; - next_expiration = pgm_min_receiver_expiry (now + sock->peer_expiry, sock); - } - - if (sock->can_send_data) - { -/* reset congestion control on ACK timeout */ - if (sock->use_pgmcc && - sock->tokens < pgm_fp8 (1) && - 0 != sock->ack_expiry) - { - if (pgm_time_after_eq (now, sock->ack_expiry)) - { -#ifdef DEBUG_PGMCC -char nows[1024]; -time_t t = time (NULL); -struct tm* tmp = localtime (&t); -strftime (nows, sizeof(nows), "%Y-%m-%d %H:%M:%S", tmp); -printf ("ACK timeout, T:%u W:%u\n", pgm_fp8tou(sock->tokens), pgm_fp8tou(sock->cwnd_size)); -#endif - sock->tokens = sock->cwnd_size = pgm_fp8 (1); - sock->ack_bitmap = 0xffffffff; - sock->ack_expiry = 0; - -/* notify blocking tx thread that transmission time is now available */ - pgm_notify_send (&sock->ack_notify); - } - next_expiration = next_expiration > 0 ? MIN(next_expiration, sock->ack_expiry) : sock->ack_expiry; - } - -/* SPM broadcast */ - pgm_mutex_lock (&sock->timer_mutex); - const unsigned spm_heartbeat_state = sock->spm_heartbeat_state; - const pgm_time_t next_heartbeat_spm = sock->next_heartbeat_spm; - pgm_mutex_unlock (&sock->timer_mutex); - -/* no lock needed on ambient */ - const pgm_time_t next_ambient_spm = sock->next_ambient_spm; - pgm_time_t next_spm = spm_heartbeat_state ? MIN(next_heartbeat_spm, next_ambient_spm) : next_ambient_spm; - - if (pgm_time_after_eq (now, next_spm) && - !pgm_send_spm (sock, 0)) - return FALSE; - -/* ambient timing not so important so base next event off current time */ - if (pgm_time_after_eq (now, next_ambient_spm)) - { - sock->next_ambient_spm = now + sock->spm_ambient_interval; - next_spm = spm_heartbeat_state ? MIN(next_heartbeat_spm, sock->next_ambient_spm) : sock->next_ambient_spm; - } - -/* heartbeat timing is often high resolution so base times to last event */ - if (spm_heartbeat_state && pgm_time_after_eq (now, next_heartbeat_spm)) - { - unsigned new_heartbeat_state = spm_heartbeat_state; - pgm_time_t new_heartbeat_spm = next_heartbeat_spm; - do { - new_heartbeat_spm += sock->spm_heartbeat_interval[new_heartbeat_state++]; - if (new_heartbeat_state == sock->spm_heartbeat_len) { - new_heartbeat_state = 0; - new_heartbeat_spm = now + sock->spm_ambient_interval; - break; - } - } while (pgm_time_after_eq (now, new_heartbeat_spm)); -/* check for reset heartbeat */ - pgm_mutex_lock (&sock->timer_mutex); - if (next_heartbeat_spm == sock->next_heartbeat_spm) { - sock->spm_heartbeat_state = new_heartbeat_state; - sock->next_heartbeat_spm = new_heartbeat_spm; - next_spm = MIN(sock->next_ambient_spm, new_heartbeat_spm); - } else - next_spm = MIN(sock->next_ambient_spm, sock->next_heartbeat_spm); - sock->next_poll = next_expiration > 0 ? MIN(next_expiration, next_spm) : next_spm; - pgm_mutex_unlock (&sock->timer_mutex); - return TRUE; - } - - next_expiration = next_expiration > 0 ? MIN(next_expiration, next_spm) : next_spm; - -/* check for reset */ - pgm_mutex_lock (&sock->timer_mutex); - sock->next_poll = sock->next_poll > now ? MIN(sock->next_poll, next_expiration) : next_expiration; - pgm_mutex_unlock (&sock->timer_mutex); - } - else - sock->next_poll = next_expiration; - - return TRUE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/timer_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/timer_unittest.c deleted file mode 100644 index 2e48802..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/timer_unittest.c +++ /dev/null @@ -1,355 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for PGM timer thread. - * - * Copyright (c) 2009-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include - - -/* mock state */ - - -#define g_main_context_new mock_g_main_context_new -#define g_main_context_unref mock_g_main_context_unref -#define g_main_loop_new mock_g_main_loop_new -#define g_main_loop_run mock_g_main_loop_run -#define g_main_loop_unref mock_g_main_loop_unref -#define g_source_new mock_g_source_new -#define g_source_set_priority mock_g_source_set_priority -#define g_source_attach mock_g_source_attach -#define g_source_unref mock_g_source_unref -#define pgm_time_now mock_pgm_time_now -#define pgm_time_update_now mock_pgm_time_update_now -#define pgm_min_receiver_expiry mock_pgm_min_receiver_expiry -#define pgm_check_peer_state mock_pgm_check_peer_state -#define pgm_send_spm mock_pgm_send_spm - - -#define TIMER_DEBUG -#include "timer.c" - -static pgm_time_t _mock_pgm_time_update_now(void); -pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; -static pgm_time_t mock_pgm_time_now = 0x1; - - -static -pgm_sock_t* -generate_sock (void) -{ - pgm_sock_t* sock = g_new0 (pgm_sock_t, 1); - return sock; -} - - -/* mock functions for external references */ - -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return 0; -} - -/** GLib */ -static -GMainContext* -mock_g_main_context_new (void) -{ - GMainContext* context = g_malloc0 (sizeof(gpointer)); - return context; -} - -static -GMainLoop* -mock_g_main_loop_new ( - GMainContext* context, - gboolean is_running - ) -{ - g_assert (NULL != context); - GMainLoop* loop = g_malloc0 (sizeof(gpointer)); - return loop; -} - -static -void -mock_g_main_loop_run ( - GMainLoop* loop - ) -{ - g_assert (NULL != loop); -} - -static -void -mock_g_main_loop_unref ( - GMainLoop* loop - ) -{ - g_assert (NULL != loop); - g_free (loop); -} - -static -void -mock_g_main_context_unref ( - GMainContext* context - ) -{ - g_assert (NULL != context); - g_free (context); -} - -static -GSource* -mock_g_source_new ( - GSourceFuncs* source_funcs, - guint struct_size - ) -{ - g_assert (struct_size > 0); - GSource* source = g_malloc0 (struct_size); - return source; -} - -static -void -mock_g_source_set_priority ( - GSource* source, - gint priority - ) -{ - g_assert (NULL != source); -} - -static -guint -mock_g_source_attach ( - GSource* source, - GMainContext* context - ) -{ - g_assert (NULL != source); - return 1; -} - -static -void -mock_g_source_unref ( - GSource* source - ) -{ - g_assert (NULL != source); - g_free (source); -} - -/** time module */ -static -pgm_time_t -_mock_pgm_time_update_now (void) -{ - return mock_pgm_time_now; -} - -/** receiver module */ -PGM_GNUC_INTERNAL -pgm_time_t -mock_pgm_min_receiver_expiry ( - pgm_time_t expiration, - pgm_sock_t* sock - ) -{ - g_assert (NULL != sock); - return 0x1; -} - -PGM_GNUC_INTERNAL -bool -mock_pgm_check_peer_state ( - pgm_sock_t* sock, - pgm_time_t now - ) -{ - g_assert (NULL != sock); - return TRUE; -} - -/** source module */ -PGM_GNUC_INTERNAL -bool -mock_pgm_send_spm ( - pgm_sock_t* sock, - int flags - ) -{ - g_assert (NULL != sock); - return TRUE; -} - - -/* target: - * bool - * pgm_timer_prepare ( - * pgm_sock_t* sock - * ) - */ - -START_TEST (test_prepare_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->can_send_data = TRUE; - sock->next_ambient_spm = mock_pgm_time_now + pgm_secs(10); - fail_unless (FALSE == pgm_timer_prepare (sock), "prepare failed"); -} -END_TEST - -START_TEST (test_prepare_fail_001) -{ - gboolean expired = pgm_timer_prepare (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_timer_check ( - * pgm_sock_t* sock - * ) - */ - -START_TEST (test_check_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - fail_unless (TRUE == pgm_timer_check (sock), "check failed"); -} -END_TEST - -START_TEST (test_check_fail_001) -{ - gboolean expired = pgm_timer_check (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * pgm_time_t - * pgm_timer_expiration ( - * pgm_sock_t* sock - * ) - */ - -START_TEST (test_expiration_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - sock->next_poll = mock_pgm_time_now + pgm_secs(300); - fail_unless (pgm_secs(300) == pgm_timer_expiration (sock), "expiration failed"); -} -END_TEST - -START_TEST (test_expiration_fail_001) -{ - long expiration = pgm_timer_expiration (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_timer_dispatch ( - * pgm_sock_t* sock - * ) - */ - -START_TEST (test_dispatch_pass_001) -{ - pgm_sock_t* sock = generate_sock (); - fail_if (NULL == sock, "generate_sock failed"); - pgm_timer_dispatch (sock); -} -END_TEST - -START_TEST (test_dispatch_fail_001) -{ - pgm_timer_dispatch (NULL); - fail ("reached"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_prepare = tcase_create ("prepare"); - suite_add_tcase (s, tc_prepare); - tcase_add_test (tc_prepare, test_prepare_pass_001); - tcase_add_test_raise_signal (tc_prepare, test_prepare_fail_001, SIGABRT); - - TCase* tc_check = tcase_create ("check"); - suite_add_tcase (s, tc_check); - tcase_add_test (tc_check, test_check_pass_001); - tcase_add_test_raise_signal (tc_check, test_check_fail_001, SIGABRT); - - TCase* tc_expiration = tcase_create ("expiration"); - suite_add_tcase (s, tc_expiration); - tcase_add_test (tc_expiration, test_expiration_pass_001); - tcase_add_test_raise_signal (tc_expiration, test_expiration_fail_001, SIGABRT); - - TCase* tc_dispatch = tcase_create ("dispatch"); - suite_add_tcase (s, tc_dispatch); - tcase_add_test (tc_dispatch, test_dispatch_pass_001); - tcase_add_test_raise_signal (tc_dispatch, test_dispatch_fail_001, SIGABRT); - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/token and leaky bucket.txt b/3rdparty/openpgm-svn-r1085/pgm/token and leaky bucket.txt deleted file mode 100644 index 3efb9c7..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/token and leaky bucket.txt +++ /dev/null @@ -1,12 +0,0 @@ -leaky bucket: - - if (BUCKET->rate_limit > BUCKET->rate_per_sec) - BUCKET->rate_limit = BUCKET->rate_per_sec; - - -token bucket: - - guint bucket_limit; - - if (BUCKET->rate_limit > BUCKET->bucket_limit) - BUCKET->rate_limit = BUCKET->bucket_limit; diff --git a/3rdparty/openpgm-svn-r1085/pgm/tsi.c b/3rdparty/openpgm-svn-r1085/pgm/tsi.c deleted file mode 100644 index 5f9ae85..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/tsi.c +++ /dev/null @@ -1,119 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * transport session ID helper functions. - * - * Copyright (c) 2006-2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - - -//#define TSI_DEBUG - - -/* locals */ - - -/* re-entrant form of pgm_tsi_print() - * - * returns number of bytes written to buffer on success, returns -1 on - * invalid parameters. - */ - -int -pgm_tsi_print_r ( - const pgm_tsi_t* restrict tsi, - char* restrict buf, - size_t bufsize - ) -{ - pgm_return_val_if_fail (NULL != tsi, -1); - pgm_return_val_if_fail (NULL != buf, -1); - pgm_return_val_if_fail (bufsize > 0, -1); - - const uint8_t* gsi = (const uint8_t*)tsi; - const uint16_t source_port = tsi->sport; - - return snprintf (buf, bufsize, "%i.%i.%i.%i.%i.%i.%i", - gsi[0], gsi[1], gsi[2], gsi[3], gsi[4], gsi[5], ntohs (source_port)); -} - -/* transform TSI to ASCII string form. - * - * on success, returns pointer to ASCII string. on error, returns NULL. - */ - -char* -pgm_tsi_print ( - const pgm_tsi_t* tsi - ) -{ - pgm_return_val_if_fail (tsi != NULL, NULL); - - static char buf[PGM_TSISTRLEN]; - pgm_tsi_print_r (tsi, buf, sizeof(buf)); - return buf; -} - -/* create hash value of TSI for use with GLib hash tables. - * - * on success, returns a hash value corresponding to the TSI. on error, fails - * on assert. - */ - -pgm_hash_t -pgm_tsi_hash ( - const void* p - ) -{ - const union { - pgm_tsi_t tsi; - uint32_t l[2]; - } *u = p; - -/* pre-conditions */ - pgm_assert (NULL != p); - - return u->l[0] ^ u->l[1]; -} - -/* compare two transport session identifier TSI values. - * - * returns TRUE if they are equal, FALSE if they are not. - */ - -bool -pgm_tsi_equal ( - const void* restrict p1, - const void* restrict p2 - ) -{ - const union { - pgm_tsi_t tsi; - uint32_t l[2]; - uint64_t ll; - } *restrict u1 = p1, *restrict u2 = p2; - -/* pre-conditions */ - pgm_assert (NULL != p1); - pgm_assert (NULL != p2); - - return (u1->l[0] == u2->l[0] && u1->l[1] == u2->l[1]); -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/tsi_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/tsi_unittest.c deleted file mode 100644 index fddff25..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/tsi_unittest.c +++ /dev/null @@ -1,185 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for transport session ID helper functions. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include -#include -#include -#include -#include -#include -#include - - -/* mock state */ - -/* mock functions for external references */ - -size_t -pgm_transport_pkt_offset2 ( - const bool can_fragment, - const bool use_pgmcc - ) -{ - return 0; -} - - -#define TSI_DEBUG -#include "tsi.c" - - -/* target: - * gchar* - * pgm_tsi_print ( - * const pgm_tsi_t* tsi - * ) - */ - -START_TEST (test_print_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - fail_if (NULL == pgm_tsi_print (&tsi), "print failed"); -} -END_TEST - -START_TEST (test_print_pass_002) -{ - fail_unless (NULL == pgm_tsi_print (NULL), "print failed"); -} -END_TEST - -/* target: - * int - * pgm_tsi_print_r ( - * const pgm_tsi_t* tsi, - * char* buf, - * gsize bufsize - * ) - */ - -START_TEST (test_print_r_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - char buf[PGM_TSISTRLEN]; - fail_unless (pgm_tsi_print_r (&tsi, buf, sizeof(buf)) > 0, "print_r failed"); -} -END_TEST - -START_TEST (test_print_r_pass_002) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - char buf[PGM_TSISTRLEN]; - fail_unless (pgm_tsi_print_r (NULL, buf, sizeof(buf)) == -1, "print_r failed"); - fail_unless (pgm_tsi_print_r (&tsi, NULL, sizeof(buf)) == -1, "print_r failed"); - fail_unless (pgm_tsi_print_r (&tsi, buf, 0) == -1, "print_r failed"); -} -END_TEST - -/* target: - * gboolean - * pgm_tsi_equal ( - * gconstpointer tsi1, - * gconstpointer tsi2 - * ) - */ - -START_TEST (test_equal_pass_001) -{ - const pgm_tsi_t tsi1 = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const pgm_tsi_t tsi2 = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - fail_unless (pgm_tsi_equal (&tsi1, &tsi2), "equal failed"); -} -END_TEST - -START_TEST (test_equal_pass_002) -{ - const pgm_tsi_t tsi1 = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const pgm_tsi_t tsi2 = { { 9, 8, 7, 6, 5, 4 }, 2000 }; - fail_if (pgm_tsi_equal (&tsi1, &tsi2), "equal failed"); -} -END_TEST - -START_TEST (test_equal_fail_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - gboolean retval = pgm_tsi_equal (NULL, &tsi); - fail ("reached"); -} -END_TEST - -START_TEST (test_equal_fail_002) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - gboolean retval = pgm_tsi_equal (&tsi, NULL); - fail ("reached"); -} -END_TEST - - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_print = tcase_create ("print"); - suite_add_tcase (s, tc_print); - tcase_add_test (tc_print, test_print_pass_001); - tcase_add_test (tc_print, test_print_pass_002); - - TCase* tc_print_r = tcase_create ("print-r"); - suite_add_tcase (s, tc_print_r); - tcase_add_test (tc_print_r, test_print_r_pass_001); - tcase_add_test (tc_print_r, test_print_r_pass_002); - - TCase* tc_equal = tcase_create ("equal"); - suite_add_tcase (s, tc_equal); - tcase_add_test (tc_equal, test_equal_pass_001); - tcase_add_test (tc_equal, test_equal_pass_002); - tcase_add_test_raise_signal (tc_equal, test_equal_fail_001, SIGABRT); - tcase_add_test_raise_signal (tc_equal, test_equal_fail_002, SIGABRT); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/txw.c b/3rdparty/openpgm-svn-r1085/pgm/txw.c deleted file mode 100644 index e2487ae..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/txw.c +++ /dev/null @@ -1,763 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * A basic transmit window: pointer array implementation. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include - - -//#define TXW_DEBUG - -#ifndef TXW_DEBUG -# define PGM_DISABLE_ASSERT -#endif - - -/* testing function: is TSI null - * - * returns TRUE if null, returns FALSE if not null. - */ - -static inline -bool -pgm_tsi_is_null ( - const void*const tsi - ) -{ - const union { - pgm_tsi_t tsi; - uint32_t l[2]; - } *u = tsi; - -/* pre-conditions */ - pgm_assert (NULL != tsi); - - return (0 == u->l[0] && 0 == u->l[1]); -} - -/* returns the pointer at the given index of the window. responsibility - * is with the caller to verify a single user ownership. - */ - -static inline -struct pgm_sk_buff_t* -_pgm_txw_peek ( - const pgm_txw_t*const window, - const uint32_t sequence - ) -{ - struct pgm_sk_buff_t* skb; - -/* pre-conditions */ - pgm_assert (NULL != window); - - if (pgm_txw_is_empty (window)) - return NULL; - - if (pgm_uint32_gte (sequence, window->trail) && pgm_uint32_lte (sequence, window->lead)) - { - const uint_fast32_t index_ = sequence % pgm_txw_max_length (window); - skb = window->pdata[index_]; - pgm_assert (NULL != skb); - pgm_assert (pgm_skb_is_valid (skb)); - pgm_assert (pgm_tsi_is_null (&skb->tsi)); - } - else - skb = NULL; - - return skb; -} - -/* testing function: can a request be peeked from the retransmit queue. - * - * returns TRUE if request is available, returns FALSE if not available. - */ - -static inline -bool -pgm_txw_retransmit_can_peek ( - pgm_txw_t*const window - ) -{ - pgm_return_val_if_fail (NULL != window, FALSE); - return (NULL != pgm_txw_retransmit_try_peek (window)); -} - -/* sequence state must be smaller than PGM skbuff control buffer */ -PGM_STATIC_ASSERT(sizeof(struct pgm_txw_state_t) <= sizeof(((struct pgm_sk_buff_t*)0)->cb)); - -uint32_t -pgm_txw_get_unfolded_checksum ( - const struct pgm_sk_buff_t*const skb - ) -{ - const pgm_txw_state_t*const state = (const pgm_txw_state_t*const)&skb->cb; - return state->unfolded_checksum; -} - -void -pgm_txw_set_unfolded_checksum ( - struct pgm_sk_buff_t*const skb, - const uint32_t csum - ) -{ - pgm_txw_state_t* state = (pgm_txw_state_t*)&skb->cb; - state->unfolded_checksum = csum; -} - -void -pgm_txw_inc_retransmit_count ( - struct pgm_sk_buff_t*const skb - ) -{ - pgm_txw_state_t*const state = (pgm_txw_state_t*const)&skb->cb; - state->retransmit_count++; -} - -bool -pgm_txw_retransmit_is_empty ( - const pgm_txw_t*const window - ) -{ - pgm_assert (NULL != window); - return pgm_queue_is_empty (&window->retransmit_queue); -} - - -/* globals */ - -static void pgm_txw_remove_tail (pgm_txw_t*const); -static bool pgm_txw_retransmit_push_parity (pgm_txw_t*const, const uint32_t, const uint8_t); -static bool pgm_txw_retransmit_push_selective (pgm_txw_t*const, const uint32_t); - - -/* constructor for transmit window. zero-length windows are not permitted. - * - * returns pointer to window. - */ - -pgm_txw_t* -pgm_txw_create ( - const pgm_tsi_t*const tsi, - const uint16_t tpdu_size, - const uint32_t sqns, /* transmit window size in sequence numbers */ - const unsigned secs, /* size in seconds */ - const ssize_t max_rte, /* max bandwidth */ - const bool use_fec, - const uint8_t rs_n, - const uint8_t rs_k - ) -{ - pgm_txw_t* window; - -/* pre-conditions */ - pgm_assert (NULL != tsi); - if (sqns) { - pgm_assert_cmpuint (tpdu_size, ==, 0); - pgm_assert_cmpuint (sqns, >, 0); - pgm_assert_cmpuint (sqns & PGM_UINT32_SIGN_BIT, ==, 0); - pgm_assert_cmpuint (secs, ==, 0); - pgm_assert_cmpuint (max_rte, ==, 0); - } else { - pgm_assert_cmpuint (tpdu_size, >, 0); - pgm_assert_cmpuint (secs, >, 0); - pgm_assert_cmpuint (max_rte, >, 0); - } - if (use_fec) { - pgm_assert_cmpuint (rs_n, >, 0); - pgm_assert_cmpuint (rs_k, >, 0); - } - - pgm_debug ("create (tsi:%s max-tpdu:%" PRIu16 " sqns:%" PRIu32 " secs %u max-rte %zd use-fec:%s rs(n):%u rs(k):%u)", - pgm_tsi_print (tsi), - tpdu_size, sqns, secs, max_rte, - use_fec ? "YES" : "NO", - rs_n, rs_k); - -/* calculate transmit window parameters */ - pgm_assert (sqns || (tpdu_size && secs && max_rte)); - const unsigned alloc_sqns = sqns ? sqns : ( (secs * max_rte) / tpdu_size ); - window = pgm_malloc0 (sizeof(pgm_txw_t) + ( alloc_sqns * sizeof(struct pgm_sk_buff_t*) )); - window->tsi = tsi; - -/* empty state for transmission group boundaries to align. - * - * trail = 0, lead = -1 - */ - window->lead = -1; - window->trail = window->lead + 1; - -/* reed-solomon forward error correction */ - if (use_fec) { - window->parity_buffer = pgm_alloc_skb (tpdu_size); - window->tg_sqn_shift = pgm_power2_log2 (rs_k); - pgm_rs_create (&window->rs, rs_n, rs_k); - window->is_fec_enabled = 1; - } - -/* pointer array */ - window->alloc = alloc_sqns; - -/* post-conditions */ - pgm_assert_cmpuint (pgm_txw_max_length (window), ==, alloc_sqns); - pgm_assert_cmpuint (pgm_txw_length (window), ==, 0); - pgm_assert_cmpuint (pgm_txw_size (window), ==, 0); - pgm_assert (pgm_txw_is_empty (window)); - pgm_assert (!pgm_txw_is_full (window)); - pgm_assert (!pgm_txw_retransmit_can_peek (window)); - - return window; -} - -/* destructor for transmit window. must not be called more than once for same window. - */ - -void -pgm_txw_shutdown ( - pgm_txw_t*const window - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert_cmpuint (window->alloc, >, 0); - - pgm_debug ("shutdown (window:%p)", (const void*)window); - -/* contents of window */ - while (!pgm_txw_is_empty (window)) { - pgm_txw_remove_tail (window); - } - -/* window must now be empty */ - pgm_assert_cmpuint (pgm_txw_length (window), ==, 0); - pgm_assert_cmpuint (pgm_txw_size (window), ==, 0); - pgm_assert (pgm_txw_is_empty (window)); - pgm_assert (!pgm_txw_is_full (window)); - -/* retransmit queue must be empty */ - pgm_assert (!pgm_txw_retransmit_can_peek (window)); - -/* free reed-solomon state */ - if (window->is_fec_enabled) { - pgm_free_skb (window->parity_buffer); - pgm_rs_destroy (&window->rs); - } - -/* window */ - pgm_free (window); -} - -/* add skb to transmit window, taking ownership. window does not grow. - * PGM skbuff data/tail pointers must point to the PGM payload, and hence skb->len - * is allowed to be zero. - * - * side effects: - * - * 1) sequence number is set in skb. - * 2) window is updated with new skb. - * - * no return value. fatal error raised on invalid parameters. if window is full then - * an entry is dropped to fulfil the request. - * - * it is an error to try to free the skb after adding to the window. - */ - -void -pgm_txw_add ( - pgm_txw_t* const restrict window, - struct pgm_sk_buff_t* const restrict skb /* cannot be NULL */ - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (NULL != skb); - pgm_assert_cmpuint (pgm_txw_max_length (window), >, 0); - pgm_assert (pgm_skb_is_valid (skb)); - pgm_assert (((const pgm_list_t*)skb)->next == NULL); - pgm_assert (((const pgm_list_t*)skb)->prev == NULL); - pgm_assert (pgm_tsi_is_null (&skb->tsi)); - pgm_assert ((char*)skb->data > (char*)skb->head); - pgm_assert ((sizeof(struct pgm_header) + sizeof(struct pgm_data)) <= (size_t)((char*)skb->data - (char*)skb->head)); - - pgm_debug ("add (window:%p skb:%p)", (const char*)window, (const char*)skb); - - if (pgm_txw_is_full (window)) - { -/* transmit window advancement scheme dependent action here */ - pgm_txw_remove_tail (window); - } - -/* generate new sequence number */ - pgm_atomic_inc32 (&window->lead); - skb->sequence = window->lead; - -/* add skb to window */ - const uint_fast32_t index_ = skb->sequence % pgm_txw_max_length (window); - window->pdata[index_] = skb; - -/* statistics */ - window->size += skb->len; - -/* post-conditions */ - pgm_assert_cmpuint (pgm_txw_length (window), >, 0); - pgm_assert_cmpuint (pgm_txw_length (window), <=, pgm_txw_max_length (window)); -} - -/* peek an entry from the window for retransmission. - * - * returns pointer to skbuff on success, returns NULL on invalid parameters. - */ - -struct pgm_sk_buff_t* -pgm_txw_peek ( - const pgm_txw_t*const window, - const uint32_t sequence - ) -{ - pgm_debug ("peek (window:%p sequence:%" PRIu32 ")", - (const void*)window, sequence); - return _pgm_txw_peek (window, sequence); -} - -/* remove an entry from the trailing edge of the transmit window. - */ - -static -void -pgm_txw_remove_tail ( - pgm_txw_t* const window - ) -{ - struct pgm_sk_buff_t* skb; - pgm_txw_state_t* state; - - pgm_debug ("pgm_txw_remove_tail (window:%p)", (const void*)window); - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert (!pgm_txw_is_empty (window)); - - skb = _pgm_txw_peek (window, pgm_txw_trail (window)); - pgm_assert (NULL != skb); - pgm_assert (pgm_skb_is_valid (skb)); - pgm_assert (pgm_tsi_is_null (&skb->tsi)); - - state = (pgm_txw_state_t*)&skb->cb; - if (state->waiting_retransmit) { - pgm_queue_unlink (&window->retransmit_queue, (pgm_list_t*)skb); - state->waiting_retransmit = 0; - } - -/* statistics */ - window->size -= skb->len; - if (state->retransmit_count > 0) { - PGM_HISTOGRAM_COUNTS("Tx.RetransmitCount", state->retransmit_count); - } - if (state->nak_elimination_count > 0) { - PGM_HISTOGRAM_COUNTS("Tx.NakEliminationCount", state->nak_elimination_count); - } - -/* remove reference to skb */ - if (PGM_UNLIKELY(pgm_mem_gc_friendly)) { - const uint_fast32_t index_ = skb->sequence % pgm_txw_max_length (window); - window->pdata[index_] = NULL; - } - pgm_free_skb (skb); - -/* advance trailing pointer */ - pgm_atomic_inc32 (&window->trail); - -/* post-conditions */ - pgm_assert (!pgm_txw_is_full (window)); -} - -/* Try to add a sequence number to the retransmit queue, ignore if - * already there or no longer in the transmit window. - * - * For parity NAKs, we deal on the transmission group sequence number - * rather than the packet sequence number. To simplify managment we - * use the leading window packet to store the details of the entire - * transmisison group. Parity NAKs are ignored if the packet count is - * less than or equal to the count already queued for retransmission. - * - * returns FALSE if request was eliminated, returns TRUE if request was - * added to queue. - */ - -bool -pgm_txw_retransmit_push ( - pgm_txw_t* const window, - const uint32_t sequence, - const bool is_parity, /* parity NAK ⇒ sequence_number = transmission group | packet count */ - const uint8_t tg_sqn_shift - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert_cmpuint (tg_sqn_shift, <, 8 * sizeof(uint32_t)); - - pgm_debug ("retransmit_push (window:%p sequence:%" PRIu32 " is_parity:%s tg_sqn_shift:%u)", - (const void*)window, sequence, is_parity ? "TRUE" : "FALSE", tg_sqn_shift); - -/* early elimination */ - if (pgm_txw_is_empty (window)) - return FALSE; - - if (is_parity) - { - return pgm_txw_retransmit_push_parity (window, sequence, tg_sqn_shift); - } - else - { - return pgm_txw_retransmit_push_selective (window, sequence); - } -} - -static -bool -pgm_txw_retransmit_push_parity ( - pgm_txw_t* const window, - const uint32_t sequence, - const uint8_t tg_sqn_shift - ) -{ - struct pgm_sk_buff_t* skb; - pgm_txw_state_t* state; - -/* pre-conditions */ - pgm_assert (NULL != window); - pgm_assert_cmpuint (tg_sqn_shift, <, 8 * sizeof(uint32_t)); - - const uint32_t tg_sqn_mask = 0xffffffff << tg_sqn_shift; - const uint32_t nak_tg_sqn = sequence & tg_sqn_mask; /* left unshifted */ - const uint32_t nak_pkt_cnt = sequence & ~tg_sqn_mask; - skb = _pgm_txw_peek (window, nak_tg_sqn); - - if (NULL == skb) { - pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Transmission group lead #%" PRIu32 " not in window."), nak_tg_sqn); - return FALSE; - } - - pgm_assert (pgm_skb_is_valid (skb)); - pgm_assert (pgm_tsi_is_null (&skb->tsi)); - state = (pgm_txw_state_t*)&skb->cb; - -/* check if request can be eliminated */ - if (state->waiting_retransmit) - { - pgm_assert (NULL != ((const pgm_list_t*)skb)->next); - pgm_assert (NULL != ((const pgm_list_t*)skb)->prev); - if (state->pkt_cnt_requested < nak_pkt_cnt) { -/* more parity packets requested than currently scheduled, simply bump up the count */ - state->pkt_cnt_requested = nak_pkt_cnt; - } - state->nak_elimination_count++; - return FALSE; - } - else - { - pgm_assert (((const pgm_list_t*)skb)->next == NULL); - pgm_assert (((const pgm_list_t*)skb)->prev == NULL); - } - -/* new request */ - state->pkt_cnt_requested++; - pgm_queue_push_head_link (&window->retransmit_queue, (pgm_list_t*)skb); - pgm_assert (!pgm_queue_is_empty (&window->retransmit_queue)); - state->waiting_retransmit = 1; - return TRUE; -} - -static -bool -pgm_txw_retransmit_push_selective ( - pgm_txw_t* const window, - const uint32_t sequence - ) -{ - struct pgm_sk_buff_t* skb; - pgm_txw_state_t* state; - -/* pre-conditions */ - pgm_assert (NULL != window); - - skb = _pgm_txw_peek (window, sequence); - if (NULL == skb) { - pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Requested packet #%" PRIu32 " not in window."), sequence); - return FALSE; - } - - pgm_assert (pgm_skb_is_valid (skb)); - pgm_assert (pgm_tsi_is_null (&skb->tsi)); - state = (pgm_txw_state_t*)&skb->cb; - -/* check if request can be eliminated */ - if (state->waiting_retransmit) { - pgm_assert (!pgm_queue_is_empty (&window->retransmit_queue)); - state->nak_elimination_count++; - return FALSE; - } - - pgm_assert (((const pgm_list_t*)skb)->next == NULL); - pgm_assert (((const pgm_list_t*)skb)->prev == NULL); - -/* new request */ - pgm_queue_push_head_link (&window->retransmit_queue, (pgm_list_t*)skb); - pgm_assert (!pgm_queue_is_empty (&window->retransmit_queue)); - state->waiting_retransmit = 1; - return TRUE; -} - -/* try to peek a request from the retransmit queue - * - * return pointer of first skb in queue, or return NULL if the queue is empty. - */ - -struct pgm_sk_buff_t* -pgm_txw_retransmit_try_peek ( - pgm_txw_t* const window - ) -{ -/* pre-conditions */ - pgm_assert (NULL != window); - - pgm_debug ("retransmit_try_peek (window:%p)", (const void*)window); - -/* no lock required to detect presence of a request */ - pgm_list_t* tail_link = pgm_queue_peek_tail_link (&window->retransmit_queue); - if (PGM_UNLIKELY(NULL == tail_link)) { - pgm_debug ("retransmit queue empty on peek."); - return NULL; - } - - struct pgm_sk_buff_t* skb = (struct pgm_sk_buff_t*)tail_link; - pgm_assert (pgm_skb_is_valid (skb)); - pgm_txw_state_t* state = (pgm_txw_state_t*)&skb->cb; - - if (!state->waiting_retransmit) { - pgm_assert (((const pgm_list_t*)skb)->next == NULL); - pgm_assert (((const pgm_list_t*)skb)->prev == NULL); - } -/* packet payload still in transit */ - if (PGM_UNLIKELY(1 != pgm_atomic_read32 (&skb->users))) { - pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Retransmit sqn #%" PRIu32 " is still in transit in transmit thread."), skb->sequence); - return NULL; - } - if (!state->pkt_cnt_requested) { - return skb; - } - -/* generate parity packet to satisify request */ - const uint8_t rs_h = state->pkt_cnt_sent % (window->rs.n - window->rs.k); - const uint32_t tg_sqn_mask = 0xffffffff << window->tg_sqn_shift; - const uint32_t tg_sqn = skb->sequence & tg_sqn_mask; - bool is_var_pktlen = FALSE; - bool is_op_encoded = FALSE; - uint16_t parity_length = 0; - const pgm_gf8_t* src[ window->rs.k ]; - for (uint_fast8_t i = 0; i < window->rs.k; i++) - { - const struct pgm_sk_buff_t* odata_skb = pgm_txw_peek (window, tg_sqn + i); - const uint16_t odata_tsdu_length = ntohs (odata_skb->pgm_header->pgm_tsdu_length); - if (!parity_length) - { - parity_length = odata_tsdu_length; - } - else if (odata_tsdu_length != parity_length) - { - is_var_pktlen = TRUE; - if (odata_tsdu_length > parity_length) - parity_length = odata_tsdu_length; - } - - src[i] = odata_skb->data; - if (odata_skb->pgm_header->pgm_options & PGM_OPT_PRESENT) { - is_op_encoded = TRUE; - } - } - -/* construct basic PGM header to be completed by send_rdata() */ - skb = window->parity_buffer; - skb->data = skb->tail = skb->head = skb + 1; - -/* space for PGM header */ - pgm_skb_put (skb, sizeof(struct pgm_header)); - - skb->pgm_header = skb->data; - skb->pgm_data = (void*)( skb->pgm_header + 1 ); - memcpy (skb->pgm_header->pgm_gsi, &window->tsi->gsi, sizeof(pgm_gsi_t)); - skb->pgm_header->pgm_options = PGM_OPT_PARITY; - -/* append actual TSDU length if variable length packets, zero pad as necessary. - */ - if (is_var_pktlen) - { - skb->pgm_header->pgm_options |= PGM_OPT_VAR_PKTLEN; - - for (uint_fast8_t i = 0; i < window->rs.k; i++) - { - struct pgm_sk_buff_t* odata_skb = pgm_txw_peek (window, tg_sqn + i); - const uint16_t odata_tsdu_length = ntohs (odata_skb->pgm_header->pgm_tsdu_length); - - pgm_assert (odata_tsdu_length == odata_skb->len); - pgm_assert (parity_length >= odata_tsdu_length); - - if (!odata_skb->zero_padded) { - memset (odata_skb->tail, 0, parity_length - odata_tsdu_length); - *(uint16_t*)((char*)odata_skb->data + parity_length) = odata_tsdu_length; - odata_skb->zero_padded = 1; - } - } - parity_length += 2; - } - - skb->pgm_header->pgm_tsdu_length = htons (parity_length); - -/* space for DATA */ - pgm_skb_put (skb, sizeof(struct pgm_data) + parity_length); - - skb->pgm_data->data_sqn = htonl ( tg_sqn | rs_h ); - - void* data_bytes = skb->pgm_data + 1; - -/* encode every option separately, currently only one applies: opt_fragment - */ - if (is_op_encoded) - { - skb->pgm_header->pgm_options |= PGM_OPT_PRESENT; - - struct pgm_opt_fragment null_opt_fragment; - const pgm_gf8_t* opt_src[ window->rs.k ]; - memset (&null_opt_fragment, 0, sizeof(null_opt_fragment)); - *(uint8_t*)&null_opt_fragment |= PGM_OP_ENCODED_NULL; - for (uint_fast8_t i = 0; i < window->rs.k; i++) - { - const struct pgm_sk_buff_t* odata_skb = pgm_txw_peek (window, tg_sqn + i); - - if (odata_skb->pgm_opt_fragment) - { - pgm_assert (odata_skb->pgm_header->pgm_options & PGM_OPT_PRESENT); -/* skip three bytes of header */ - opt_src[i] = (pgm_gf8_t*)((char*)odata_skb->pgm_opt_fragment + sizeof (struct pgm_opt_header)); - } - else - { - opt_src[i] = (pgm_gf8_t*)&null_opt_fragment; - } - } - -/* add options to this rdata packet */ - const uint16_t opt_total_length = sizeof(struct pgm_opt_length) + - sizeof(struct pgm_opt_header) + - sizeof(struct pgm_opt_fragment); - -/* add space for PGM options */ - pgm_skb_put (skb, opt_total_length); - - struct pgm_opt_length* opt_len = data_bytes; - opt_len->opt_type = PGM_OPT_LENGTH; - opt_len->opt_length = sizeof(struct pgm_opt_length); - opt_len->opt_total_length = htons ( opt_total_length ); - struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); - opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; - opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fragment); - opt_header->opt_reserved = PGM_OP_ENCODED; - struct pgm_opt_fragment* opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); - -/* The cast below is the correct way to handle the problem. - * The (void *) cast is to avoid a GCC warning like: - * - * "warning: dereferencing type-punned pointer will break strict-aliasing rules" - */ - pgm_rs_encode (&window->rs, - opt_src, - window->rs.k + rs_h, - (pgm_gf8_t*)((char*)opt_fragment + sizeof(struct pgm_opt_header)), - sizeof(struct pgm_opt_fragment) - sizeof(struct pgm_opt_header)); - - data_bytes = opt_fragment + 1; - } - -/* encode payload */ - pgm_rs_encode (&window->rs, - src, - window->rs.k + rs_h, - data_bytes, - parity_length); - -/* calculate partial checksum */ - const uint16_t tsdu_length = ntohs (skb->pgm_header->pgm_tsdu_length); - state->unfolded_checksum = pgm_csum_partial ((char*)skb->tail - tsdu_length, tsdu_length, 0); - return skb; -} - -/* remove head entry from retransmit queue, will fail on assertion if queue is empty. - */ - -void -pgm_txw_retransmit_remove_head ( - pgm_txw_t* const window - ) -{ - struct pgm_sk_buff_t* skb; - pgm_txw_state_t* state; - -/* pre-conditions */ - pgm_assert (NULL != window); - - pgm_debug ("retransmit_remove_head (window:%p)", - (const void*)window); - -/* tail link is valid without lock */ - pgm_list_t* tail_link = pgm_queue_peek_tail_link (&window->retransmit_queue); - -/* link must be valid for pop */ - pgm_assert (NULL != tail_link); - - skb = (struct pgm_sk_buff_t*)tail_link; - pgm_assert (pgm_skb_is_valid (skb)); - pgm_assert (pgm_tsi_is_null (&skb->tsi)); - state = (pgm_txw_state_t*)&skb->cb; - if (!state->waiting_retransmit) - { - pgm_assert (((const pgm_list_t*)skb)->next == NULL); - pgm_assert (((const pgm_list_t*)skb)->prev == NULL); - } - if (state->pkt_cnt_requested) - { - state->pkt_cnt_sent++; - -/* remove if all requested parity packets have been sent */ - if (state->pkt_cnt_sent == state->pkt_cnt_requested) { - pgm_queue_pop_tail_link (&window->retransmit_queue); - state->waiting_retransmit = 0; - } - } - else /* selective request */ - { - pgm_queue_pop_tail_link (&window->retransmit_queue); - state->waiting_retransmit = 0; - } -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/txw_unittest.c b/3rdparty/openpgm-svn-r1085/pgm/txw_unittest.c deleted file mode 100644 index bec079b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/txw_unittest.c +++ /dev/null @@ -1,743 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * unit tests for transmit window. - * - * Copyright (c) 2009 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include - - -/* mock global */ - -#define pgm_histogram_add mock_pgm_histogram_add -#define pgm_rs_create mock_pgm_rs_create -#define pgm_rs_destroy mock_pgm_rs_destroy -#define pgm_rs_encode mock_pgm_rs_encode -#define pgm_compat_csum_partial mock_pgm_compat_csum_partial -#define pgm_histogram_init mock_pgm_histogram_init - -#define TXW_DEBUG -#include "txw.c" - - -/** reed-solomon module */ -void -mock_pgm_rs_create ( - pgm_rs_t* rs, - uint8_t n, - uint8_t k - ) -{ -} - -void -mock_pgm_rs_destroy ( - pgm_rs_t* rs - ) -{ -} - -void -mock_pgm_rs_encode( - pgm_rs_t* rs, - const pgm_gf8_t** src, - const uint8_t offset, - pgm_gf8_t* dst, - const uint16_t len - ) -{ -} - -/** checksum module */ -uint32_t -mock_pgm_compat_csum_partial ( - const void* addr, - uint16_t len, - uint32_t csum - ) -{ - return 0x0; -} - -void -mock_pgm_histogram_init ( - pgm_histogram_t* histogram - ) -{ -} - -void -mock_pgm_histogram_add ( - pgm_histogram_t* histogram, - int value - ) -{ -} - - -/* mock functions for external references */ - -size_t -pgm_pkt_offset ( - const bool can_fragment, - const sa_family_t pgmcc_family /* 0 = disable */ - ) -{ - return 0; -} - - -/* generate valid skb, data pointer pointing to PGM payload - */ -static -struct pgm_sk_buff_t* -generate_valid_skb (void) -{ - const guint16 tsdu_length = 1000; - const guint16 header_length = sizeof(struct pgm_header) + sizeof(struct pgm_data); - struct pgm_sk_buff_t* skb = pgm_alloc_skb (1500); -/* fake but valid transport and timestamp */ - skb->sock = (pgm_sock_t*)0x1; - skb->tstamp = 1; -/* header */ - pgm_skb_reserve (skb, header_length); - memset (skb->head, 0, header_length); - skb->pgm_header = (struct pgm_header*)skb->head; - skb->pgm_data = (struct pgm_data*)(skb->pgm_header + 1); - skb->pgm_header->pgm_type = PGM_ODATA; - skb->pgm_header->pgm_tsdu_length = g_htons (tsdu_length); -/* DATA */ - pgm_skb_put (skb, tsdu_length); - return skb; -} - -/* target: - * pgm_txw_t* - * pgm_txw_create ( - * const pgm_tsi_t* const tsi, - * const guint16 tpdu_size, - * const guint32 sqns, - * const guint secs, - * const guint max_rte, - * const gboolean use_fec, - * const guint rs_n, - * const guint rs_k - * ) - */ - -/* vanilla sequence count window */ -START_TEST (test_create_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - fail_if (NULL == pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0), "create failed"); -} -END_TEST - -/* vanilla time based window */ -START_TEST (test_create_pass_002) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - fail_if (NULL == pgm_txw_create (&tsi, 1500, 0, 60, 800000, FALSE, 0, 0), "create failed"); -} -END_TEST - -/* jumbo frame */ -START_TEST (test_create_pass_003) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - fail_if (NULL == pgm_txw_create (&tsi, 9000, 0, 60, 800000, FALSE, 0, 0), "create failed"); -} -END_TEST - -/* max frame */ -START_TEST (test_create_pass_004) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - fail_if (NULL == pgm_txw_create (&tsi, UINT16_MAX, 0, 60, 800000, FALSE, 0, 0), "create failed"); -} -END_TEST - -/* invalid tpdu size */ -START_TEST (test_create_fail_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const pgm_txw_t* window = pgm_txw_create (&tsi, 0, 0, 60, 800000, FALSE, 0, 0); - fail ("reached"); -} -END_TEST - -/* no specified sequence count or time value */ -START_TEST (test_create_fail_002) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const pgm_txw_t* window = pgm_txw_create (&tsi, 0, 0, 0, 800000, FALSE, 0, 0); - fail ("reached"); -} -END_TEST - -/* no specified rate */ -START_TEST (test_create_fail_003) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const pgm_txw_t* window = pgm_txw_create (&tsi, 0, 0, 60, 0, FALSE, 0, 0); - fail ("reached"); -} -END_TEST - -/* all invalid */ -START_TEST (test_create_fail_004) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - const pgm_txw_t* window = pgm_txw_create (NULL, 0, 0, 0, 0, FALSE, 0, 0); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_txw_shutdown ( - * pgm_txw_t* const window - * ) - */ - -START_TEST (test_shutdown_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - pgm_txw_shutdown (window); -} -END_TEST - -START_TEST (test_shutdown_fail_001) -{ - pgm_txw_shutdown (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_txw_add ( - * pgm_txw_t* const window, - * struct pgm_sk_buff_t* const skb - * ) - * failures raise assert errors and stop process execution. - */ - -START_TEST (test_add_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - pgm_txw_shutdown (window); -} -END_TEST - -/* null skb */ -START_TEST (test_add_fail_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - pgm_txw_add (window, NULL); - fail ("reached"); -} -END_TEST - -/* null window */ -START_TEST (test_add_fail_002) -{ - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (NULL, skb); - fail ("reached"); -} -END_TEST - -/* null skb content */ -START_TEST (test_add_fail_003) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - char buffer[1500]; - memset (buffer, 0, sizeof(buffer)); - pgm_txw_add (window, (struct pgm_sk_buff_t*)buffer); - fail ("reached"); -} -END_TEST - -/* target: - * struct pgm_sk_buff_t* - * pgm_txw_peek ( - * pgm_txw_t* const window, - * const guint32 sequence - * ) - */ - -START_TEST (test_peek_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - fail_unless (skb == pgm_txw_peek (window, window->trail), "peek failed"); - pgm_txw_shutdown (window); -} -END_TEST - -/* null window */ -START_TEST (test_peek_fail_001) -{ - const struct pgm_sk_buff_t* skb = pgm_txw_peek (NULL, 0); - fail ("reached"); -} -END_TEST - -/* empty window */ -START_TEST (test_peek_fail_002) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - fail_unless (NULL == pgm_txw_peek (window, window->trail), "peek failed"); - pgm_txw_shutdown (window); -} -END_TEST - -/** inline function tests **/ -/* pgm_txw_max_length () - */ -START_TEST (test_max_length_pass_001) -{ - const guint window_length = 100; - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, window_length, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - fail_unless (window_length == pgm_txw_max_length (window), "max_length failed"); - pgm_txw_shutdown (window); -} -END_TEST - -START_TEST (test_max_length_fail_001) -{ - const size_t answer = pgm_txw_max_length (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_txw_length () - */ -START_TEST (test_length_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - fail_unless (0 == pgm_txw_length (window), "length failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - fail_unless (1 == pgm_txw_length (window), "length failed"); - pgm_txw_shutdown (window); -} -END_TEST - -START_TEST (test_length_fail_001) -{ - const uint32_t answer = pgm_txw_length (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_txw_size () - */ -START_TEST (test_size_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - fail_unless (0 == pgm_txw_size (window), "size failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - fail_unless (1000 == pgm_txw_size (window), "size failed"); - pgm_txw_shutdown (window); -} -END_TEST - -START_TEST (test_size_fail_001) -{ - const size_t answer = pgm_txw_size (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_txw_is_empty - */ -START_TEST (test_is_empty_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - fail_unless (pgm_txw_is_empty (window), "is_empty failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - fail_if (pgm_txw_is_empty (window), "is_empty failed"); - pgm_txw_shutdown (window); -} -END_TEST - -START_TEST (test_is_empty_fail_001) -{ - const bool answer = pgm_txw_is_empty (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_txw_is_full - */ -START_TEST (test_is_full_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 1, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - fail_if (pgm_txw_is_full (window), "is_full failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - fail_unless (pgm_txw_is_full (window), "is_full failed"); - pgm_txw_shutdown (window); -} -END_TEST - -START_TEST (test_is_full_fail_001) -{ - const bool answer = pgm_txw_is_full (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_txw_lead - */ -START_TEST (test_lead_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - guint32 lead = pgm_txw_lead (window); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - fail_unless (lead + 1 == pgm_txw_lead (window), "lead failed"); - pgm_txw_shutdown (window); -} -END_TEST - -START_TEST (test_lead_fail_001) -{ - const uint32_t answer = pgm_txw_lead (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_txw_next_lead - */ -START_TEST (test_next_lead_pass_001) -{ - const guint window_length = 100; - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, window_length, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - guint32 next_lead = pgm_txw_next_lead (window); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - fail_unless (next_lead == pgm_txw_lead (window), "lead failed"); - pgm_txw_shutdown (window); -} -END_TEST - -START_TEST (test_next_lead_fail_001) -{ - const uint32_t answer = pgm_txw_next_lead (NULL); - fail ("reached"); -} -END_TEST - -/* pgm_txw_trail - */ -START_TEST (test_trail_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 1, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); -/* does not advance with adding skb */ - guint32 trail = pgm_txw_trail (window); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - fail_unless (trail == pgm_txw_trail (window), "trail failed"); -/* does advance when filling up window */ - skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - fail_if (trail == pgm_txw_trail (window), "trail failed"); - pgm_txw_shutdown (window); -} -END_TEST - -START_TEST (test_trail_fail_001) -{ - const uint32_t answer = pgm_txw_trail (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * bool - * pgm_txw_retransmit_push ( - * pgm_txw_t* const window, - * const uint32_t sequence, - * const bool is_parity, - * const uint8_t tg_sqn_shift - * ) - */ - -START_TEST (test_retransmit_push_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); -/* empty window invalidates all requests */ - fail_unless (FALSE == pgm_txw_retransmit_push (window, window->trail, FALSE, 0), "retransmit_push failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); -/* first request */ - fail_unless (TRUE == pgm_txw_retransmit_push (window, window->trail, FALSE, 0), "retransmit_push failed"); -/* second request eliminated */ - fail_unless (FALSE == pgm_txw_retransmit_push (window, window->trail, FALSE, 0), "retransmit_push failed"); - pgm_txw_shutdown (window); -} -END_TEST - -START_TEST (test_retransmit_push_fail_001) -{ - const bool answer = pgm_txw_retransmit_push (NULL, 0, FALSE, 0); - fail ("reached"); -} -END_TEST - -/* target: - * struct pgm_sk_buff_t* - * pgm_txw_retransmit_try_peek ( - * pgm_txw_t* const window - * ) - */ - -START_TEST (test_retransmit_try_peek_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - fail_unless (1 == pgm_txw_retransmit_push (window, window->trail, FALSE, 0), "retransmit_push failed"); - fail_unless (NULL != pgm_txw_retransmit_try_peek (window), "retransmit_try_peek failed"); - pgm_txw_shutdown (window); -} -END_TEST - -/* null window */ -START_TEST (test_retransmit_try_peek_fail_001) -{ - const struct pgm_sk_buff_t* skb = pgm_txw_retransmit_try_peek (NULL); - fail ("reached"); -} -END_TEST - -/* target: - * void - * pgm_txw_retransmit_remove_head ( - * pgm_txw_t* const window - * ) - */ - -START_TEST (test_retransmit_remove_head_pass_001) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - struct pgm_sk_buff_t* skb = generate_valid_skb (); - fail_if (NULL == skb, "generate_valid_skb failed"); - pgm_txw_add (window, skb); - fail_unless (1 == pgm_txw_retransmit_push (window, window->trail, FALSE, 0), "retransmit_push failed"); - fail_unless (NULL != pgm_txw_retransmit_try_peek (window), "retransmit_try_peek failed"); - pgm_txw_retransmit_remove_head (window); - pgm_txw_shutdown (window); -} -END_TEST - -/* null window */ -START_TEST (test_retransmit_remove_head_fail_001) -{ - pgm_txw_retransmit_remove_head (NULL); - fail ("reached"); -} -END_TEST - -/* empty retransmit queue */ -START_TEST (test_retransmit_remove_head_fail_002) -{ - const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; - pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); - fail_if (NULL == window, "create failed"); - pgm_txw_retransmit_remove_head (window); - fail ("reached"); -} -END_TEST - -static -Suite* -make_test_suite (void) -{ - Suite* s; - - s = suite_create (__FILE__); - - TCase* tc_create = tcase_create ("create"); - suite_add_tcase (s, tc_create); - tcase_add_test (tc_create, test_create_pass_001); - tcase_add_test (tc_create, test_create_pass_002); - tcase_add_test (tc_create, test_create_pass_003); - tcase_add_test (tc_create, test_create_pass_004); - tcase_add_test_raise_signal (tc_create, test_create_fail_001, SIGABRT); - tcase_add_test_raise_signal (tc_create, test_create_fail_002, SIGABRT); - tcase_add_test_raise_signal (tc_create, test_create_fail_003, SIGABRT); - tcase_add_test_raise_signal (tc_create, test_create_fail_004, SIGABRT); - - TCase* tc_shutdown = tcase_create ("shutdown"); - suite_add_tcase (s, tc_shutdown); - tcase_add_test (tc_shutdown, test_shutdown_pass_001); - tcase_add_test_raise_signal (tc_shutdown, test_shutdown_fail_001, SIGABRT); - - TCase* tc_add = tcase_create ("add"); - suite_add_tcase (s, tc_add); - tcase_add_test (tc_add, test_add_pass_001); - tcase_add_test_raise_signal (tc_add, test_add_fail_001, SIGABRT); - tcase_add_test_raise_signal (tc_add, test_add_fail_002, SIGABRT); - tcase_add_test_raise_signal (tc_add, test_add_fail_003, SIGABRT); - - TCase* tc_peek = tcase_create ("peek"); - suite_add_tcase (s, tc_peek); - tcase_add_test (tc_peek, test_peek_pass_001); - tcase_add_test_raise_signal (tc_peek, test_peek_fail_001, SIGABRT); -/* logical not fatal errors */ - tcase_add_test (tc_peek, test_peek_fail_002); - - TCase* tc_max_length = tcase_create ("max-length"); - suite_add_tcase (s, tc_max_length); - tcase_add_test (tc_max_length, test_max_length_pass_001); - tcase_add_test_raise_signal (tc_max_length, test_max_length_fail_001, SIGABRT); - - TCase* tc_length = tcase_create ("length"); - suite_add_tcase (s, tc_length); - tcase_add_test (tc_length, test_length_pass_001); - tcase_add_test_raise_signal (tc_length, test_length_fail_001, SIGABRT); - - TCase* tc_size = tcase_create ("size"); - suite_add_tcase (s, tc_size); - tcase_add_test (tc_size, test_size_pass_001); - tcase_add_test_raise_signal (tc_size, test_size_fail_001, SIGABRT); - - TCase* tc_is_empty = tcase_create ("is-empty"); - suite_add_tcase (s, tc_is_empty); - tcase_add_test (tc_is_empty, test_is_empty_pass_001); - tcase_add_test_raise_signal (tc_is_empty, test_is_empty_fail_001, SIGABRT); - TCase* tc_is_full = tcase_create ("is-full"); - suite_add_tcase (s, tc_is_full); - tcase_add_test (tc_is_full, test_is_full_pass_001); - tcase_add_test_raise_signal (tc_is_full, test_is_full_fail_001, SIGABRT); - - TCase* tc_lead = tcase_create ("lead"); - suite_add_tcase (s, tc_lead); - tcase_add_test (tc_lead, test_lead_pass_001); - tcase_add_test_raise_signal (tc_lead, test_lead_fail_001, SIGABRT); - - TCase* tc_next_lead = tcase_create ("next-lead"); - suite_add_tcase (s, tc_next_lead); - tcase_add_test (tc_next_lead, test_next_lead_pass_001); - tcase_add_test_raise_signal (tc_next_lead, test_next_lead_fail_001, SIGABRT); - - TCase* tc_trail = tcase_create ("trail"); - suite_add_tcase (s, tc_trail); - tcase_add_test (tc_trail, test_trail_pass_001); - tcase_add_test_raise_signal (tc_trail, test_trail_fail_001, SIGABRT); - - TCase* tc_retransmit_push = tcase_create ("retransmit-push"); - suite_add_tcase (s, tc_retransmit_push); - tcase_add_test (tc_retransmit_push, test_retransmit_push_pass_001); - tcase_add_test_raise_signal (tc_retransmit_push, test_retransmit_push_fail_001, SIGABRT); - - TCase* tc_retransmit_try_peek = tcase_create ("retransmit-try-peek"); - suite_add_tcase (s, tc_retransmit_try_peek); - tcase_add_test (tc_retransmit_try_peek, test_retransmit_try_peek_pass_001); - tcase_add_test_raise_signal (tc_retransmit_try_peek, test_retransmit_try_peek_fail_001, SIGABRT); - - TCase* tc_retransmit_remove_head = tcase_create ("retransmit-remove-head"); - suite_add_tcase (s, tc_retransmit_remove_head); - tcase_add_test (tc_retransmit_remove_head, test_retransmit_remove_head_pass_001); - tcase_add_test_raise_signal (tc_retransmit_remove_head, test_retransmit_remove_head_fail_001, SIGABRT); - tcase_add_test_raise_signal (tc_retransmit_remove_head, test_retransmit_remove_head_fail_002, SIGABRT); - - return s; -} - -static -Suite* -make_master_suite (void) -{ - Suite* s = suite_create ("Master"); - return s; -} - -int -main (void) -{ - SRunner* sr = srunner_create (make_master_suite ()); - srunner_add_suite (sr, make_test_suite ()); - srunner_run_all (sr, CK_ENV); - int number_failed = srunner_ntests_failed (sr); - srunner_free (sr); - return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1085/pgm/valgrind.supp b/3rdparty/openpgm-svn-r1085/pgm/valgrind.supp deleted file mode 100644 index ea74d2d..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/valgrind.supp +++ /dev/null @@ -1,147 +0,0 @@ -##----------------------------------------------------------------------## -## Suppressions to run OpenPGM - -{ - miru-glib-hack-1 - Memcheck:Leak - fun:memalign - fun:posix_memalign - obj:/usr/lib/libglib-2.0.so* - fun:g_slice_alloc -} - -{ - miru-glib-hack-2 - Memcheck:Leak - fun:calloc - fun:g_malloc0 - obj:/usr/lib/libglib-2.0.so* - fun:g_slice_alloc -} - -{ - miru-glib-hack-2b - Memcheck:Leak - fun:malloc - fun:g_malloc - obj:/usr/lib/libglib-2.0.so* - fun:g_slice_alloc -} - -{ - miru-glib-hack-3 - Memcheck:Leak - fun:malloc - fun:realloc - fun:g_realloc - obj:/usr/lib/libglib-2.0.so* - fun:g_ptr_array_add - fun:g_main_context_check - obj:/usr/lib/libglib-2.0.so* - fun:g_main_loop_run -} - -{ - miru-glib-hack-4 - Memcheck:Leak - fun:realloc - fun:g_realloc - obj:/usr/lib/libglib-2.0.so* - fun:g_array_set_size - fun:g_static_private_set - fun:g_get_language_names -} - -{ - miru-glib-hack-5 - Memcheck:Leak - fun:malloc - fun:g_malloc - fun:g_slice_alloc - fun:g_array_sized_new - fun:g_static_private_set - fun:g_get_charset - fun:g_log_default_handler - fun:g_logv - fun:g_log -} - -{ - miru-glib-hack-6 - Memcheck:Leak - fun:malloc - fun:g_malloc - fun:g_log_set_handler -} - -{ - miru-glib-hack-7 - Memcheck:Leak - fun:calloc - fun:g_malloc0 - fun:g_thread_self - fun:g_thread_init_glib -} - - - -## Annoying libc errors - -{ - miru-libc-hack-1 - Memcheck:Addr8 - obj:/lib/ld-2.*.so - obj:/lib/ld-2.*.so - obj:/lib/libc-2.*.so - obj:/lib/ld-2.*.so - fun:__libc_dlopen_mode - fun:__nss_lookup_function - obj:/lib/libc-2.*.so - fun:getprotobyname_r -} - -{ - miru-libc-hack-1b - Memcheck:Addr8 - obj:/lib/ld-2.*.so - obj:/lib/ld-2.*.so - obj:/lib/ld-2.*.so - obj:/lib/ld-2.*.so - obj:/lib/ld-2.*.so - obj:/lib/ld-2.*.so - obj:/lib/ld-2.*.so - obj:/lib/libc-2.*.so - obj:/lib/ld-2.*.so - fun:__libc_dlopen_mode - fun:__nss_lookup_function - obj:/lib/libc-2.*.so - fun:getprotobyname_r -} - -{ - miru-libc-hack-2 - Memcheck:Cond - obj:/lib/ld-2.*.so - obj:/lib/ld-2.*.so - obj:/lib/libc-2.*.so - obj:/lib/ld-2.*.so - fun:__libc_dlsym - fun:__nss_lookup_function - obj:/lib/libc-2.*.so - fun:getaddrinfo -} - -{ - miru-libc-hack-3 - Memcheck:Addr8 - obj:/lib/ld-2.*.so - obj:/lib/ld-2.*.so - obj:/lib/ld-2.*.so - obj:/lib/ld-2.*.so - obj:/lib/libc-2.*.so - obj:/lib/ld-2.*.so - fun:__libc_dlsym - fun:__nss_lookup_function - obj:/lib/libc-2.*.so - fun:getaddrinfo -} diff --git a/3rdparty/openpgm-svn-r1085/pgm/version_generator.py b/3rdparty/openpgm-svn-r1085/pgm/version_generator.py deleted file mode 100755 index 0db781b..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/version_generator.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/python - -import os -import platform -import time - -build_date = time.strftime ("%Y-%m-%d") -build_time = time.strftime ("%H:%M:%S") -build_rev = os.popen('svnversion -n .').read(); - -print """ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * OpenPGM version. - * - * Copyright (c) 2006-2010 Miru Limited. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - - -/* globals */ - -const unsigned pgm_major_version = 5; -const unsigned pgm_minor_version = 0; -const unsigned pgm_micro_version = 70; -const char* pgm_build_date = "%s"; -const char* pgm_build_time = "%s"; -const char* pgm_build_system = "%s"; -const char* pgm_build_machine = "%s"; -const char* pgm_build_revision = "%s"; - - -/* eof */ -"""%(build_date, build_time, platform.system(), platform.machine(), build_rev) - -# end of file diff --git a/3rdparty/openpgm-svn-r1085/pgm/win/mingw32-runtime_3.13-1openpgm3.diff b/3rdparty/openpgm-svn-r1085/pgm/win/mingw32-runtime_3.13-1openpgm3.diff deleted file mode 100644 index 5b860a1..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/win/mingw32-runtime_3.13-1openpgm3.diff +++ /dev/null @@ -1,136 +0,0 @@ -diff -urN include-original/mswsock.h include/mswsock.h ---- include-original/mswsock.h 2009-08-21 22:41:22.000000000 +0800 -+++ include/mswsock.h 2010-01-21 17:31:14.662159471 +0800 -@@ -83,23 +83,19 @@ - } WSAMSG, *PWSAMSG, *LPWSAMSG; - - --/* According to MSDN docs, the WSAMSG.Control buffer starts with a -- cmsghdr header of the following form. See also RFC 2292. */ -- --typedef struct wsacmsghdr { -- UINT cmsg_len; -- INT cmsg_level; -- INT cmsg_type; -- /* followed by UCHAR cmsg_data[]; */ --} WSACMSGHDR; -- --/* TODO: Standard Posix.1g macros as per RFC 2292, with WSA_uglification. */ --#if 0 --#define WSA_CMSG_FIRSTHDR(mhdr) --#define WSA_CMSG_NXTHDR(mhdr, cmsg) --#define WSA_CMSG_SPACE(length) --#define WSA_CMSG_LEN(length) --#endif -+ typedef struct _WSACMSGHDR { -+ SIZE_T cmsg_len; -+ INT cmsg_level; -+ INT cmsg_type; -+ } WSACMSGHDR,*PWSACMSGHDR,*LPWSACMSGHDR; -+ -+#define WSA_CMSGHDR_ALIGN(length) (((length) + TYPE_ALIGNMENT(WSACMSGHDR)-1) & (~(TYPE_ALIGNMENT(WSACMSGHDR)-1))) -+#define WSA_CMSGDATA_ALIGN(length) (((length) + MAX_NATURAL_ALIGNMENT-1) & (~(MAX_NATURAL_ALIGNMENT-1))) -+#define WSA_CMSG_FIRSTHDR(msg) (((msg)->Control.len >= sizeof(WSACMSGHDR)) ? (LPWSACMSGHDR)(msg)->Control.buf : (LPWSACMSGHDR)NULL) -+#define WSA_CMSG_NXTHDR(msg,cmsg) ((!(cmsg)) ? WSA_CMSG_FIRSTHDR(msg) : ((((u_char *)(cmsg) + WSA_CMSGHDR_ALIGN((cmsg)->cmsg_len) + sizeof(WSACMSGHDR)) > (u_char *)((msg)->Control.buf) + (msg)->Control.len) ? (LPWSACMSGHDR)NULL : (LPWSACMSGHDR)((u_char *)(cmsg) + WSA_CMSGHDR_ALIGN((cmsg)->cmsg_len)))) -+#define WSA_CMSG_DATA(cmsg) ((u_char *)(cmsg) + WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR))) -+#define WSA_CMSG_SPACE(length) (WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR) + WSA_CMSGHDR_ALIGN(length))) -+#define WSA_CMSG_LEN(length) (WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR)) + length) -+ -+typedef INT (WINAPI * LPFN_WSARECVMSG)(SOCKET, LPWSAMSG, LPDWORD, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); -+ - BOOL PASCAL DisconnectEx(SOCKET,LPOVERLAPPED,DWORD,DWORD); - int PASCAL WSARecvMsg(SOCKET,LPWSAMSG,LPDWORD,LPWSAOVERLAPPED,LPWSAOVERLAPPED_COMPLETION_ROUTINE); - -diff -urN include-original/ws2tcpip.h include/ws2tcpip.h ---- include-original/ws2tcpip.h 2009-08-21 22:41:42.000000000 +0800 -+++ include/ws2tcpip.h 2009-08-21 22:42:15.000000000 +0800 -@@ -78,6 +78,18 @@ - - #define UDP_NOCHECKSUM 1 - -+/* RFC 3768 */ -+#define MCAST_JOIN_GROUP 41 -+#define MCAST_LEAVE_GROUP 42 -+#define MCAST_BLOCK_SOURCE 43 -+#define MCAST_UNBLOCK_SOURCE 44 -+#define MCAST_JOIN_SOURCE_GROUP 45 -+#define MCAST_LEAVE_SOURCE_GROUP 46 -+#define MCAST_MSFILTER 47 -+ -+#define MCAST_EXCLUDE 0 -+#define MCAST_INCLUDE 1 -+ - /* INTERFACE_INFO iiFlags */ - #define IFF_UP 1 - #define IFF_BROADCAST 2 -@@ -104,6 +116,7 @@ - #define AI_PASSIVE 1 - #define AI_CANONNAME 2 - #define AI_NUMERICHOST 4 -+#define AI_ADDRCONFIG 0x20 - - /* getaddrinfo error codes */ - #define EAI_AGAIN WSATRY_AGAIN -@@ -132,6 +145,25 @@ - struct in_addr imr_interface; - }; - -+struct group_req { -+ u_long gr_interface; -+ struct sockaddr_storage gr_group; -+}; -+ -+struct group_source_req { -+ u_long gsr_interface; -+ struct sockaddr_storage gsr_group; -+ struct sockaddr_storage gsr_source; -+}; -+ -+struct group_filter { -+ u_long gf_interface; -+ struct sockaddr_storage gf_group; -+ u_long gf_fmode; -+ u_long gf_numsrc; -+ struct in_addr gf_slist[1]; -+}; -+ - struct ip_msfilter { - struct in_addr imsf_multiaddr; - struct in_addr imsf_interface; -@@ -356,6 +388,13 @@ - sockaddr_gen iiNetmask; - } INTERFACE_INFO, *LPINTERFACE_INFO; - -+typedef struct _INTERFACE_INFO_EX { -+ u_long iiFlags; -+ SOCKET_ADDRESS iiAddress; -+ SOCKET_ADDRESS iiBroadcastAddress; -+ SOCKET_ADDRESS iiNetmask; -+} INTERFACE_INFO_EX, *_LPINTERFACE_INFO_EX; -+ - /* - The definition above can cause problems on NT4,prior to sp4. - To workaround, include the following struct and typedef and ---- include-original/winnt.h 2009-08-21 22:41:42.000000000 +0800 -+++ include/winnt.h 2010-01-21 17:33:56.366162880 +0800 -@@ -43,6 +43,20 @@ - #define UNALIGNED - #endif - -+#ifdef _WIN64 -+#define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG) -+#define MEMORY_ALLOCATION_ALIGNMENT 16 -+#else -+#define MAX_NATURAL_ALIGNMENT sizeof(DWORD) -+#define MEMORY_ALLOCATION_ALIGNMENT 8 -+#endif -+ -+#ifdef __cplusplus -+#define TYPE_ALIGNMENT(t) __alignof__ (t) -+#else -+#define TYPE_ALIGNMENT(t) FIELD_OFFSET(struct { char x; t test; },test) -+#endif -+ - #ifndef DECLSPEC_ALIGN - #ifdef __GNUC__ - #define DECLSPEC_ALIGN(x) __attribute__((aligned(x))) diff --git a/3rdparty/openpgm-svn-r1085/pgm/win/mingw32-runtime_3.15.2-0openpgm1.diff b/3rdparty/openpgm-svn-r1085/pgm/win/mingw32-runtime_3.15.2-0openpgm1.diff deleted file mode 100644 index b6e3d11..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/win/mingw32-runtime_3.15.2-0openpgm1.diff +++ /dev/null @@ -1,135 +0,0 @@ -diff -urN include-original/mswsock.h include/mswsock.h ---- include-original/mswsock.h 2009-06-30 16:32:31.000000000 +0800 -+++ include/mswsock.h 2010-03-23 20:34:12.000000000 +0800 -@@ -83,23 +83,20 @@ - } WSAMSG, *PWSAMSG, *LPWSAMSG; - - --/* According to MSDN docs, the WSAMSG.Control buffer starts with a -- cmsghdr header of the following form. See also RFC 2292. */ -- --typedef struct wsacmsghdr { -- UINT cmsg_len; -- INT cmsg_level; -- INT cmsg_type; -- /* followed by UCHAR cmsg_data[]; */ --} WSACMSGHDR; -- --/* TODO: Standard Posix.1g macros as per RFC 2292, with WSA_uglification. */ --#if 0 --#define WSA_CMSG_FIRSTHDR(mhdr) --#define WSA_CMSG_NXTHDR(mhdr, cmsg) --#define WSA_CMSG_SPACE(length) --#define WSA_CMSG_LEN(length) --#endif -+typedef struct _WSACMSGHDR { -+ SIZE_T cmsg_len; -+ INT cmsg_level; -+ INT cmsg_type; -+} WSACMSGHDR,*PWSACMSGHDR,*LPWSACMSGHDR; -+ -+#define WSA_CMSGHDR_ALIGN(length) (((length) + TYPE_ALIGNMENT(WSACMSGHDR)-1) & (~(TYPE_ALIGNMENT(WSACMSGHDR)-1))) -+#define WSA_CMSGDATA_ALIGN(length) (((length) + MAX_NATURAL_ALIGNMENT-1) & (~(MAX_NATURAL_ALIGNMENT-1))) -+#define WSA_CMSG_FIRSTHDR(msg) (((msg)->Control.len >= sizeof(WSACMSGHDR)) ? (LPWSACMSGHDR)(msg)->Control.buf : (LPWSACMSGHDR)NULL) -+#define WSA_CMSG_NXTHDR(msg,cmsg) ((!(cmsg)) ? WSA_CMSG_FIRSTHDR(msg) : ((((u_char *)(cmsg) + WSA_CMSGHDR_ALIGN((cmsg)->cmsg_len) + sizeof(WSACMSGHDR)) > (u_char *)((msg)->Control.buf) + (msg)->Control.len) ? (LPWSACMSGHDR)NULL : (LPWSACMSGHDR)((u_char *)(cmsg) + WSA_CMSGHDR_ALIGN((cmsg)->cmsg_len)))) -+#define WSA_CMSG_DATA(cmsg) ((u_char *)(cmsg) + WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR))) -+#define WSA_CMSG_SPACE(length) (WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR) + WSA_CMSGHDR_ALIGN(length))) -+#define WSA_CMSG_LEN(length) (WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR)) + length) -+typedef INT (WINAPI * LPFN_WSARECVMSG)(SOCKET, LPWSAMSG, LPDWORD, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); - - BOOL PASCAL DisconnectEx(SOCKET,LPOVERLAPPED,DWORD,DWORD); - int PASCAL WSARecvMsg(SOCKET,LPWSAMSG,LPDWORD,LPWSAOVERLAPPED,LPWSAOVERLAPPED_COMPLETION_ROUTINE); -diff -urN include-original/winnt.h include/winnt.h ---- include-original/winnt.h 2009-06-30 16:32:32.000000000 +0800 -+++ include/winnt.h 2010-03-23 20:36:29.000000000 +0800 -@@ -43,6 +43,20 @@ - #define UNALIGNED - #endif - -+#ifdef _WIN64 -+#define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG) -+#define MEMORY_ALLOCATION_ALIGNMENT 16 -+#else -+#define MAX_NATURAL_ALIGNMENT sizeof(DWORD) -+#define MEMORY_ALLOCATION_ALIGNMENT 8 -+#endif -+ -+#ifdef __cplusplus -+#define TYPE_ALIGNMENT(t) __alignof__ (t) -+#else -+#define TYPE_ALIGNMENT(t) FIELD_OFFSET(struct { char x; t test; },test) -+#endif -+ - #ifndef DECLSPEC_ALIGN - #ifdef __GNUC__ - #define DECLSPEC_ALIGN(x) __attribute__((aligned(x))) -diff -urN include-original/ws2tcpip.h include/ws2tcpip.h ---- include-original/ws2tcpip.h 2009-06-30 16:32:32.000000000 +0800 -+++ include/ws2tcpip.h 2010-03-23 20:35:59.000000000 +0800 -@@ -78,6 +78,18 @@ - - #define UDP_NOCHECKSUM 1 - -+/* RFC 3768 */ -+#define MCAST_JOIN_GROUP 41 -+#define MCAST_LEAVE_GROUP 42 -+#define MCAST_BLOCK_SOURCE 43 -+#define MCAST_UNBLOCK_SOURCE 44 -+#define MCAST_JOIN_SOURCE_GROUP 45 -+#define MCAST_LEAVE_SOURCE_GROUP 46 -+#define MCAST_MSFILTER 47 -+ -+#define MCAST_EXCLUDE 0 -+#define MCAST_INCLUDE 1 -+ - /* INTERFACE_INFO iiFlags */ - #define IFF_UP 1 - #define IFF_BROADCAST 2 -@@ -104,6 +116,7 @@ - #define AI_PASSIVE 1 - #define AI_CANONNAME 2 - #define AI_NUMERICHOST 4 -+#define AI_ADDRCONFIG 0x20 - - /* getaddrinfo error codes */ - #define EAI_AGAIN WSATRY_AGAIN -@@ -132,6 +145,25 @@ - struct in_addr imr_interface; - }; - -+struct group_req { -+ u_long gr_interface; -+ struct sockaddr_storage gr_group; -+}; -+ -+struct group_source_req { -+ u_long gsr_interface; -+ struct sockaddr_storage gsr_group; -+ struct sockaddr_storage gsr_source; -+}; -+ -+struct group_filter { -+ u_long gf_interface; -+ struct sockaddr_storage gf_group; -+ u_long gf_fmode; -+ u_long gf_numsrc; -+ struct in_addr gf_slist[1]; -+}; -+ - struct ip_msfilter { - struct in_addr imsf_multiaddr; - struct in_addr imsf_interface; -@@ -356,6 +388,13 @@ - sockaddr_gen iiNetmask; - } INTERFACE_INFO, *LPINTERFACE_INFO; - -+typedef struct _INTERFACE_INFO_EX { -+ u_long iiFlags; -+ SOCKET_ADDRESS iiAddress; -+ SOCKET_ADDRESS iiBroadcastAddress; -+ SOCKET_ADDRESS iiNetmask; -+} INTERFACE_INFO_EX, *_LPINTERFACE_INFO_EX; -+ - /* - The definition above can cause problems on NT4,prior to sp4. - To workaround, include the following struct and typedef and diff --git a/3rdparty/openpgm-svn-r1085/pgm/win64/mingw-w64-bin_x86-64-linux_4.4.1-1openpgm1.diff b/3rdparty/openpgm-svn-r1085/pgm/win64/mingw-w64-bin_x86-64-linux_4.4.1-1openpgm1.diff deleted file mode 100644 index 237bcb3..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/win64/mingw-w64-bin_x86-64-linux_4.4.1-1openpgm1.diff +++ /dev/null @@ -1,53 +0,0 @@ -diff -urN include-original/./ws2tcpip.h x86_64-w64-mingw32/include/./ws2tcpip.h ---- include-original/./ws2tcpip.h 2009-09-10 13:36:49.000000000 +0800 -+++ x86_64-w64-mingw32/include/./ws2tcpip.h 2010-01-21 14:59:13.000000000 +0800 -@@ -12,6 +12,25 @@ - - #include - -+struct group_req { -+ u_long gr_interface; -+ struct sockaddr_storage gr_group; -+}; -+ -+struct group_source_req { -+ u_long gsr_interface; -+ struct sockaddr_storage gsr_group; -+ struct sockaddr_storage gsr_source; -+}; -+ -+struct group_filter { -+ u_long gf_interface; -+ struct sockaddr_storage gf_group; -+ u_long gf_fmode; -+ u_long gf_numsrc; -+ struct in_addr gf_slist[1]; -+}; -+ - struct ip_msfilter { - struct in_addr imsf_multiaddr; - struct in_addr imsf_interface; -@@ -22,6 +41,15 @@ - - #define IP_MSFILTER_SIZE(numsrc) (sizeof(struct ip_msfilter)-sizeof(struct in_addr) + (numsrc)*sizeof(struct in_addr)) - -+/* RFC 3768 */ -+#define MCAST_JOIN_GROUP 41 -+#define MCAST_LEAVE_GROUP 42 -+#define MCAST_BLOCK_SOURCE 43 -+#define MCAST_UNBLOCK_SOURCE 44 -+#define MCAST_JOIN_SOURCE_GROUP 45 -+#define MCAST_LEAVE_SOURCE_GROUP 46 -+#define MCAST_MSFILTER 47 -+ - #define MCAST_INCLUDE 0 - #define MCAST_EXCLUDE 1 - -@@ -277,6 +305,7 @@ - #define AI_PASSIVE 0x1 - #define AI_CANONNAME 0x2 - #define AI_NUMERICHOST 0x4 -+#define AI_ADDRCONFIG 0x20 - - #ifdef __cplusplus - extern "C" { diff --git a/3rdparty/openpgm-svn-r1085/pgm/wsastrerror.c b/3rdparty/openpgm-svn-r1085/pgm/wsastrerror.c deleted file mode 100644 index 2e21449..0000000 --- a/3rdparty/openpgm-svn-r1085/pgm/wsastrerror.c +++ /dev/null @@ -1,372 +0,0 @@ -/* vim:ts=8:sts=8:sw=4:noai:noexpandtab - * - * Winsock Error strings. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -#ifdef _WIN32 -# include - - -char* -pgm_wsastrerror ( - const int wsa_errno - ) -{ - switch (wsa_errno) { -#ifdef WSA_INVALID_HANDLE - case WSA_INVALID_HANDLE: return _("Specified event object handle is invalid."); -#endif -#ifdef WSA_NOT_ENOUGH_MEMORY - case WSA_NOT_ENOUGH_MEMORY: return _("Insufficient memory available."); -#endif -#ifdef WSA_INVALID_PARAMETER - case WSA_INVALID_PARAMETER: return _("One or more parameters are invalid."); -#endif -#ifdef WSA_OPERATION_ABORTED - case WSA_OPERATION_ABORTED: return _("Overlapped operation aborted."); -#endif -#ifdef WSA_IO_INCOMPLETE - case WSA_IO_INCOMPLETE: return _("Overlapped I/O event object not in signaled state."); -#endif -#ifdef WSA_IO_PENDING - case WSA_IO_PENDING: return _("Overlapped operations will complete later."); -#endif -#ifdef WSAEINTR - case WSAEINTR: return _("Interrupted function call."); -#endif -#ifdef WSAEBADF - case WSAEBADF: return _("File handle is not valid."); -#endif -#ifdef WSAEACCES - case WSAEACCES: return _("Permission denied."); -#endif -#ifdef WSAEFAULT - case WSAEFAULT: return _("Bad address."); -#endif -#ifdef WSAEINVAL - case WSAEINVAL: return _("Invalid argument."); -#endif -#ifdef WSAEMFILE - case WSAEMFILE: return _("Too many open files."); -#endif -#ifdef WSAEWOULDBLOCK - case WSAEWOULDBLOCK: return _("Resource temporarily unavailable."); -#endif -#ifdef WSAEINPROGRESS - case WSAEINPROGRESS: return _("Operation now in progress."); -#endif -#ifdef WSAEALREADY - case WSAEALREADY: return _("Operation already in progress."); -#endif -#ifdef WSAENOTSOCK - case WSAENOTSOCK: return _("Socket operation on nonsocket."); -#endif -#ifdef WSAEDESTADDRREQ - case WSAEDESTADDRREQ: return _("Destination address required."); -#endif -#ifdef WSAEMSGSIZE - case WSAEMSGSIZE: return _("Message too long."); -#endif -#ifdef WSAEPROTOTYPE - case WSAEPROTOTYPE: return _("Protocol wrong type for socket."); -#endif -#ifdef WSAENOPROTOOPT - case WSAENOPROTOOPT: return _("Bad protocol option."); -#endif -#ifdef WSAEPROTONOSUPPORT - case WSAEPROTONOSUPPORT: return _("Protocol not supported."); -#endif -#ifdef WSAESOCKTNOSUPPORT - case WSAESOCKTNOSUPPORT: return _("Socket type not supported."); -#endif -#ifdef WSAEOPNOTSUPP - case WSAEOPNOTSUPP: return _("Operation not supported."); -#endif -#ifdef WSAEPFNOSUPPORT - case WSAEPFNOSUPPORT: return _("Protocol family not supported."); -#endif -#ifdef WSAEAFNOSUPPORT - case WSAEAFNOSUPPORT: return _("Address family not supported by protocol family."); -#endif -#ifdef WSAEADDRINUSE - case WSAEADDRINUSE: return _("Address already in use."); -#endif -#ifdef WSAEADDRNOTAVAIL - case WSAEADDRNOTAVAIL: return _("Cannot assign requested address."); -#endif -#ifdef WSAENETDOWN - case WSAENETDOWN: return _("Network is down."); -#endif -#ifdef WSAENETUNREACH - case WSAENETUNREACH: return _("Network is unreachable."); -#endif -#ifdef WSAENETRESET - case WSAENETRESET: return _("Network dropped connection on reset."); -#endif -#ifdef WSAECONNABORTED - case WSAECONNABORTED: return _("Software caused connection abort."); -#endif -#ifdef WSAECONNRESET - case WSAECONNRESET: return _("Connection reset by peer."); -#endif -#ifdef WSAENOBUFS - case WSAENOBUFS: return _("No buffer space available."); -#endif -#ifdef WSAEISCONN - case WSAEISCONN: return _("Socket is already connected."); -#endif -#ifdef WSAENOTCONN - case WSAENOTCONN: return _("Socket is not connected."); -#endif -#ifdef WSAESHUTDOWN - case WSAESHUTDOWN: return _("Cannot send after socket shutdown."); -#endif -#ifdef WSAETOOMANYREFS - case WSAETOOMANYREFS: return _("Too many references."); -#endif -#ifdef WSAETIMEDOUT - case WSAETIMEDOUT: return _("Connection timed out."); -#endif -#ifdef WSAECONNREFUSED - case WSAECONNREFUSED: return _("Connection refused."); -#endif -#ifdef WSAELOOP - case WSAELOOP: return _("Cannot translate name."); -#endif -#ifdef WSAENAMETOOLONG - case WSAENAMETOOLONG: return _("Name too long."); -#endif -#ifdef WSAEHOSTDOWN - case WSAEHOSTDOWN: return _("Host is down."); -#endif -#ifdef WSAEHOSTUNREACH - case WSAEHOSTUNREACH: return _("No route to host."); -#endif -#ifdef WSAENOTEMPTY - case WSAENOTEMPTY: return _("Directory not empty."); -#endif -#ifdef WSAEPROCLIM - case WSAEPROCLIM: return _("Too many processes."); -#endif -#ifdef WSAEUSERS - case WSAEUSERS: return _("User quota exceeded."); -#endif -#ifdef WSAEDQUOT - case WSAEDQUOT: return _("Disk quota exceeded."); -#endif -#ifdef WSAESTALE - case WSAESTALE: return _("Stale file handle reference."); -#endif -#ifdef WSAEREMOTE - case WSAEREMOTE: return _("Item is remote."); -#endif -#ifdef WSASYSNOTREADY - case WSASYSNOTREADY: return _("Network subsystem is unavailable."); -#endif -#ifdef WSAVERNOTSUPPORTED - case WSAVERNOTSUPPORTED: return _("Winsock.dll version out of range."); -#endif -#ifdef WSANOTINITIALISED - case WSANOTINITIALISED: return _("Successful WSAStartup not yet performed."); -#endif -#ifdef WSAEDISCON - case WSAEDISCON: return _("Graceful shutdown in progress."); -#endif -#ifdef WSAENOMORE - case WSAENOMORE: return _("No more results."); -#endif -#ifdef WSAECANCELLED - case WSAECANCELLED: return _("Call has been canceled."); -#endif -#ifdef WSAEINVALIDPROCTABLE - case WSAEINVALIDPROCTABLE: return _("Procedure call table is invalid."); -#endif -#ifdef WSAEINVALIDPROVIDER - case WSAEINVALIDPROVIDER: return _("Service provider is invalid."); -#endif -#ifdef WSAEPROVIDERFAILEDINIT - case WSAEPROVIDERFAILEDINIT: return _("Service provider failed to initialize."); -#endif -#ifdef WSASYSCALLFAILURE - case WSASYSCALLFAILURE: return _("System call failure."); -#endif -#ifdef WSASERVICE_NOT_FOUND - case WSASERVICE_NOT_FOUND: return _("Service not found."); -#endif -#ifdef WSATYPE_NOT_FOUND - case WSATYPE_NOT_FOUND: return _("Class type not found."); -#endif -#ifdef WSA_E_NO_MORE - case WSA_E_NO_MORE: return _("No more results."); -#endif -#ifdef WSA_E_CANCELLED - case WSA_E_CANCELLED: return _("Call was canceled."); -#endif -#ifdef WSAEREFUSED - case WSAEREFUSED: return _("Database query was refused."); -#endif -#ifdef WSAHOST_NOT_FOUND - case WSAHOST_NOT_FOUND: return _("Host not found."); -#endif -#ifdef WSATRY_AGAIN - case WSATRY_AGAIN: return _("Nonauthoritative host not found."); -#endif -#ifdef WSANO_RECOVERY - case WSANO_RECOVERY: return _("This is a nonrecoverable error."); -#endif -#ifdef WSANO_DATA - case WSANO_DATA: return _("Valid name, no data record of requested type."); -#endif -#ifdef WSA_QOS_RECEIVERS - case WSA_QOS_RECEIVERS: return _("QOS receivers."); -#endif -#ifdef WSA_QOS_SENDERS - case WSA_QOS_SENDERS: return _("QOS senders."); -#endif -#ifdef WSA_QOS_NO_SENDERS - case WSA_QOS_NO_SENDERS: return _("No QOS senders."); -#endif -#ifdef WSA_QOS_NO_RECEIVERS - case WSA_QOS_NO_RECEIVERS: return _("QOS no receivers."); -#endif -#ifdef WSA_QOS_REQUEST_CONFIRMED - case WSA_QOS_REQUEST_CONFIRMED: return _("QOS request confirmed."); -#endif -#ifdef WSA_QOS_ADMISSION_FAILURE - case WSA_QOS_ADMISSION_FAILURE: return _("QOS admission error."); -#endif -#ifdef WSA_QOS_POLICY_FAILURE - case WSA_QOS_POLICY_FAILURE: return _("QOS policy failure."); -#endif -#ifdef WSA_QOS_BAD_STYLE - case WSA_QOS_BAD_STYLE: return _("QOS bad style."); -#endif -#ifdef WSA_QOS_BAD_OBJECT - case WSA_QOS_BAD_OBJECT: return _("QOS bad object."); -#endif -#ifdef WSA_QOS_TRAFFIC_CTRL_ERROR - case WSA_QOS_TRAFFIC_CTRL_ERROR: return _("QOS traffic control error."); -#endif -#ifdef WSA_QOS_GENERIC_ERROR - case WSA_QOS_GENERIC_ERROR: return _("QOS generic error."); -#endif -#ifdef WSA_QOS_ESERVICETYPE - case WSA_QOS_ESERVICETYPE: return _("QOS service type error."); -#endif -#ifdef WSA_QOS_EFLOWSPEC - case WSA_QOS_EFLOWSPEC: return _("QOS flowspec error."); -#endif -#ifdef WSA_QOS_EPROVSPECBUF - case WSA_QOS_EPROVSPECBUF: return _("Invalid QOS provider buffer."); -#endif -#ifdef WSA_QOS_EFILTERSTYLE - case WSA_QOS_EFILTERSTYLE: return _("Invalid QOS filter style."); -#endif -#ifdef WSA_QOS_EFILTERTYPE - case WSA_QOS_EFILTERTYPE: return _("Invalid QOS filter type."); -#endif -#ifdef WSA_QOS_EFILTERCOUNT - case WSA_QOS_EFILTERCOUNT: return _("Incorrect QOS filter count."); -#endif -#ifdef WSA_QOS_EOBJLENGTH - case WSA_QOS_EOBJLENGTH: return _("Invalid QOS object length."); -#endif -#ifdef WSA_QOS_EFLOWCOUNT - case WSA_QOS_EFLOWCOUNT: return _("Incorrect QOS flow count."); -#endif -#ifdef WSA_QOS_EUNKOWNPSOBJ - case WSA_QOS_EUNKOWNPSOBJ: return _("Unrecognized QOS object."); -#endif -#ifdef WSA_QOS_EPOLICYOBJ - case WSA_QOS_EPOLICYOBJ: return _("Invalid QOS policy object."); -#endif -#ifdef WSA_QOS_EFLOWDESC - case WSA_QOS_EFLOWDESC: return _("Invalid QOS flow descriptor."); -#endif -#ifdef WSA_QOS_EPSFLOWSPEC - case WSA_QOS_EPSFLOWSPEC: return _("Invalid QOS provider-specific flowspec."); -#endif -#ifdef WSA_QOS_EPSFILTERSPEC - case WSA_QOS_EPSFILTERSPEC: return _("Invalid QOS provider-specific filterspec."); -#endif -#ifdef WSA_QOS_ESDMODEOBJ - case WSA_QOS_ESDMODEOBJ: return _("Invalid QOS shape discard mode object."); -#endif -#ifdef WSA_QOS_ESHAPERATEOBJ - case WSA_QOS_ESHAPERATEOBJ: return _("Invalid QOS shaping rate object."); -#endif -#ifdef WSA_QOS_RESERVED_PETYPE - case WSA_QOS_RESERVED_PETYPE: return _("Reserved policy QOS element type."); -#endif - default: return _("Unknown."); - } -} - -char* -pgm_adapter_strerror ( - const int adapter_errno - ) -{ - switch (adapter_errno) { -#ifdef ERROR_ADDRESS_NOT_ASSOCIATED - case ERROR_ADDRESS_NOT_ASSOCIATED: return _("DHCP lease information was available."); -#endif -#ifdef ERROR_BUFFER_OVERFLOW - case ERROR_BUFFER_OVERFLOW: return _("The buffer to receive the adapter information is too small."); -#endif -#ifdef ERROR_INVALID_DATA - case ERROR_INVALID_DATA: return _("Invalid adapter information was retrieved."); -#endif -#ifdef ERROR_INVALID_PARAMETER - case ERROR_INVALID_PARAMETER: return _("One of the parameters is invalid."); -#endif -#ifdef ERROR_NOT_ENOUGH_MEMORY - case ERROR_NOT_ENOUGH_MEMORY: return _("Insufficient memory resources are available to complete the operation."); -#endif -#ifdef ERROR_NO_DATA - case ERROR_NO_DATA: return _("No adapter information exists for the local computer."); -#endif -#ifdef ERROR_NOT_SUPPORTED - case ERROR_NOT_SUPPORTED: return _("The GetAdaptersInfo function is not supported by the operating system running on the local computer.."); -#endif - default: return _("Other."); - } -} - -char* -pgm_win_strerror ( - char* buf, - size_t buflen, - const int win_errno - ) -{ - const DWORD nSize = buflen; - FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, - NULL, /* source */ - win_errno, /* message id */ - MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* language id */ - (LPTSTR)buf, - buflen, - NULL); /* arguments */ - return buf; -} -#endif /* _WIN32 */ - -/* eof */ diff --git a/3rdparty/openpgm-svn-r1135-0001-sigsegv-in-txw.patch b/3rdparty/openpgm-svn-r1135-0001-sigsegv-in-txw.patch new file mode 100644 index 0000000..af6d4fd --- /dev/null +++ b/3rdparty/openpgm-svn-r1135-0001-sigsegv-in-txw.patch @@ -0,0 +1,28 @@ +Problem: OpenPGM generates a SIGSEGV upon accessing peer->sock->use_pgmcc. + This is because the code assumes that the queue list entry comes first + in the definition of struct pgm_peer_t, which it does not (anymore?). + +diff -Naur openpgm-r1135-pristine/pgm/receiver.c openpgm-svn-r1135/pgm/receiver.c +--- openpgm-r1135-pristine/pgm/receiver.c 2010-09-06 20:41:52.000000000 +0200 ++++ openpgm-svn-r1135/pgm/receiver.c 2010-09-24 12:40:07.000000000 +0200 +@@ -71,7 +71,9 @@ + pgm_assert (NULL != window); + pgm_assert (NULL != window->ack_backoff_queue.tail); + +- const struct pgm_peer_t* peer = (const struct pgm_peer_t*)window->ack_backoff_queue.tail; ++ const struct pgm_peer_t* peer = (const struct pgm_peer_t*)window->ack_backoff_queue.tail->data; ++ pgm_assert (NULL != peer); ++ + pgm_assert (peer->sock->use_pgmcc); + return peer->ack_rb_expiry; + } +@@ -416,6 +418,9 @@ + sock->ack_c_p); + peer->spmr_expiry = now + sock->spmr_expiry; + ++/* Prepare ack_link */ ++ peer->ack_link.data = peer; ++ + /* add peer to hash table and linked list */ + pgm_rwlock_writer_lock (&sock->peers_lock); + pgm_peer_t* entry = _pgm_peer_ref (peer); diff --git a/3rdparty/openpgm-svn-r1135-0002-correct-checksum-calculation.patch b/3rdparty/openpgm-svn-r1135-0002-correct-checksum-calculation.patch new file mode 100644 index 0000000..b78dc3c --- /dev/null +++ b/3rdparty/openpgm-svn-r1135-0002-correct-checksum-calculation.patch @@ -0,0 +1,17 @@ +Problem: OpenPGM may calculate incorrect checksums when sending RDATA packets + if no ODATA packet has been sent before. When and why this + happens exactly is unknown. +Solution: Always force recomputation of checksums until a more suitable + solution is found. + +--- openpgm-r1135-pristine/pgm/source.c 2010-09-09 03:24:47.000000000 +0200 ++++ openpgm-svn-r1135/pgm/source.c 2010-09-30 18:32:04.000000000 +0200 +@@ -2295,7 +2295,7 @@ + header->pgm_checksum = 0; + const size_t pgm_header_len = tpdu_length - ntohs(header->pgm_tsdu_length); + uint32_t unfolded_header = pgm_csum_partial (header, pgm_header_len, 0); +- uint32_t unfolded_odata = pgm_txw_get_unfolded_checksum (skb); ++ uint32_t unfolded_odata = pgm_csum_partial (skb->data, ntohs(header->pgm_tsdu_length), 0); + header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, unfolded_odata, pgm_header_len)); + + /* congestion control */ diff --git a/3rdparty/openpgm-svn-r1135-0003-fix-rdata-congestion-control.patch b/3rdparty/openpgm-svn-r1135-0003-fix-rdata-congestion-control.patch new file mode 100644 index 0000000..c6e721d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135-0003-fix-rdata-congestion-control.patch @@ -0,0 +1,42 @@ +Problem: When enough lost data accumulates, RDATA packets are sent at + a massively reduced rate and block the congestion control + window for subsequent RDATA packets. This results in a + transmission rate of close to zero for up to 15 seconds in + experiments. +Solution: Allow sending of RDATA packets even when congestion control + would normally disallow it, but still consume a token if + there is one left. + +diff -Naur openpgm-r1135-pristine/pgm/source.c openpgm-svn-r1135/pgm/source.c +--- openpgm-r1135-pristine/pgm/source.c 2010-09-09 03:24:47.000000000 +0200 ++++ openpgm-svn-r1135/pgm/source.c 2010-09-24 17:40:12.000000000 +0200 +@@ -2299,13 +2299,13 @@ + header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, unfolded_odata, pgm_header_len)); + + /* congestion control */ +- if (sock->use_pgmcc && +- sock->tokens < pgm_fp8 (1)) +- { ++// if (sock->use_pgmcc && ++// sock->tokens < pgm_fp8 (1)) ++// { + // pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Token limit reached.")); +- sock->blocklen = tpdu_length; +- return FALSE; +- } ++// sock->blocklen = tpdu_length; ++// return FALSE; ++// } + + const ssize_t sent = pgm_sendto (sock, + sock->is_controlled_rdata, /* rate limited */ +@@ -2323,7 +2323,8 @@ + const pgm_time_t now = pgm_time_update_now(); + + if (sock->use_pgmcc) { +- sock->tokens -= pgm_fp8 (1); ++ if (sock->tokens >= pgm_fp8 (1)) ++ sock->tokens -= pgm_fp8 (1); + sock->ack_expiry = now + sock->ack_expiry_ivl; + } + diff --git a/3rdparty/openpgm-svn-r1135/doc/draft-ietf-rmt-bb-pgmcc-03.txt b/3rdparty/openpgm-svn-r1135/doc/draft-ietf-rmt-bb-pgmcc-03.txt new file mode 100644 index 0000000..6f1869c --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/doc/draft-ietf-rmt-bb-pgmcc-03.txt @@ -0,0 +1,1226 @@ + +Internet Engineering Task Force RMT WG +INTERNET-DRAFT Luigi Rizzo/U. Pisa +draft-ietf-rmt-bb-pgmcc-03.txt Gianluca Iannaccone/Intel + Lorenzo Vicisano/Cisco + Mark Handley/UCL + 12 July 2004 + Expires: January 2005 + + + PGMCC single rate multicast congestion control: + Protocol Specification + + + +Status of this Document + +This document is an Internet-Draft and is in full conformance with all +provisions of Section 10 of RFC2026. + +Internet-Drafts are working documents of the Internet Engineering Task +Force (IETF), its areas, and its working groups. Note that other groups +may also distribute working documents as Internet-Drafts. + +Internet-Drafts are valid for a maximum of six months and may be +updated, replaced, or obsoleted by other documents at any time. It is +inappropriate to use Internet-Drafts as reference material or to cite +them other than as a "work in progress". + +The list of current Internet-Drafts can be accessed at +http://www.ietf.org/ietf/1id-abstracts.txt + +To view the list Internet-Draft Shadow Directories, see +http://www.ietf.org/shadow.html. + +This document is a product of the IETF RMT WG. Comments should be +addressed to the authors, or the WG's mailing list at rmt@lbl.gov. + + + Abstract + + + This document describes PGMCC, a single rate multicast + congestion control scheme which is TCP-friendly and achieves + scalability, stability and fast response to variations in + network conditions. PGMCC is suitable for both non-reliable + + + +Rizzo/Iannaccone/Vicisano/Handley [Page 1] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + + and reliable data transfers. It is mainly designed for NAK- + based multicast protocols, and uses a window-based, TCP-like + control loop using positive ACKs between one representative of + the receiver group (the ACKER) and the sender. The ACKER is + selected dynamically and may change over time. + + PGMCC is made of two components: a window-based control loop, + which closely mimics TCP behavior, and a fast and low-overhead + procedure to select (and track changes of) the ACKER. The + scheme is robust to measurement errors, and supports fast + response to changes in the receiver set and/or network + conditions. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Rizzo/Iannaccone/Vicisano/Handley [Page 2] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + + Table of Contents + + + 1. Introduction. . . . . . . . . . . . . . . . . . . . . . 4 + 1.1. Terminology. . . . . . . . . . . . . . . . . . . . . 4 + 2. Protocol Overview . . . . . . . . . . . . . . . . . . . 4 + 2.1. Packet Contents. . . . . . . . . . . . . . . . . . . 6 + 2.1.1. Data Packets. . . . . . . . . . . . . . . . . . . 6 + 2.1.2. Feedback Packets. . . . . . . . . . . . . . . . . 7 + 2.1.3. Field sizes and formats . . . . . . . . . . . . . 8 + 2.2. Window-based controller. . . . . . . . . . . . . . . 9 + 2.3. Acker Selection. . . . . . . . . . . . . . . . . . . 11 + 2.3.1. Initial Acker election. . . . . . . . . . . . . . 11 + 2.3.2. Acker dropouts. . . . . . . . . . . . . . . . . . 12 + 2.4. TCP Throughput Equation. . . . . . . . . . . . . . . 12 + 2.5. RTT measurement. . . . . . . . . . . . . . . . . . . 13 + 2.5.1. Explicit Timestamp. . . . . . . . . . . . . . . . 13 + 2.5.2. Implicit timestamp. . . . . . . . . . . . . . . . 13 + 2.5.3. Sequence numbers. . . . . . . . . . . . . . . . . 14 + 2.5.4. Recommendations . . . . . . . . . . . . . . . . . 15 + 2.6. Loss rate measurement. . . . . . . . . . . . . . . . 15 + 2.7. Timeouts . . . . . . . . . . . . . . . . . . . . . . 16 + 2.8. Interaction with feedback suppression + schemes . . . . . . . . . . . . . . . . . . . . . . . . . 16 + 2.9. Interaction with ECN . . . . . . . . . . . . . . . . 17 + 3. Procedures - Sender . . . . . . . . . . . . . . . . . . 17 + 4. Procedures -- Receiver. . . . . . . . . . . . . . . . . 18 + 5. Security Considerations . . . . . . . . . . . . . . . . 19 + 6. Authors' Addresses. . . . . . . . . . . . . . . . . . . 20 + 7. Acknowledgments . . . . . . . . . . . . . . . . . . . . 20 + 8. Full Copyright Statement. . . . . . . . . . . . . . . . 21 + + + + + + + + + + + + + + + + + + + + +Rizzo/Iannaccone/Vicisano/Handley [Page 3] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +1. Introduction + +This document describes PGMCC, a single rate multicast congestion +control scheme which is TCP-friendly and achieves scalability, stability +and fast response to variations in network conditions. + +PGMCC is designed for multicast sessions with one sender and one or more +receivers, and is a good match for transport protocols using negative +acknowledgements (NAKs) to collect feedback from the receivers. The +congestion control scheme implemented by PGMCC closely mimics the +congestion-control behavior of TCP, as it uses a window-based control +loop which is run between the sender and a selected receiver called the +ACKER. The role of the ACKER is to provide timely feedback in the same +way as a TCP receiver; additionally, the ACKER is selected dynamically +among the receivers as the one which would experience the lowest +throughput if separate TCP sessions were run between the sender and each +of the receivers. + +Scalability in PGMCC comes from the use of negative acknowledgements +(NAKs) for collecting feedback from receivers other than the ACKER. As +a consequence, the usual techniques for NAK suppression and aggregation +can be used to reduce the amount of feedback to the source and improve +the scalability of the scheme. + +PGMCC is designed to completely decouple congestion control from data +integrity. As a consequence, the scheme can work with both reliable data +transfer and unreliable communication protocols such as those used for +video or audio streaming. + +While designed with multicast in mind, PGMCC can be equally used as a +replacement for TCP for unicast sessions which require a lower degree of +reliability than what TCP offers. + + +1.1. Terminology + +In this document, the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", +"SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and +"OPTIONAL" are to be interpreted as described in RFC 2119 and indicate +requirement levels for compliant PGMCC implementations. + + +2. Protocol Overview + +PGMCC is based on two separate but complementary mechanisms: + + o A window-based control loop which closely emulates TCP congestion + control. + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2. [Page 4] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + + The window-based control loop is simply an adaptation of the TCP + congestion control scheme to transport protocols where missing + (because of network errors or congestion) data packets are not + necessarily retransmitted, and so the congestion control scheme + cannot rely on cumulative acknowledgements. In PGMCC, the + ``congestion window'' is simulated using a token-based scheme which + permits congestion control to be decoupled from retransmission + state. One of the receivers in the group operates as the ACKER, i.e. + the node in charge of sending positive acknowledgements back to the + source and thus controlling the rate of the transfer. + + + o A procedure to select the ACKER. + The purpose of this procedure is to make sure that, in presence of + multiple receivers, the ACKER is dynamically selected to be the + receiver which would have the lowest throughput if separate TCP + sessions were run between the sender and each receiver. + For the acker selection mechanism, PGMCC uses a throughput equation + to determine the expected throughput for a given receiver as a + function of the loss rate and round-trip time. Unlike other schemes + [2], the TCP throughput equation is not used to determine the actual + sending rate, which is completely controlled by the window-based + control loop. + + +In principle, PGMCC's congestion control mechanism works as follows: + + + o Receivers measure the loss rate and feed this information back to + the sender, either in ACK or NAK messages. + + + o The sender also uses these feedback messages to measure the round- + trip time (RTT) to each receiver. + + + o The loss rate and RTT are then fed into PGMCC's throughput equation, + to determine the expected throughput to that receiver. + + + o The sender then selects as the acker the receiver with the lowest + expected throughput, as computed by the equation. + +The dynamics of the acker selection mechanism are sensitive to how the +measurements are performed and applied. In the rest of this document we +suggest specific mechanisms to perform and apply these measurements. +Other mechanisms are possible, but it is important to understand how the +interactions between mechanisms affect the dynamics of PGMCC. + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2. [Page 5] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +2.1. Packet Contents + +Before specifying the sender and receiver functionality, we describe the +information required by PGMCC to perform its tasks. This information is +carried in the data packets sent by the sender, and in the feedback +packets sent by the receiver. As PGMCC will be used along with some +transport protocol, the actual data and feedback packets will contain +further information for use by the protocol itself. For this reason, we +do not specify packet formats, as these depend on the details of the +transport protocol used. + +Note that the requirements of the transport protocol in terms of packet +generation may differ from those of PGMCC. As an example, most NAK-based +reliable multicast protocols do not use positive acknowledgements, but +PGMCC requires ACKs for clocking out data packets; unreliable transport +protocols might have no interest in generating NAKs for data integrity +purposes, yet PGMCC depends on NAKs reaching the data sender in order to +elect the ACKER. + + +Implementors may decide to insert PGMCC-related information in already +existing protocol packets whenever possible, but in cases such as the +ones described in the previous paragraph, it might be necessary to +define and generate new packets exclusively for congestion control +purposes. As an example, in a prototype implementation of PGMCC on top +of the PGM protocol [7], some of the information used by PGMCC is +already present in the original protocol packets, and PGMCC-specific +information is carried as PGM options in ODATA and NAK packets. However, +a new packet type has been defined for ACKs, which are generated +according to the rules defined in this document. + + +2.1.1. Data Packets + +Each data packet sent by the data sender contains the following +information: + + + o A SEQUENCE NUMBER. This number is incremented by one for each data + packet transmitted. The field must be sufficiently large that it + does not wrap causing two different packets with the same sequence + number to be in the receiver's recent packet history at the same + time. + + + o A TIMESTAMP (or equivalent information, see Section 2.5) indicating + when the packet with this sequence number has been sent. There is + no requirement for synchronized clocks between the sender and the + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2.1.1. [Page 6] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + + receivers. The timestamp is used to measure network round-trip + times, so needs sufficient resolution for this task. A resolution + of 1ms would be adequate. + + + o The ACKER IDENTITY, i.e. the identity of the receiver in charge of + sending an acknowledgement for this data packet. The ACKER is + elected as a result of the process described in Section 2.3. + A special value is used to indicate that no ACKER is designated for + this packet -- this can happen at the beginning of a session or when + the current ACKER leaves the group. Receivers interpret this value + as a request to elect a new acker. + + +2.1.2. Feedback Packets + +There are two types of feedback packets used by PGMCC: ACK packets and +NAK packets. +ACK packets are generated by the current ACKER, and are used to detect +loss or successful delivery of packets, and to regulate the throughput +accordingly. ACK packets also contain information used to determine the +TCP-equivalent throughput for the ACKER. +NAK packets are sent by any receiver who experiences loss. They contain +information used to determine the TCP-equivalent throughput for that +receiver. In an actual protocol instantiation (such as PGM [7]), NAK +packets might also be used by the protocol to request the retransmission +of specific packets, and indicate the identity of the packet being +requested. + +Both ACK and NAK packets are sent by data receivers, and contain the +following information: + + + o The TIMESTAMP (or equivalent information) derived from the most + recently received data packet according to one of the techniques + described in Section 2.5. + This value is used by the sender to measure the RTT to the receiver + who generated this feedback packet. + + + o ``p'', the receiver's current estimate of the LOSS RATE. The loss + rate is measured by receivers as described in Section 2.6 + +In addition to the above, ACK packets (sent by the acker designated in +the corresponding data packets) must also contain the following +information: + + + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2.1.2. [Page 7] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + + o RX_MAX, the highest sequence number among received data packets + (taking care to deal with sequence number wrapping correctly). + + o ACK_BITMAP, a bitmap indicating the receive status of the latest N + (typically N=32) data packets with sequence numbers RX_MAX-(N-1) to + RX_MAX. + + +This information is used by the sender to record which packets have been +received or lost, and manipulate the transmit window accordingly. Note +that each ACK packet contains information about multiple packets, and +this increases the robustness of the scheme to loss of ACK packets. +This is necessary because ACKs are not sent reliably (unlike TCP's ACKs, +which are cumulative). + + +2.1.3. Field sizes and formats + +The following sizes and formats are suggested for the various fields +used by PGMCC and transmitted over the network: + + + o SEQUENCE NUMBERS + 32 bit, unsigned, network order. + + + o TIMESTAMPS + 32 bit, unsigned, network order. A resolution of 1ms or better is + desirable. + + + o ACKER IDENTITY + Same size and format of a network layer address (e.g. 32 bit for + IPv4). Note though that using an IP address for the Acker Identify + will cause problems with NAT traversal. Transport protocol + designers might examine the SSRC mechanism used by RTP [6] as an + alternative form of node identifier that could be used as Acker + Identity. + + + o LOSS RATE (``p'') + 16-bit unsigned integer, in network format, with 0 indicating no + loss and 2^16-1 indicating 100% loss. + + + o ACK BITMAP + 32-bit, in network format, with least significant bit indicating + receive status of packet RX_MAX. + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2.1.3. [Page 8] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +2.2. Window-based controller + +In a window-based congestion control scheme such as TCP, the +``congestion window'' represents, among other things, the maximum amount +of packets in flight at any time, which in turn controls the throughput +of the session. The sender keeps track of the actual number of packets +in flight, basing on its transmissions and the reception of +acknowledgements. + +The sender may dynamically change the size of the window, according to +the congestion control scheme being used. In TCP, and PGMCC, an +``Additive Increase Multiplicative Decrease'' (AIMD) scheme is used: in +absence of loss, the window is increased by some fixed amount (typically +one packet) per round trip time (RTT), whereas upon loss the window is +reduced to a fraction of its original value (typically halved) in each +RTT in which a loss event is experienced. + +In PGMCC the window is managed using a token-based mechanism, controlled +by two variables: + + o A ``Window Size'', W, which describes the current window size in + packets. + + o A ``Token Count'', T, which indicates the number of packets that can + be transmitted. T is bounded above by W. It is decremented every + time a packet is transmitted, and incremented every time an ACK is + received, according to the rules below. + +Note that these two variables need to hold non-integer data. Typically +a fixed point representation with at least 16 bits for both integer and +fractional parts would be acceptable for implementation purposes. + +The information contained in each ACK is used to determine how many new +packets are acknowledged by that ACK, and whether there are +unacknowledged packets which were not reported in previous ACKs. The +sender also schedules a timeout to react in case no ACKs are received. + +The sender behaves as follows: + + + o INITIALIZATION + At startup, or after a timeout, both W and T are set to 1. + + + o ACK RECEPTION, NO LOSS DETECTED + If the incoming ACK reports new acknowledged packets, and no loss + (as defined in the next paragraph) is detected, then the window is + inflated by one packet per RTT. + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2.2. [Page 9] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + + NOTE: during the slow-start phase, TCP opens the window + exponentially up to the SSTHRESH value, which is computed by TCP + according to the dynamics of the session and updated upon losses. + + We do recommend that PGMCC uses a similar strategy, but using a + fixed, small value for SSTHRESH (e.g. 4 packets). In fact, due to + the dynamicity of the ACKER, which might change on every single + packet, it is hard to compute a reliable estimate of the SSTHRESH + without keeping state for multiple receivers, and the benefits are + small in any event. + + In summary, the reaction to ACK reception on no loss modifies T and + W as follows (here, N is the number of new packets acknowledged by + the incoming ACK): + + if (W < SSTHRESH) then + D = min(N, SSTHRESH - W) // use the first D acks for + exp.opening + N = N - D // and the remaining ones for + linear opening + T = T + 2*D + W = W + D + endif + // do linear window opening with the remaining acks + T = T + N * ( 1 + 1/W ) + W = W + N/W + + + o PACKET TRANSMISSION + One token is consumed for each packet transmitted: + + T = T - 1 + + + o ACK RECEPTION, LOSS DETECTED + If the incoming ACK reports an unacknowledged data packet which is + followed by at least 3 acknowledged data packets, then the packet is + assumed to be lost and PGMCC reacts by halving the window, in the + same way as TCP after 3 duplicate acknowledgements. This is + achieved by modifying T and W as follows: + + T = T - W/2 , W = W/2 + + to simulate the multiplicative decrease. + Additionally, all window manipulation is suspended for the + subsequent RTT. This is achieved by recording the current transmit + sequence number, and canceling any further manipulation of the + window until feedback is received for the next transmitted packet, + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2.2. [Page 10] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + + or until a timeout occurs. + + + + +2.3. Acker Selection + +The ACKER selection process in PGMCC aims at locating the receiver which +would have the lowest throughput if each receiver were using a separate +TCP connection to transfer data. + +Because the steady-state throughput of a TCP connection can be +characterized in a reasonably accurate way in terms of its loss rate and +round trip time [3], the throughput for each receiver can be estimated +by using these two parameters. + +Whenever an ACK or NAK packet from any of the receivers reaches it, the +sender is able to compute the expected throughput T_i for that receiver +by using the equation shown in Section 2.4, with the round trip time RTT +and loss rate p and measured as described in Sections 2.5 and 2.6, +respectively. At any given time, the sender stores the expected +throughput for the current ACKER, T_acker. This value is updated every +time an ACK or NAK from the current ACKER is received (note that, after +a new ACKER is selected, the sender will typically receive ACKs from the +old ACKER for one RTT, and the feedback from different ACKERs might be +interleaved if the paths leading to them have different round trip +times). + +Whenever an ACK or NAK is received from another node i (a previous ACKER +or some other receiver), the expected throughput T_i for that node is +computed, and compared with T_acker. Node i is selected as the new +acker if + + T_i < C * T_acker + +where the constant C between 0 and 1 provides some hysteresis and avoids +too frequent oscillations in the choice of the ACKER. A suggested value +for C is 0.75. + +Note that, from an implementation point of view (see Section 2.4), it is +more convenient to compute T_i ^(-2), so the above equation must be +modified accordingly. + + +2.3.1. Initial Acker election + +Upon reception of a data packet reporting that no acker is currently +selected, receivers generate a dummy NAK report which is used to elect + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2.3.1. [Page 11] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +the initial acker. The NAK is sent with the usual feedback suppression +mechanism dictated by the transport protocol (possibly with shorter time +constants) to avoid feedback implosion, and the sender will select the +source of the first incoming NAK as the new ACKER. + + +2.3.2. Acker dropouts + + +If the ACKER decides to disconnect from the session, it can cause the +session to stop. To avoid this, it is recommended that an ACKER deciding +to leave the session informs the sender by sending an ACK packet (or a +duplicate) carrying an "ACKER_LEAVING" option. The reception of this +packet by the sender will in turn trigger an initial acker election +phase. + + + +2.4. TCP Throughput Equation + +Any realistic equation of TCP throughput as a function of loss event +rate and RTT should be suitable for use in PGMCC. Unlike other schemes +[2] where the throughput equation directly controls the transmit rate, +in PGMCC the equation is used only for acker selection purposes, and the +throughput values are only compared among themselves. As a consequence, +we can use the following equation, derived from the one presented in [3] +by setting RTO = 4 * RTT (as it is common practice): + + M = 1/T = RTT_i * sqrt(p) * (1 + 9*p * (1 + 32*(p)^2)) + + +where + + M = 1/T is proportional to the inverse of the throughput for the + receiver under consideration; + + RTT is the round trip time for the receiver under consideration; + + p is the loss rate for the receiver under consideration, between 0 + and 1.0; + +and multiplying constants are omitted. + +The above equation is accurate on a wide range of loss rates, and also +covers situations where retransmission timeouts have a significant +impact on the throughput of the protocol. + +Note that when p=0, the equation yields 1/T = M = 0. This does not + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2.4. [Page 12] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +constitute a problem as we can still compare the M values computed for +different receivers to determine the acker. Also note that it is easier +to compute M^2 instead of M, because the former does not require the use +of sqrt(). + +In future, different throughput equations may be substituted for this +equation. The requirement is that the throughput equation be a +reasonable approximation of the sending rate of TCP for conformant TCP +congestion control. + +The parameters p and RTT need to be measured or calculated by a PGMCC +implementation. The measurement of RTT is specified in Section 2.5; the +measurement of p is specified in Section 2.6. + +2.5. RTT measurement + +In PGMCC, the RTT is measured by the sender making use of the timestamp +(or equivalent information) echoed back by each receiver in feedback +messages. Three procedures are possible to measure the RTT, as follows. +In no case is it required to have clock synchronization between sender +and receivers. + + +2.5.1. Explicit Timestamp + +This first technique relies on the transmission of a timestamp TS_j with +each data packet j. +The receiver will record the most recently received timestamp, and will +echo it back to the source when generating an ACK or a NAK. If the +feedback is delayed, the time elapsed between the reception of the +timestamp and the generation of the feedback should be added to the +echoed timestamp. +The sender computes the RTT by subtracting the received timestamp from +the current value of the clock. + +The resolution of the timestamp value should be good enough for +reasonable precision measurement of typical network round trip times. If +receivers need to apply correction for delayed feedback, it is necessary +that receivers know the resolution of the timestamp clock. A suggested +value is 1ms. + + +2.5.2. Implicit timestamp + +With this technique, the sender will record a timestamp TS_j for each +transmitted data packet j, but the timestamp will not be transmitted +with the packet itself. +The receiver will record the most recently received sequence number, and + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2.5.2. [Page 13] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +will echo it back to the source when generating an ACK or a NAK. +The sender computes the RTT by looking up the timestamp associated with +the sequence number received in the feedback packet, and subtracting it +from the current clock value. + +If the feedback from the receiver is delayed, as it is commonly the case +for NAKs, the receiver can compute, and send back to the source, a +correction term corresponding to the time elapsed between the reception +of the timestamp and the generation of the feedback. The correction term +will then be subtracted by the sender in order to obtain the correct +estimate of the RTT. + +This RTT measurement technique is equivalent to the previous one, but it +saves some space in data packets as the timestamp does not need to be +sent explicitly. Feedback packets might become larger if the correction +value is transmitted explicitly; but in many cases, the sequence number +will already be present for other reasons (e.g. ACK packets), and +wherever space is a concern the sequence number and the correction term +can be packed in a single 32-bit word without loss of precision. + + +2.5.3. Sequence numbers + +This technique is the least precise, but it does not rely on the +presence of a high resolution clock on the nodes. +The sender will not compute any timestamp, and just send data packets +with their sequence number j. +The receiver will record the most recently received sequence number, and +will echo it back to the source when generating an ACK or a NAK. +The sender computes the RTT as the difference between the most recently +sent sequence number and the sequence number received from the ACK or +NAK packet. + +Note that in this case the RTT is not measured in seconds, but in +"sequence numbers", which are monotonically, but not uniformly, +increasing with time. The two measurements are equivalent if the sender +transmits at a constant rate. When the data rate changes over time (as +it is normally happens, given that PGMCC controls the actual data rate), +then the "measured" RTT values grow with the actual transmit rate. This +can influence the correctness of the results when comparing two +measurement done over different and only partially overlapping time (and +sequence number) intervals where the transmit rate incurs a significant +change. + + + + + + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2.5.3. [Page 14] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +2.5.4. Recommendations + +Whenever possible, the measurement of the RTT should be carried out +using either explicit or implicit timestamps, and by keeping track of +the "correction term" (the delay between data reception and feedback +generation). + +If the receiver does not have a clock with a suitable resolution, the +correction term might not be present (or be inaccurate). In this case +the timestamps received by the sender on NAK packets might be in error, +in the worst case, by as much as the packet interarrival time. This +error will normally not be present on ACK packets, which are sent +immediately. A suitable correction should be applied by the sender in +order to avoid systematic errors. + +The measurement based on sequence numbers is less accurate, but also +less sensitive to errors due to the lack of the correction term. In +fact, the measurement error induced by the lack of the correction term +can be at most one unit. This suggests that, when the correction term +is not available, measurements based on sequence numbers should be +favoured. Simulations have shown that the acker selection mechanism +performs moderately better when the RTT measurement is based on +timestamps, but performance is reasonably good also with measurements +based on sequence numbers. + + + +2.6. Loss rate measurement + + +The loss measurement in PGMCC is entirely performed by receivers. The +measurement results do not directly influence the transmit rate, but are +only used for comparison purposes. As a consequence, the scheme is +reasonably robust to different measurement techniques, as long as they +are not influenced too strongly by single loss events. + +The main method suggested for loss measurement is Exponentially Weighted +Moving Average (EWMA), which is formally equivalent to a single-pole +digital low pass filter applied to a binary signal x_i, where x_i = 1 if +packet i is lost, x_i = 0 if packet i is successfully received. + +The loss rate p_i upon reception or detection of loss of packet i is +computed as + + + p_i = c_p * p_{i-1} + (1 - c_p ) * p_i + where the constant c_p between 0 and 1 is related to the bandpass of +the filter. Experiments have shown good performance with c = 500/65536, + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2.6. [Page 15] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +and computations performed with fixed point arithmetic and 16 fractional +digits. + +As an alternative to EWMA, the technique used in TFRC [2] can be +adopted. Simulations have shown a moderate improvement in the acker +selection mechanism by measuring loss using the TFRC loss estimator, +which is however slightly more expensive to compute than the EWMA loss +estimator in presence of packet reordering. + + +2.7. Timeouts + + +When a packet is transmitted, the sender schedules a timeout to prevent +stalls upon loss of ACKs or disconnection of the ACKER. In TCP, which +has a similar problem, the timeout value is computed by accumulating +statistics (SRTT and RTTVAR) on RTT samples, starting from a default +initial value (3s) when no RTT samples are available. + +PGMCC can use a similar scheme to compute the timeouts, remembering that +upon ACKER changes (which may be very frequent), the computation of SRTT +and RTTVAR must be restarted from the beginning, unless the sender +decides to keep state for at least a small number of recent ackers. + +Because the ACKER can leave the group without notifying the sender, +after a number of successive timeouts the sender MUST force the election +of a new ACKER. We recommend this new election to be performed after +two successive timeouts. + + +2.8. Interaction with feedback suppression schemes + + +Several schemes are used by NAK-based multicast protocols to reduce the +amount of feedback directed toward the source and make the protocol +scale with large populations of receivers. Such schemes typically rely +on randomly delaying NAK generation, and suppressing pending NAKs when +an equivalent NAK or a retransmission is heard; or, intermediate nodes +such as routers can implement some form of feedback aggregation and +filtering. + +Such schemes might prevent NAKs from potential ACKER candidates from +reaching the source. This filtering might impact the speed at which +PGMCC selects the correct ACKER, though initial experience from +simulations seem to suggest that PGMCC behavior is not severely affected +by NAK suppression schemes. + + + + + +Rizzo/Iannaccone/Vicisano/Handley Section 2.8. [Page 16] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +2.9. Interaction with ECN + + +PGMCC can use ECN notifications in much the same way as actual losses, +and use such notifications to control the throughput of the session. + +At the receiver, ECN-marked data packets can be considered as lost +packets for the purpose of loss rate computation and ACK/NAK generation. +If the ACKER sends an ACK for ECN-marked packets, that ACK MUST report +that the packet being acknowledged that was ECN marked. Similarly the +ACKER must indicate in the ACK packet's received packets bitmap that the +packet was ECN-marked, or that the packet was lost. + +We note that to support use of the ECN nonce, the ACK packet's received +packets bitmap would require two bits per packet being reported. + + +3. Procedures - Sender + +The following pseudo-code specifies the complete behavior of the sender +in PGMCC. + + +initialization: + T = 1 ; W = 1 ; /* initialize window and number of tokens */ + RETRY = 0 ; /* number of consecutive timeouts so far */ + < initialize p, RTT for acker to default values > + ACKER = NO_ACKER; /* no acker is known */ + < initialize sequence numbers > + QUEUED = 0; /* packets waiting to be transmitted */ + +on transmission request: + send_packet() ; + +on timeout expiration : + T = 1 ; W = 1 ; /* initialize window and number of tokens */ + if (RETRY < RETRY_MAX) + RETRY = RETRY + 1 + else + ACKER = NO_ACKER ; /* old acker is not valid anymore */ + send_packet() ; + + + + + + + + + + +Rizzo/Iannaccone/Vicisano/Handley Section 3. [Page 17] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +on ACK/NAK reception from receiver I : + < compute p and RTT for source of this ACK, see Sec. 2.5 and 2.6 > + RETRY = 0 ; + if (ACKER == NO_ACKER) { /* select current as acker is no other known */ + ACKER = I ; + T = T + 1 ; + } + if (ACKER != I) + < select acker according to Sec. 2.3 > ; + else { + + if (packet_type == ACK) { + < update_window according to Sec.2.2 > + send_packet ; + if (ack_pending) + update_timeout ; + } +} + +send_packet() { + if (QUEUED > 0 && T >= 1) { + < transmit one packet > + T = T - 1 ; + QUEUED = QUEUED - 1 ; + } + if ( ) + +} + + + +4. Procedures -- Receiver + +The following pseudo-code specifies the complete behavior of the +receiver in PGMCC. + +A receiver only transmits an ACK packet when it receives a data packet +for which the receiver is designated as the ACKER by the data packet +itself. A receiver can transmit a NAK packet after it has detected that +a data packet is missing and a suitable delay has passed, as dictated by +the feedback suppression rules of the protocol in use. + +The data packet contains acknowledgement status about the most recent 32 +sequence numbers known to the receiver. + + + + + + + +Rizzo/Iannaccone/Vicisano/Handley Section 4. [Page 18] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +on initialization/session setup: + < initialize state variables and ACK bitmap > + +on DATA packet reception: + < update p measurement according to Sec.2.6 > + < record timestamp and packet reception time > + if (ACKER == this_node) { + < send an immediate ACK > + } + if ( ) + < schedule a timeout for NAK transmission > + +on NAK reception: + < suppress any pending NAK transmission for the sequence + number indicated in the NAK > + +on timeout: + if ( < there are missing and unacknowledged packets > ) { + < send a NAK for one or more of the missing packets > + < mark such packets as acknowledged > + if ( ) + < schedule a timeout for NAK transmission > + } + + +5. Security Considerations + +PGMCC is not a transport protocol in its own right, but a congestion +control mechanism that is intended to be used in conjunction with a +transport protocol. Therefore security primarily needs to be considered +in the context of a specific transport protocol and its authentication +mechanisms. + +Congestion control mechanisms can potentially be exploited to create +denial of service. This may occur through spoofed feedback. Thus any +transport protocol that uses PGMCC should take care to ensure that +feedback is only accepted from the receiver of the data. The precise +mechanism to achieve this will however depend on the transport protocol +itself. + +In addition, congestion control mechanisms may potentially be +manipulated by a greedy receiver that wishes to receive more than its +fair share of network bandwidth. A receiver might do this by first +reporting inflated loss and RTT samples, in order to get selected as the +ACKER, and then generating ACK at the desired rate (including possibly +claiming to have received packets that in fact were lost due to +congestion). Possible defenses against such a receiver could be based +on the sender verifying the correctness of the loss and RTT samples + + + +Rizzo/Iannaccone/Vicisano/Handley Section 5. [Page 19] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +supplied by the receiver. A PGMCC sender SHOULD compare the receiver +reports on loss rate and RTT with the information derived directly from +the incoming stream of ACKs. In case of discrepancy of the reports, a +PGMCC sender SHOULD mark the current acker as ineligible and initiate a +new acker election. The decision on how large that discrepancy should be +before initiating a new acker election is left to the implementation. + +Also, the sender MAY include some form of nonce that the receiver must +feed back to the sender to prove receipt. However, the details of such a +nonce would depend on the transport protocol, and in particular on +whether the transport protocol is reliable or unreliable. + + +6. Authors' Addresses + + Luigi Rizzo + luigi@iet.unipi.it + Dip. Ing. dell'Informazione, + Univ. di Pisa + via Diotisalvi 2, 56122 Pisa, Italy + + Gianluca Iannaccone + gianluca.iannaccone@intel.com + Intel Research + 15 JJ Thomson Avenue, Cambridge CB3 0FD, UK + + Lorenzo Vicisano + lorenzo@cisco.com + cisco Systems, Inc. + 170 West Tasman Dr., + San Jose, CA, USA, 95134 + + Mark Handley + m.handley@cs.ucl.ac.uk + University College London, + Gower Street, London WC1E 6BT, UK + + +7. Acknowledgments + +We would like to acknowledge feedback and discussions on equation-based +congestion control with a wide range of people, including members of the +Reliable Multicast Research Group, the Reliable Multicast Transport +Working Group, and the End-to-End Research Group. + + + + + + + +Rizzo/Iannaccone/Vicisano/Handley Section 7. [Page 20] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +[1] Bradner, S., Key words for use in RFCs to Indicate Requirement +Levels (IETF RFC 2119) http://www.rfc-editor.org/rfc/rfc2119.txt + +[2] Floyd, S., Handley, M., Padhye, J., Widmer, J., "Equation-Based +Congestion Control for Unicast Applications", ACM SIGCOMM 2000, +Stockholm, Aug. 2000 + +[3] Padhye, J. and Firoiu, V. and Towsley, D. and Kurose, J., "Modeling +TCP Throughput: A Simple Model and its Empirical Validation", Proc ACM +SIGCOMM 1998. + +[4] Mankin, A., Romanow, A., Brander, S., Paxson, V., "IETF Criteria for +Evaluating Reliable Multicast Transport and Application Protocols," +RFC2357, June 1998. + +[5] Rizzo, L., "pgmcc: a TCP-friendly single-rate multicast congestion +control scheme", ACM SIGCOMM 2000, Stockholm, Aug.2000 + +[6] Schulzrinne, H., Casner, S., Frederick, R., Jacobson, V., "RTP: A +Transport Protocol for Real-Time Applications", RFC 1889, Jan 1996. + +[7] Speakman, T., Crowcroft, J., Gemmell, J., Farinacci, D. , Lin, S., +Leshchiner, D., Luby, M., Montgomery, T. , Rizzo, L., Tweedly, A., +Bhaskar, N., Edmonstone, R., Sumanasekera, R., Vicisano, L., PGM +Reliable Transport Protocol Specification, RFC 3208, December 2001. +rfc3208.txt also available at ftp://ftp.rfc-editor.org/in- +notes/rfc3208.txt + + + + +8. Full Copyright Statement + +Copyright (C) The Internet Society (2000). All Rights Reserved. + +This document and translations of it may be copied and furnished to +others, and derivative works that comment on or otherwise explain it or +assist in its implementation may be prepared, copied, published and +distributed, in whole or in part, without restriction of any kind, +provided that the above copyright notice and this paragraph are included +on all such copies and derivative works. However, this document itself +may not be modified in any way, such as by removing the copyright notice +or references to the Internet Society or other Internet organizations, +except as needed for the purpose of developing Internet standards in +which case the procedures for copyrights defined in the Internet +languages other than English. + + + + + +Rizzo/Iannaccone/Vicisano/Handley Section 8. [Page 21] + +INTERNET-DRAFT Expires: January 2005 July 2004 + + +The limited permissions granted above are perpetual and will not be +revoked by the Internet Society or its successors or assigns. + +This document and the information contained herein is provided on an "AS +IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK +FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT +INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR +FITNESS FOR A PARTICULAR PURPOSE." + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Rizzo/Iannaccone/Vicisano/Handley Section 8. [Page 22] diff --git a/3rdparty/openpgm-svn-r1135/doc/rfc3208.txt b/3rdparty/openpgm-svn-r1135/doc/rfc3208.txt new file mode 100644 index 0000000..fb82c26 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/doc/rfc3208.txt @@ -0,0 +1,6219 @@ + + + + + + +Network Working Group T. Speakman +Request for Comments: 3208 Cisco Systems +Category: Experimental J. Crowcroft + UCL + J. Gemmell + Microsoft + D. Farinacci + Procket Networks + S. Lin + Juniper Networks + D. Leshchiner + TIBCO Software + M. Luby + Digital Fountain + T. Montgomery + Talarian Corporation + L. Rizzo + University of Pisa + A. Tweedly + N. Bhaskar + R. Edmonstone + R. Sumanasekera + L. Vicisano + Cisco Systems + December 2001 + + + PGM Reliable Transport Protocol Specification + +Status of this Memo + + This memo defines an Experimental Protocol for the Internet + community. It does not specify an Internet standard of any kind. + Discussion and suggestions for improvement are requested. + Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2001). All Rights Reserved. + +Abstract + + Pragmatic General Multicast (PGM) is a reliable multicast transport + protocol for applications that require ordered or unordered, + duplicate-free, multicast data delivery from multiple sources to + multiple receivers. PGM guarantees that a receiver in the group + either receives all data packets from transmissions and repairs, or + is able to detect unrecoverable data packet loss. PGM is + + + +Speakman, et. al. Experimental [Page 1] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + specifically intended as a workable solution for multicast + applications with basic reliability requirements. Its central design + goal is simplicity of operation with due regard for scalability and + network efficiency. + +Table of Contents + + 1. Introduction and Overview .................................. 3 + 2. Architectural Description .................................. 9 + 3. Terms and Concepts ......................................... 12 + 4. Procedures - General ....................................... 18 + 5. Procedures - Sources ....................................... 19 + 6. Procedures - Receivers ..................................... 22 + 7. Procedures - Network Elements .............................. 27 + 8. Packet Formats ............................................. 31 + 9. Options .................................................... 40 + 10. Security Considerations .................................... 56 + 11. Appendix A - Forward Error Correction ...................... 58 + 12. Appendix B - Support for Congestion Control ................ 72 + 13. Appendix C - SPM Requests .................................. 79 + 14. Appendix D - Poll Mechanism ................................ 82 + 15. Appendix E - Implosion Prevention .......................... 92 + 16. Appendix F - Transmit Window Example ....................... 98 + 17 Appendix G - Applicability Statement ....................... 103 + 18. Abbreviations .............................................. 105 + 19. Acknowledgments ............................................ 106 + 20. References ................................................. 106 + 21. Authors' Addresses.......................................... 108 + 22. Full Copyright Statement ................................... 111 + +Nota Bene: + + The publication of this specification is intended to freeze the + definition of PGM in the interest of fostering both ongoing and + prospective experimentation with the protocol. The intent of that + experimentation is to provide experience with the implementation and + deployment of a reliable multicast protocol of this class so as to be + able to feed that experience back into the longer-term + standardization process underway in the Reliable Multicast Transport + Working Group of the IETF. Appendix G provides more specific detail + on the scope and status of some of this experimentation. Reports of + experiments include [16-23]. Additional results and new + experimentation are encouraged. + + + + + + + + +Speakman, et. al. Experimental [Page 2] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +1. Introduction and Overview + + A variety of reliable protocols have been proposed for multicast data + delivery, each with an emphasis on particular types of applications, + network characteristics, or definitions of reliability ([1], [2], + [3], [4]). In this tradition, Pragmatic General Multicast (PGM) is a + reliable transport protocol for applications that require ordered or + unordered, duplicate-free, multicast data delivery from multiple + sources to multiple receivers. + + PGM is specifically intended as a workable solution for multicast + applications with basic reliability requirements rather than as a + comprehensive solution for multicast applications with sophisticated + ordering, agreement, and robustness requirements. Its central design + goal is simplicity of operation with due regard for scalability and + network efficiency. + + PGM has no notion of group membership. It simply provides reliable + multicast data delivery within a transmit window advanced by a source + according to a purely local strategy. Reliable delivery is provided + within a source's transmit window from the time a receiver joins the + group until it departs. PGM guarantees that a receiver in the group + either receives all data packets from transmissions and repairs, or + is able to detect unrecoverable data packet loss. PGM supports any + number of sources within a multicast group, each fully identified by + a globally unique Transport Session Identifier (TSI), but since these + sources/sessions operate entirely independently of each other, this + specification is phrased in terms of a single source and extends + without modification to multiple sources. + + More specifically, PGM is not intended for use with applications that + depend either upon acknowledged delivery to a known group of + recipients, or upon total ordering amongst multiple sources. + + Rather, PGM is best suited to those applications in which members may + join and leave at any time, and that are either insensitive to + unrecoverable data packet loss or are prepared to resort to + application recovery in the event. Through its optional extensions, + PGM provides specific mechanisms to support applications as disparate + as stock and news updates, data conferencing, low-delay real-time + video transfer, and bulk data transfer. + + In the following text, transport-layer originators of PGM data + packets are referred to as sources, transport-layer consumers of PGM + data packets are referred to as receivers, and network-layer entities + in the intervening network are referred to as network elements. + + + + + +Speakman, et. al. Experimental [Page 3] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Unless otherwise specified, the term "repair" will be used to + indicate both the actual retransmission of a copy of a missing packet + or the transmission of an FEC repair packet. + +Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [14] and + indicate requirement levels for compliant PGM implementations. + +1.1. Summary of Operation + + PGM runs over a datagram multicast protocol such as IP multicast [5]. + In the normal course of data transfer, a source multicasts sequenced + data packets (ODATA), and receivers unicast selective negative + acknowledgments (NAKs) for data packets detected to be missing from + the expected sequence. Network elements forward NAKs PGM-hop-by- + PGM-hop to the source, and confirm each hop by multicasting a NAK + confirmation (NCF) in response on the interface on which the NAK was + received. Repairs (RDATA) may be provided either by the source + itself or by a Designated Local Repairer (DLR) in response to a NAK. + + Since NAKs provide the sole mechanism for reliability, PGM is + particularly sensitive to their loss. To minimize NAK loss, PGM + defines a network-layer hop-by-hop procedure for reliable NAK + forwarding. + + Upon detection of a missing data packet, a receiver repeatedly + unicasts a NAK to the last-hop PGM network element on the + distribution tree from the source. A receiver repeats this NAK until + it receives a NAK confirmation (NCF) multicast to the group from that + PGM network element. That network element responds with an NCF to + the first occurrence of the NAK and any further retransmissions of + that same NAK from any receiver. In turn, the network element + repeatedly forwards the NAK to the upstream PGM network element on + the reverse of the distribution path from the source of the original + data packet until it also receives an NCF from that network element. + Finally, the source itself receives and confirms the NAK by + multicasting an NCF to the group. + + While NCFs are multicast to the group, they are not propagated by PGM + network elements since they act as hop-by-hop confirmations. + + + + + + + + +Speakman, et. al. Experimental [Page 4] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + To avoid NAK implosion, PGM specifies procedures for subnet-based NAK + suppression amongst receivers and NAK elimination within network + elements. The usual result is the propagation of just one copy of a + given NAK along the reverse of the distribution path from any network + with directly connected receivers to a source. + + The net effect is that unicast NAKs return from a receiver to a + source on the reverse of the path on which ODATA was forwarded, that + is, on the reverse of the distribution tree from the source. More + specifically, they return through exactly the same sequence of PGM + network elements through which ODATA was forwarded, but in reverse. + The reasons for handling NAKs this way will become clear in the + discussion of constraining repairs, but first it's necessary to + describe the mechanisms for establishing the requisite source path + state in PGM network elements. + + To establish source path state in PGM network elements, the basic + data transfer operation is augmented by Source Path Messages (SPMs) + from a source, periodically interleaved with ODATA. SPMs function + primarily to establish source path state for a given TSI in all PGM + network elements on the distribution tree from the source. PGM + network elements use this information to address returning unicast + NAKs directly to the upstream PGM network element toward the source, + and thereby insure that NAKs return from a receiver to a source on + the reverse of the distribution path for the TSI. + + SPMs are sent by a source at a rate that serves to maintain up-to- + date PGM neighbor information. In addition, SPMs complement the role + of DATA packets in provoking further NAKs from receivers, and + maintaining receive window state in the receivers. + + As a further efficiency, PGM specifies procedures for the constraint + of repairs by network elements so that they reach only those network + segments containing group members that did not receive the original + transmission. As NAKs traverse the reverse of the ODATA path + (upward), they establish repair state in the network elements which + is used in turn to constrain the (downward) forwarding of the + corresponding RDATA. + + Besides procedures for the source to provide repairs, PGM also + specifies options and procedures that permit designated local + repairers (DLRs) to announce their availability and to redirect + repair requests (NAKs) to themselves rather than to the original + source. In addition to these conventional procedures for loss + recovery through selective ARQ, Appendix A specifies Forward Error + Correction (FEC) procedures for sources to provide and receivers to + request general error correcting parity packets rather than selective + retransmissions. + + + +Speakman, et. al. Experimental [Page 5] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Finally, since PGM operates without regular return traffic from + receivers, conventional feedback mechanisms for transport flow and + congestion control cannot be applied. Appendix B specifies a TCP- + friendly, NE-based solution for PGM congestion control, and cites a + reference to a TCP-friendly, end-to-end solution for PGM congestion + control. + + In its basic operation, PGM relies on a purely rate-limited + transmission strategy in the source to bound the bandwidth consumed + by PGM transport sessions and to define the transmit window + maintained by the source. + + PGM defines four basic packet types: three that flow downstream + (SPMs, DATA, NCFs), and one that flows upstream (NAKs). + +1.2. Design Goals and Constraints + + PGM has been designed to serve that broad range of multicast + applications that have relatively simple reliability requirements, + and to do so in a way that realizes the much advertised but often + unrealized network efficiencies of multicast data transfer. The + usual impediments to realizing these efficiencies are the implosion + of negative and positive acknowledgments from receivers to sources, + repair latency from the source, and the propagation of repairs to + disinterested receivers. + +1.2.1. Reliability. + + Reliable data delivery across an unreliable network is conventionally + achieved through an end-to-end protocol in which a source (implicitly + or explicitly) solicits receipt confirmation from a receiver, and the + receiver responds positively or negatively. While the frequency of + negative acknowledgments is a function of the reliability of the + network and the receiver's resources (and so, potentially quite low), + the frequency of positive acknowledgments is fixed at at least the + rate at which the transmit window is advanced, and usually more + often. + + Negative acknowledgments primarily determine repairs and reliability. + Positive acknowledgments primarily determine transmit buffer + management. + + When these principles are extended without modification to multicast + protocols, the result, at least for positive acknowledgments, is a + burden of positive acknowledgments transmitted to the source that + quickly threatens to overwhelm it as the number of receivers grows. + More succinctly, ACK implosion keeps ACK-based reliable multicast + protocols from scaling well. + + + +Speakman, et. al. Experimental [Page 6] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + One of the goals of PGM is to get as strong a definition of + reliability as possible from as simple a protocol as possible. ACK + implosion can be addressed in a variety of effective but complicated + ways, most of which require re-transmit capability from other than + the original source. + + An alternative is to dispense with positive acknowledgments + altogether, and to resort to other strategies for buffer management + while retaining negative acknowledgments for repairs and reliability. + The approach taken in PGM is to retain negative acknowledgments, but + to dispense with positive acknowledgments and resort instead to + timeouts at the source to manage transmit resources. + + The definition of reliability with PGM is a direct consequence of + this design decision. PGM guarantees that a receiver either receives + all data packets from transmissions and repairs, or is able to detect + unrecoverable data packet loss. + + PGM includes strategies for repeatedly provoking NAKs from receivers, + and for adding reliability to the NAKs themselves. By reinforcing + the NAK mechanism, PGM minimizes the probability that a receiver will + detect a missing data packet so late that the packet is unavailable + for repair either from the source or from a designated local repairer + (DLR). Without ACKs and knowledge of group membership, however, PGM + cannot eliminate this possibility. + +1.2.2. Group Membership + + A second consequence of eliminating ACKs is that knowledge of group + membership is neither required nor provided by the protocol. + Although a source may receive some PGM packets (NAKs for instance) + from some receivers, the identity of the receivers does not figure in + the processing of those packets. Group membership MAY change during + the course of a PGM transport session without the knowledge of or + consequence to the source or the remaining receivers. + +1.2.3. Efficiency + + While PGM avoids the implosion of positive acknowledgments simply by + dispensing with ACKs, the implosion of negative acknowledgments is + addressed directly. + + Receivers observe a random back-off prior to generating a NAK during + which interval the NAK is suppressed (i.e. it is not sent, but the + receiver acts as if it had sent it) by the receiver upon receipt of a + matching NCF. In addition, PGM network elements eliminate duplicate + NAKs received on different interfaces on the same network element. + + + + +Speakman, et. al. Experimental [Page 7] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + The combination of these two strategies usually results in the source + receiving just a single NAK for any given lost data packet. + + Whether a repair is provided from a DLR or the original source, it is + important to constrain that repair to only those network segments + containing members that negatively acknowledged the original + transmission rather than propagating it throughout the group. PGM + specifies procedures for network elements to use the pattern of NAKs + to define a sub-tree within the group upon which to forward the + corresponding repair so that it reaches only those receivers that + missed it in the first place. + +1.2.4. Simplicity + + PGM is designed to achieve the greatest improvement in reliability + (as compared to the usual UDP) with the least complexity. As a + result, PGM does NOT address conference control, global ordering + amongst multiple sources in the group, nor recovery from network + partitions. + +1.2.5. Operability + + PGM is designed to function, albeit with less efficiency, even when + some or all of the network elements in the multicast tree have no + knowledge of PGM. To that end, all PGM data packets can be + conventionally multicast routed by non-PGM network elements with no + loss of functionality, but with some inefficiency in the propagation + of RDATA and NCFs. + + In addition, since NAKs are unicast to the last-hop PGM network + element and NCFs are multicast to the group, NAK/NCF operation is + also consistent across non-PGM network elements. Note that for NAK + suppression to be most effective, receivers should always have a PGM + network element as a first hop network element between themselves and + every path to every PGM source. If receivers are several hops + removed from the first PGM network element, the efficacy of NAK + suppression may degrade. + +1.3. Options + + In addition to the basic data transfer operation described above, PGM + specifies several end-to-end options to address specific application + requirements. PGM specifies options to support fragmentation, late + joining, redirection, Forward Error Correction (FEC), reachability, + and session synchronization/termination/reset. Options MAY be + appended to PGM data packet headers only by their original + transmitters. While they MAY be interpreted by network elements, + options are neither added nor removed by network elements. + + + +Speakman, et. al. Experimental [Page 8] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + All options are receiver-significant (i.e., they must be interpreted + by receivers). Some options are also network-significant (i.e., they + must be interpreted by network elements). + + Fragmentation MAY be used in conjunction with data packets to allow a + transport-layer entity at the source to break up application-layer + data packets into multiple PGM data packets to conform with the + maximum transmission unit (MTU) supported by the network layer. + + Late joining allows a source to indicate whether or not receivers may + request all available repairs when they initially join a particular + transport session. + + Redirection MAY be used in conjunction with Poll Responses to allow a + DLR to respond to normal NCFs or POLLs with a redirecting POLR + advertising its own address as an alternative re-transmitter to the + original source. + + FEC techniques MAY be applied by receivers to use source-provided + parity packets rather than selective retransmissions to effect loss + recovery. + +2. Architectural Description + + As an end-to-end transport protocol, PGM specifies packet formats and + procedures for sources to transmit and for receivers to receive data. + To enhance the efficiency of this data transfer, PGM also specifies + packet formats and procedures for network elements to improve the + reliability of NAKs and to constrain the propagation of repairs. The + division of these functions is described in this section and expanded + in detail in the next section. + +2.1. Source Functions + + Data Transmission + + Sources multicast ODATA packets to the group within the + transmit window at a given transmit rate. + + Source Path State + + Sources multicast SPMs to the group, interleaved with ODATA if + present, to establish source path state in PGM network + elements. + + + + + + + +Speakman, et. al. Experimental [Page 9] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + NAK Reliability + + Sources multicast NCFs to the group in response to any NAKs + they receive. + + Repairs + + Sources multicast RDATA packets to the group in response to + NAKs received for data packets within the transmit window. + + Transmit Window Advance + + Sources MAY advance the trailing edge of the window according + to one of a number of strategies. Implementations MAY support + automatic adjustments such as keeping the window at a fixed + size in bytes, a fixed number of packets or a fixed real time + duration. In addition, they MAY optionally delay window + advancement based on NAK-silence for a certain period. Some + possible strategies are outlined later in this document. + +2.2. Receiver Functions + + Source Path State + + Receivers use SPMs to determine the last-hop PGM network + element for a given TSI to which to direct their NAKs. + + Data Reception + + Receivers receive ODATA within the transmit window and + eliminate any duplicates. + + Repair Requests + + Receivers unicast NAKs to the last-hop PGM network element (and + MAY optionally multicast a NAK with TTL of 1 to the local + group) for data packets within the receive window detected to + be missing from the expected sequence. A receiver MUST + repeatedly transmit a given NAK until it receives a matching + NCF. + + NAK Suppression + + Receivers suppress NAKs for which a matching NCF or NAK is + received during the NAK transmit back-off interval. + + + + + + +Speakman, et. al. Experimental [Page 10] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Receive Window Advance + + Receivers immediately advance their receive windows upon + receipt of any PGM data packet or SPM within the transmit + window that advances the receive window. + +2.3. Network Element Functions + + Network elements forward ODATA without intervention. + + Source Path State + + Network elements intercept SPMs and use them to establish + source path state for the corresponding TSI before multicast + forwarding them in the usual way. + + NAK Reliability + + Network elements multicast NCFs to the group in response to any + NAK they receive. For each NAK received, network elements + create repair state recording the transport session identifier, + the sequence number of the NAK, and the input interface on + which the NAK was received. + + Constrained NAK Forwarding + + Network elements repeatedly unicast forward only the first copy + of any NAK they receive to the upstream PGM network element on + the distribution path for the TSI until they receive an NCF in + response. In addition, they MAY optionally multicast this NAK + upstream with TTL of 1. + + Nota Bene: Once confirmed by an NCF, network elements discard NAK + packets; NAKs are NOT retained in network elements beyond this + forwarding operation, but state about the reception of them is + stored. + + NAK Elimination + + Network elements discard exact duplicates of any NAK for which + they already have repair state (i.e., that has been forwarded + either by themselves or a neighboring PGM network element), and + respond with a matching NCF. + + + + + + + + +Speakman, et. al. Experimental [Page 11] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Constrained RDATA Forwarding + + Network elements use NAKs to maintain repair state consisting + of a list of interfaces upon which a given NAK was received, + and they forward the corresponding RDATA only on these + interfaces. + + NAK Anticipation + + If a network element hears an upstream NCF (i.e., on the + upstream interface for the distribution tree for the TSI), it + establishes repair state without outgoing interfaces in + anticipation of responding to and eliminating duplicates of the + NAK that may arrive from downstream. + +3. Terms and Concepts + + Before proceeding from the preceding overview to the detail in the + subsequent Procedures, this section presents some concepts and + definitions that make that detail more intelligible. + +3.1. Transport Session Identifiers + + Every PGM packet is identified by a: + + TSI transport session identifier + + TSIs MUST be globally unique, and only one source at a time may act + as the source for a transport session. (Note that repairers do not + change the TSI in any RDATA they transmit). TSIs are composed of the + concatenation of a globally unique source identifier (GSI) and a + source-assigned data-source port. + + Since all PGM packets originated by receivers are in response to PGM + packets originated by a source, receivers simply echo the TSI heard + from the source in any corresponding packets they originate. + + Since all PGM packets originated by network elements are in response + to PGM packets originated by a receiver, network elements simply echo + the TSI heard from the receiver in any corresponding packets they + originate. + +3.2. Sequence Numbers + + PGM uses a circular sequence number space from 0 through ((2**32) - + 1) to identify and order ODATA packets. Sources MUST number ODATA + packets in unit increments in the order in which the corresponding + application data is submitted for transmission. Within a transmit or + + + +Speakman, et. al. Experimental [Page 12] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + receive window (defined below), a sequence number x is "less" or + "older" than sequence number y if it numbers an ODATA packet + preceding ODATA packet y, and a sequence number y is "greater" or + "more recent" than sequence number x if it numbers an ODATA packet + subsequent to ODATA packet x. + +3.3. Transmit Window + + The description of the operation of PGM rests fundamentally on the + definition of the source-maintained transmit window. This definition + in turn is derived directly from the amount of transmitted data (in + seconds) a source retains for repair (TXW_SECS), and the maximum + transmit rate (in bytes/second) maintained by a source to regulate + its bandwidth utilization (TXW_MAX_RTE). + + In terms of sequence numbers, the transmit window is the range of + sequence numbers consumed by the source for sequentially numbering + and transmitting the most recent TXW_SECS of ODATA packets. The + trailing (or left) edge of the transmit window (TXW_TRAIL) is defined + as the sequence number of the oldest data packet available for repair + from a source. The leading (or right) edge of the transmit window + (TXW_LEAD) is defined as the sequence number of the most recent data + packet a source has transmitted. + + The size of the transmit window in sequence numbers (TXW_SQNS) (i.e., + the difference between the leading and trailing edges plus one) MUST + be no greater than half the PGM sequence number space less one. + + When TXW_TRAIL is equal to TXW_LEAD, the transmit window size is one. + When TXW_TRAIL is equal to TXW_LEAD plus one, the transmit window + size is empty. + +3.4. Receive Window + + The receive window at the receivers is determined entirely by PGM + packets from the source. That is, a receiver simply obeys what the + source tells it in terms of window state and advancement. + + For a given transport session identified by a TSI, a receiver + maintains: + + RXW_TRAIL the sequence number defining the trailing edge of the + receive window, the sequence number (known from data + packets and SPMs) of the oldest data packet available + for repair from the source + + + + + + +Speakman, et. al. Experimental [Page 13] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + RXW_LEAD the sequence number defining the leading edge of the + receive window, the greatest sequence number of any + received data packet within the transmit window + + The receive window is the range of sequence numbers a receiver is + expected to use to identify receivable ODATA. + + A data packet is described as being "in" the receive window if its + sequence number is in the receive window. + + The receive window is advanced by the receiver when it receives an + SPM or ODATA packet within the transmit window that increments + RXW_TRAIL. Receivers also advance their receive windows upon receipt + of any PGM data packet within the receive window that advances the + receive window. + +3.5. Source Path State + + To establish the repair state required to constrain RDATA, it's + essential that NAKs return from a receiver to a source on the reverse + of the distribution tree from the source. That is, they must return + through the same sequence of PGM network elements through which the + ODATA was forwarded, but in reverse. There are two reasons for this, + the less obvious one being by far the more important. + + The first and obvious reason is that RDATA is forwarded on the same + path as ODATA and so repair state must be established on this path if + it is to constrain the propagation of RDATA. + + The second and less obvious reason is that in the absence of repair + state, PGM network elements do NOT forward RDATA, so the default + behavior is to discard repairs. If repair state is not properly + established for interfaces on which ODATA went missing, then + receivers on those interfaces will continue to NAK for lost data and + ultimately experience unrecoverable data loss. + + The principle function of SPMs is to provide the source path state + required for PGM network elements to forward NAKs from one PGM + network element to the next on the reverse of the distribution tree + for the TSI, establishing repair state each step of the way. This + source path state is simply the address of the upstream PGM network + element on the reverse of the distribution tree for the TSI. That + upstream PGM network element may be more than one subnet hop away. + SPMs establish the identity of the upstream PGM network element on + the distribution tree for each TSI in each group in each PGM network + element, a sort of virtual PGM topology. So although NAKs are + unicast addressed, they are NOT unicast routed by PGM network + elements in the conventional sense. Instead PGM network elements use + + + +Speakman, et. al. Experimental [Page 14] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + the source path state established by SPMs to direct NAKs PGM-hop-by- + PGM-hop toward the source. The idea is to constrain NAKs to the pure + PGM topology spanning the more heterogeneous underlying topology of + both PGM and non-PGM network elements. + + The result is repair state in every PGM network element between the + receiver and the source so that the corresponding RDATA is never + discarded by a PGM network element for lack of repair state. + + SPMs also maintain transmit window state in receivers by advertising + the trailing and leading edges of the transmit window (SPM_TRAIL and + SPM_LEAD). In the absence of data, SPMs MAY be used to close the + transmit window in time by advancing the transmit window until + SPM_TRAIL is equal to SPM_LEAD plus one. + +3.6. Packet Contents + + This section just provides enough short-hand to make the Procedures + intelligible. For the full details of packet contents, please refer + to Packet Formats below. + +3.6.1. Source Path Messages + +3.6.1.1. SPMs + + SPMs are transmitted by sources to establish source-path state in PGM + network elements, and to provide transmit-window state in receivers. + + SPMs are multicast to the group and contain: + + SPM_TSI the source-assigned TSI for the session to which the + SPM corresponds + + SPM_SQN a sequence number assigned sequentially by the source + in unit increments and scoped by SPM_TSI + + Nota Bene: this is an entirely separate sequence than is used to + number ODATA and RDATA. + + SPM_TRAIL the sequence number defining the trailing edge of the + source's transmit window (TXW_TRAIL) + + SPM_LEAD the sequence number defining the leading edge of the + source's transmit window (TXW_LEAD) + + SPM_PATH the network-layer address (NLA) of the interface on + the PGM network element on which the SPM is forwarded + + + + +Speakman, et. al. Experimental [Page 15] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +3.6.2. Data Packets + +3.6.2.1. ODATA - Original Data + + ODATA packets are transmitted by sources to send application data to + receivers. + + ODATA packets are multicast to the group and contain: + + OD_TSI the globally unique source-assigned TSI + + OD_TRAIL the sequence number defining the trailing edge of the + source's transmit window (TXW_TRAIL) + + OD_TRAIL makes the protocol more robust in the face of + lost SPMs. By including the trailing edge of the + transmit window on every data packet, receivers that + have missed any SPMs that advanced the transmit window + can still detect the case, recover the application, + and potentially re-synchronize to the transport + session. + + OD_SQN a sequence number assigned sequentially by the source + in unit increments and scoped by OD_TSI + +3.6.2.2. RDATA - Repair Data + + RDATA packets are repair packets transmitted by sources or DLRs in + response to NAKs. + + RDATA packets are multicast to the group and contain: + + RD_TSI OD_TSI of the ODATA packet for which this is a repair + + RD_TRAIL the sequence number defining the trailing edge of the + source's transmit window (TXW_TRAIL). This is updated + to the most current value when the repair is sent, so + it is not necessarily the same as OD_TRAIL of the + ODATA packet for which this is a repair + + RD_SQN OD_SQN of the ODATA packet for which this is a repair + +3.6.3. Negative Acknowledgments + +3.6.3.1. NAKs - Negative Acknowledgments + + NAKs are transmitted by receivers to request repairs for missing data + packets. + + + +Speakman, et. al. Experimental [Page 16] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + NAKs are unicast (PGM-hop-by-PGM-hop) to the source and contain: + + NAK_TSI OD_TSI of the ODATA packet for which a repair is + requested + + NAK_SQN OD_SQN of the ODATA packet for which a repair is + requested + + NAK_SRC the unicast NLA of the original source of the missing + ODATA. + + NAK_GRP the multicast group NLA + +3.6.3.2. NNAKs - Null Negative Acknowledgments + + NNAKs are transmitted by a DLR that receives NAKs redirected to it by + either receivers or network elements to provide flow-control feed- + back to a source. + + NNAKs are unicast (PGM-hop-by-PGM-hop) to the source and contain: + + NNAK_TSI NAK_TSI of the corresponding re-directed NAK. + + NNAK_SQN NAK_SQN of the corresponding re-directed NAK. + + NNAK_SRC NAK_SRC of the corresponding re-directed NAK. + + NNAK_GRP NAK_GRP of the corresponding re-directed NAK. + +3.6.4. Negative Acknowledgment Confirmations + +3.6.4.1. NCFs - NAK confirmations + + NCFs are transmitted by network elements and sources in response to + NAKs. + + NCFs are multicast to the group and contain: + + NCF_TSI NAK_TSI of the NAK being confirmed + + NCF_SQN NAK_SQN of the NAK being confirmed + + NCF_SRC NAK_SRC of the NAK being confirmed + + NCF_GRP NAK_GRP of the NAK being confirmed + + + + + + +Speakman, et. al. Experimental [Page 17] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +3.6.5. Option Encodings + + OPT_LENGTH 0x00 - Option's Length + + OPT_FRAGMENT 0x01 - Fragmentation + + OPT_NAK_LIST 0x02 - List of NAK entries + + OPT_JOIN 0x03 - Late Joining + + OPT_REDIRECT 0x07 - Redirect + + OPT_SYN 0x0D - Synchronization + + OPT_FIN 0x0E - Session Fin receivers, conventional + feedbackish + + OPT_RST 0x0F - Session Reset + + OPT_PARITY_PRM 0x08 - Forward Error Correction Parameters + + OPT_PARITY_GRP 0x09 - Forward Error Correction Group Number + + OPT_CURR_TGSIZE 0x0A - Forward Error Correction Group Size + + OPT_CR 0x10 - Congestion Report + + OPT_CRQST 0x11 - Congestion Report Request + + OPT_NAK_BO_IVL 0x04 - NAK Back-Off Interval + + OPT_NAK_BO_RNG 0x05 - NAK Back-Off Range + + OPT_NBR_UNREACH 0x0B - Neighbor Unreachable + + OPT_PATH_NLA 0x0C - Path NLA + + OPT_INVALID 0x7F - Option invalidated + +4. Procedures - General + + Since SPMs, NCFs, and RDATA must be treated conditionally by PGM + network elements, they must be distinguished from other packets in + the chosen multicast network protocol if PGM network elements are to + extract them from the usual switching path. + + + + + + +Speakman, et. al. Experimental [Page 18] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + The most obvious way for network elements to achieve this is to + examine every packet in the network for the PGM transport protocol + and packet types. However, the overhead of this approach is costly + for high-performance, multi-protocol network elements. An + alternative, and a requirement for PGM over IP multicast, is that + SPMs, NCFs, and RDATA MUST be transmitted with the IP Router Alert + Option [6]. This option gives network elements a network-layer + indication that a packet should be extracted from IP switching for + more detailed processing. + +5. Procedures - Sources + +5.1. Data Transmission + + Since PGM relies on a purely rate-limited transmission strategy in + the source to bound the bandwidth consumed by PGM transport sessions, + an assortment of techniques is assembled here to make that strategy + as conservative and robust as possible. These techniques are the + minimum REQUIRED of a PGM source. + +5.1.1. Maximum Cumulative Transmit Rate + + A source MUST number ODATA packets in the order in which they are + submitted for transmission by the application. A source MUST + transmit ODATA packets in sequence and only within the transmit + window beginning with TXW_TRAIL at no greater a rate than + TXW_MAX_RTE. + + TXW_MAX_RTE is typically the maximum cumulative transmit rate of SPM, + ODATA, and RDATA. Different transmission strategies MAY define + TXW_MAX_RTE as appropriate for the implementation. + +5.1.2. Transmit Rate Regulation + + To regulate its transmit rate, a source MUST use a token bucket + scheme or any other traffic management scheme that yields equivalent + behavior. A token bucket [7] is characterized by a continually + sustainable data rate (the token rate) and the extent to which the + data rate may exceed the token rate for short periods of time (the + token bucket size). Over any arbitrarily chosen interval, the number + of bytes the source may transmit MUST NOT exceed the token bucket + size plus the product of the token rate and the chosen interval. + + In addition, a source MUST bound the maximum rate at which successive + packets may be transmitted using a leaky bucket scheme drained at a + maximum transmit rate, or equivalent mechanism. + + + + + +Speakman, et. al. Experimental [Page 19] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +5.1.3. Outgoing Packet Ordering + + To preserve the logic of PGM's transmit window, a source MUST + strictly prioritize sending of pending NCFs first, pending SPMs + second, and only send ODATA or RDATA when no NCFs or SPMs are + pending. The priority of RDATA versus ODATA is application + dependent. The sender MAY implement weighted bandwidth sharing + between RDATA and ODATA. Note that strict prioritization of RDATA + over ODATA may stall progress of ODATA if there are receivers that + keep generating NAKs so as to always have RDATA pending (e.g. a + steady stream of late joiners with OPT_JOIN). Strictly prioritizing + ODATA over RDATA may lead to a larger portion of receivers getting + unrecoverable losses. + +5.1.4. Ambient SPMs + + Interleaved with ODATA and RDATA, a source MUST transmit SPMs at a + rate at least sufficient to maintain current source path state in PGM + network elements. Note that source path state in network elements + does not track underlying changes in the distribution tree from a + source until an SPM traverses the altered distribution tree. The + consequence is that NAKs may go unconfirmed both at receivers and + amongst network elements while changes in the underlying distribution + tree take place. + +5.1.5. Heartbeat SPMs + + In the absence of data to transmit, a source SHOULD transmit SPMs at + a decaying rate in order to assist early detection of lost data, to + maintain current source path state in PGM network elements, and to + maintain current receive window state in the receivers. + + In this scheme [8], a source maintains an inter-heartbeat timer + IHB_TMR which times the interval between the most recent packet + (ODATA, RDATA, or SPM) transmission and the next heartbeat + transmission. IHB_TMR is initialized to a minimum interval IHB_MIN + after the transmission of any data packet. If IHB_TMR expires, the + source transmits a heartbeat SPM and initializes IHB_TMR to double + its previous value. The transmission of consecutive heartbeat SPMs + doubles IHB each time up to a maximum interval IHB_MAX. The + transmission of any data packet initializes IHB_TMR to IHB_MIN once + again. The effect is to provoke prompt detection of missing packets + in the absence of data to transmit, and to do so with minimal + bandwidth overhead. + + + + + + + +Speakman, et. al. Experimental [Page 20] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +5.1.6. Ambient and Heartbeat SPMs + + Ambient and heartbeat SPMs are described as driven by separate timers + in this specification to highlight their contrasting functions. + Ambient SPMs are driven by a count-down timer that expires regularly + while heartbeat SPMs are driven by a count-down timer that keeps + being reset by data, and the interval of which changes once it begins + to expire. The ambient SPM timer is just counting down in real-time + while the heartbeat timer is measuring the inter-data-packet + interval. + + In the presence of data, no heartbeat SPMs will be transmitted since + the transmission of data keeps setting the IHB_TMR back to its + initial value. At the same time however, ambient SPMs MUST be + interleaved into the data as a matter of course, not necessarily as a + heartbeat mechanism. This ambient transmission of SPMs is REQUIRED + to keep the distribution tree information in the network current and + to allow new receivers to synchronize with the session. + + An implementation SHOULD de-couple ambient and heartbeat SPM timers + sufficiently to permit them to be configured independently of each + other. + +5.2. Negative Acknowledgment Confirmation + + A source MUST immediately multicast an NCF in response to any NAK it + receives. The NCF is REQUIRED since the alternative of responding + immediately with RDATA would not allow other PGM network elements on + the same subnet to do NAK anticipation, nor would it allow DLRs on + the same subnet to provide repairs. A source SHOULD be able to + detect a NAK storm and adopt countermeasure to protect the network + against a denial of service. A possible countermeasure is to send + the first NCF immediately in response to a NAK and then delay the + generation of further NCFs (for identical NAKs) by a small interval, + so that identical NCFs are rate-limited, without affecting the + ability to suppress NAKs. + +5.3. Repairs + + After multicasting an NCF in response to a NAK, a source MUST then + multicast RDATA (while respecting TXW_MAX_RTE) in response to any NAK + it receives for data packets within the transmit window. + + In the interest of increasing the efficiency of a particular RDATA + packet, a source MAY delay RDATA transmission to accommodate the + arrival of NAKs from the whole loss neighborhood. This delay SHOULD + not exceed twice the greatest propagation delay in the loss + neighborhood. + + + +Speakman, et. al. Experimental [Page 21] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +6. Procedures - Receivers + +6.1. Data Reception + + Initial data reception + + A receiver SHOULD initiate data reception beginning with the first + data packet it receives within the advertised transmit window. This + packet's sequence number (ODATA_SQN) temporarily defines the trailing + edge of the transmit window from the receiver's perspective. That + is, it is assigned to RXW_TRAIL_INIT within the receiver, and until + the trailing edge sequence number advertised in subsequent packets + (SPMs or ODATA or RDATA) increments past RXW_TRAIL_INIT, the receiver + MUST only request repairs for sequence numbers subsequent to + RXW_TRAIL_INIT. Thereafter, it MAY request repairs anywhere in the + transmit window. This temporary restriction on repair requests + prevents receivers from requesting a potentially large amount of + history when they first begin to receive a given PGM transport + session. + + Note that the JOIN option, discussed later, MAY be used to provide a + different value for RXW_TRAIL_INIT. + + Receiving and discarding data packets + + Within a given transport session, a receiver MUST accept any ODATA or + RDATA packets within the receive window. A receiver MUST discard any + data packet that duplicates one already received in the transmit + window. A receiver MUST discard any data packet outside of the + receive window. + + Contiguous data + + Contiguous data is comprised of those data packets within the receive + window that have been received and are in the range from RXW_TRAIL up + to (but not including) the first missing sequence number in the + receive window. The most recently received data packet of contiguous + data defines the leading edge of contiguous data. + + As its default mode of operation, a receiver MUST deliver only + contiguous data packets to the application, and it MUST do so in the + order defined by those data packets' sequence numbers. This provides + applications with a reliable ordered data flow. + + + + + + + + +Speakman, et. al. Experimental [Page 22] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Non contiguous data + + PGM receiver implementations MAY optionally provide a mode of + operation in which data is delivered to an application in the order + received. However, the implementation MUST only deliver complete + application protocol data units (APDUs) to the application. That is, + APDUs that have been fragmented into different TPDUs MUST be + reassembled before delivery to the application. + +6.2. Source Path Messages + + Receivers MUST receive and sequence SPMs for any TSI they are + receiving. An SPM is in sequence if its sequence number is greater + than that of the most recent in-sequence SPM and within half the PGM + number space. Out-of-sequence SPMs MUST be discarded. + + For each TSI, receivers MUST use the most recent SPM to determine the + NLA of the upstream PGM network element for use in NAK addressing. A + receiver MUST NOT initiate repair requests until it has received at + least one SPM for the corresponding TSI. + + Since SPMs require per-hop processing, it is likely that they will be + forwarded at a slower rate than data, and that they will arrive out + of sync with the data stream. In this case, the window information + that the SPMs carry will be out of date. Receivers SHOULD expect + this to be the case and SHOULD detect it by comparing the packet lead + and trail values with the values the receivers have stored for lead + and trail. If the SPM packet values are less, they SHOULD be + ignored, but the rest of the packet SHOULD be processed as normal. + +6.3. Data Recovery by Negative Acknowledgment + + Detecting missing data packets + + Receivers MUST detect gaps in the expected data sequence in the + following manners: + + by comparing the sequence number on the most recently received + ODATA or RDATA packet with the leading edge of contiguous data + + by comparing SPM_LEAD of the most recently received SPM with the + leading edge of contiguous data + + In both cases, if the receiver has not received all intervening data + packets, it MAY initiate selective NAK generation for each missing + sequence number. + + + + + +Speakman, et. al. Experimental [Page 23] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + In addition, a receiver may detect a single missing data packet by + receiving an NCF or multicast NAK for a data packet within the + transmit window which it has not received. In this case it MAY + initiate selective NAK generation for the said sequence number. + + In all cases, receivers SHOULD temper the initiation of NAK + generation to account for simple mis-ordering introduced by the + network. A possible mechanism to achieve this is to assume loss only + after the reception of N packets with sequence numbers higher than + those of the (assumed) lost packets. A possible value for N is 2. + This method SHOULD be complemented with a timeout based mechanism + that handles the loss of the last packet before a pause in the + transmission of the data stream. The leading edge field in SPMs + SHOULD also be taken into account in the loss detection algorithm. + + Generating NAKs + + NAK generation follows the detection of a missing data packet and is + the cycle of: + + waiting for a random period of time (NAK_RB_IVL) while listening + for matching NCFs or NAKs + + transmitting a NAK if a matching NCF or NAK is not heard + + waiting a period (NAK_RPT_IVL) for a matching NCF and recommencing + NAK generation if the matching NCF is not received + + waiting a period (NAK_RDATA_IVL) for data and recommencing NAK + generation if the matching data is not received + + The entire generation process can be summarized by the following + state machine: + + + + + + + + + + + + + + + + + + +Speakman, et. al. Experimental [Page 24] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + | + | detect missing tpdu + | - clear data retry count + | - clear NCF retry count + V + matching NCF |--------------------------| + <---------------| BACK-OFF_STATE | <---------------------- + | | start timer(NAK_RB_IVL) | ^ ^ + | | | | | + | |--------------------------| | | + | matching | | timer expires | | + | NAK | | - send NAK | | + | | | | | + | V V | | + | |--------------------------| | | + | | WAIT_NCF_STATE | | | + | matching NCF | start timer(NAK_RPT_IVL) | | | + |<--------------| |------------> | + | |--------------------------| timer expires | + | | | ^ - increment NCF | + | NAK_NCF_RETRIES | | | retry count | + | exceeded | | | | + | V ----------- | + | Cancelation matching NAK | + | - restart timer(NAK_RPT_IVL) | + | | + | | + V |--------------------------| | + --------------->| WAIT_DATA_STATE |-----------------------> + |start timer(NAK_RDATA_IVL)| timer expires + | | - increment data + |--------------------------| retry count + | | ^ + NAK_DATA_RETRIES | | | + exceeded | | | + | ----------- + | matching NCF or NAK + V - restart timer(NAK_RDATA_IVL) + Cancellation + + In any state, receipt of matching RDATA or ODATA completes data + recovery and successful exit from the state machine. State + transition stops any running timers. + + In any state, if the trailing edge of the window moves beyond the + sequence number, data recovery for that sequence number terminates. + + + + + +Speakman, et. al. Experimental [Page 25] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + During NAK_RB_IVL a NAK is said to be pending. When awaiting data or + an NCF, a NAK is said to be outstanding. + + Backing off NAK transmission + + Before transmitting a NAK, a receiver MUST wait some interval + NAK_RB_IVL chosen randomly over some time period NAK_BO_IVL. During + this period, receipt of a matching NAK or a matching NCF will suspend + NAK generation. NAK_RB_IVL is counted down from the time a missing + data packet is detected. + + A value for NAK_BO_IVL learned from OPT_NAK_BO_IVL (see 16.4.1 below) + MUST NOT be used by a receiver (i.e., the receiver MUST NOT NAK) + unless either NAK_BO_IVL_SQN is zero, or the receiver has seen + POLL_RND == 0 for POLL_SQN =< NAK_BO_IVL_SQN within half the sequence + number space. + + When a parity NAK (Appendix A, FEC) is being generated, the back-off + interval SHOULD be inversely biased with respect to the number of + parity packets requested. This way NAKs requesting larger numbers of + parity packets are likely to be sent first and thus suppress other + NAKs. A NAK for a given transmission group suppresses another NAK + for the same transmission group only if it is requesting an equal or + larger number of parity packets. + + When a receiver has to transmit a sequence of NAKs, it SHOULD + transmit the NAKs in order from oldest to most recent. + + Suspending NAK generation + + Suspending NAK generation just means waiting for either NAK_RB_IVL, + NAK_RPT_IVL or NAK_RDATA_IVL to pass. A receiver MUST suspend NAK + generation if a duplicate of the NAK is already pending from this + receiver or the NAK is already outstanding from this or another + receiver. + + NAK suppression + + A receiver MUST suppress NAK generation and wait at least + NAK_RDATA_IVL before recommencing NAK generation if it hears a + matching NCF or NAK during NAK_RB_IVL. A matching NCF must match + NCF_TSI with NAK_TSI, and NCF_SQN with NAK_SQN. + + Transmitting a NAK + + Upon expiry of NAK_RB_IVL, a receiver MUST unicast a NAK to the + upstream PGM network element for the TSI specifying the transport + session identifier and missing sequence number. In addition, it MAY + + + +Speakman, et. al. Experimental [Page 26] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + multicast a NAK with TTL of 1 to the group, if the PGM parent is not + directly connected. It also records both the address of the source + of the corresponding ODATA and the address of the group in the NAK + header. + + It MUST repeat the NAK at a rate governed by NAK_RPT_IVL up to + NAK_NCF_RETRIES times while waiting for a matching NCF. It MUST then + wait NAK_RDATA_IVL before recommencing NAK generation. If it hears a + matching NCF or NAK during NAK_RDATA_IVL, it MUST wait anew for + NAK_RDATA_IVL before recommencing NAK generation (i.e. matching NCFs + and NAKs restart NAK_RDATA_IVL). + + Completion of NAK generation + + NAK generation is complete only upon the receipt of the matching + RDATA (or even ODATA) packet at any time during NAK generation. + + Cancellation of NAK generation + + NAK generation is cancelled upon the advancing of the receive window + so as to exclude the matching sequence number of a pending or + outstanding NAK, or NAK_DATA_RETRIES / NAK_NCF_RETRIES being + exceeded. Cancellation of NAK generation indicates unrecoverable + data loss. + + Receiving NCFs and multicast NAKs + + A receiver MUST discard any NCFs or NAKs it hears for data packets + outside the transmit window or for data packets it has received. + Otherwise they are treated as appropriate for the current repair + state. + +7. Procedures - Network Elements + +7.1. Source Path State + + Upon receipt of an in-sequence SPM, a network element records the + Source Path Address SPM_PATH with the multicast routing information + for the TSI. If the receiving network element is on the same subnet + as the forwarding network element, this address will be the same as + the address of the immediately upstream network element on the + distribution tree for the TSI. If, however, non-PGM network elements + intervene between the forwarding and the receiving network elements, + this address will be the address of the first PGM network element + across the intervening network elements. + + + + + + +Speakman, et. al. Experimental [Page 27] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + The network element then forwards the SPM on each outgoing interface + for that TSI. As it does so, it encodes the network address of the + outgoing interface in SPM_PATH in each copy of the SPM it forwards. + +7.2. NAK Confirmation + + Network elements MUST immediately transmit an NCF in response to any + unicast NAK they receive. The NCF MUST be multicast to the group on + the interface on which the NAK was received. + + Nota Bene: In order to avoid creating multicast routing state for + PGM network elements across non-PGM-capable clouds, the network- + header source address of NCFs transmitted by network elements MUST + be set to the ODATA source's NLA, not the network element's NLA as + might be expected. + + Network elements should be able to detect a NAK storm and adopt + counter-measure to protect the network against a denial of service. + A possible countermeasure is to send the first NCF immediately in + response to a NAK and then delay the generation of further NCFs (for + identical NAKs) by a small interval, so that identical NCFs are + rate-limited, without affecting the ability to suppress NAKs. + + Simultaneously, network elements MUST establish repair state for the + NAK if such state does not already exist, and add the interface on + which the NAK was received to the corresponding repair interface list + if the interface is not already listed. + +7.3. Constrained NAK Forwarding + + The NAK forwarding procedures for network elements are quite similar + to those for receivers, but three important differences should be + noted. + + First, network elements do NOT back off before forwarding a NAK + (i.e., there is no NAK_BO_IVL) since the resulting delay of the NAK + would compound with each hop. Note that NAK arrivals will be + randomized by the receivers from which they originate, and this + factor in conjunction with NAK anticipation and elimination will + combine to forestall NAK storms on subnets with a dense network + element population. + + Second, network elements do NOT retry confirmed NAKs if RDATA is not + seen; they simply discard the repair state and rely on receivers to + re-request the repair. This approach keeps the repair state in the + network elements relatively ephemeral and responsive to underlying + routing changes. + + + + +Speakman, et. al. Experimental [Page 28] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Third, note that ODATA does NOT cancel NAK forwarding in network + elements since it is switched by network elements without transport- + layer intervention. + + Nota Bene: Once confirmed by an NCF, network elements discard NAK + packets; they are NOT retained in network elements beyond this + forwarding operation. + + NAK forwarding requires that a network element listen to NCFs for the + same transport session. NAK forwarding also requires that a network + element observe two time out intervals for any given NAK (i.e., per + NAK_TSI and NAK_SQN): NAK_RPT_IVL and NAK_RDATA_IVL. + + The NAK repeat interval NAK_RPT_IVL, limits the length of time for + which a network element will repeat a NAK while waiting for a + corresponding NCF. NAK_RPT_IVL is counted down from the transmission + of a NAK. Expiry of NAK_RPT_IVL cancels NAK forwarding (due to + missing NCF). + + The NAK RDATA interval NAK_RDATA_IVL, limits the length of time for + which a network element will wait for the corresponding RDATA. + NAK_RDATA_IVL is counted down from the time a matching NCF is + received. Expiry of NAK_RDATA_IVL causes the network element to + discard the corresponding repair state (due to missing RDATA). + + During NAK_RPT_IVL, a NAK is said to be pending. During + NAK_RDATA_IVL, a NAK is said to be outstanding. + + A Network element MUST forward NAKs only to the upstream PGM network + element for the TSI. + + A network element MUST repeat a NAK at a rate of NAK_RPT_RTE for an + interval of NAK_RPT_IVL until it receives a matching NCF. A matching + NCF must match NCF_TSI with NAK_TSI, and NCF_SQN with NAK_SQN. + + Upon reception of the corresponding NCF, network elements MUST wait + at least NAK_RDATA_IVL for the corresponding RDATA. Receipt of the + corresponding RDATA at any time during NAK forwarding cancels NAK + forwarding and tears down the corresponding repair state in the + network element. + +7.4. NAK elimination + + Two NAKs duplicate each other if they bear the same NAK_TSI and + NAK_SQN. Network elements MUST discard all duplicates of a NAK that + is pending. + + + + + +Speakman, et. al. Experimental [Page 29] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Once a NAK is outstanding, network elements MUST discard all + duplicates of that NAK for NAK_ELIM_IVL. Upon expiry of + NAK_ELIM_IVL, network elements MUST suspend NAK elimination for that + TSI/SQN until the first duplicate of that NAK is seen after the + expiry of NAK_ELIM_IVL. This duplicate MUST be forwarded in the + usual manner. Once this duplicate NAK is outstanding, network + elements MUST once again discard all duplicates of that NAK for + NAK_ELIM_IVL, and so on. NAK_RDATA_IVL MUST be reset each time a NAK + for the corresponding TSI/SQN is confirmed (i.e., each time + NAK_ELIM_IVL is reset). NAK_ELIM_IVL MUST be some small fraction of + NAK_RDATA_IVL. + + NAK_ELIM_IVL acts to balance implosion prevention against repair + state liveness. That is, it results in the elimination of all but at + most one NAK per NAK_ELIM_IVL thereby allowing repeated NAKs to keep + the repair state alive in the PGM network elements. + +7.5. NAK Anticipation + + An unsolicited NCF is one that is received by a network element when + the network element has no corresponding pending or outstanding NAK. + Network elements MUST process unsolicited NCFs differently depending + on the interface on which they are received. + + If the interface on which an NCF is received is the same interface + the network element would use to reach the upstream PGM network + element, the network element simply establishes repair state for + NCF_TSI and NCF_SQN without adding the interface to the repair + interface list, and discards the NCF. If the repair state already + exists, the network element restarts the NAK_RDATA_IVL and + NAK_ELIM_IVL timers and discards the NCF. + + If the interface on which an NCF is received is not the same + interface the network element would use to reach the upstream PGM + network element, the network element does not establish repair state + and just discards the NCF. + + Anticipated NAKs permit the elimination of any subsequent matching + NAKs from downstream. Upon establishing anticipated repair state, + network elements MUST eliminate subsequent NAKs only for a period of + NAK_ELIM_IVL. Upon expiry of NAK_ELIM_IVL, network elements MUST + suspend NAK elimination for that TSI/SQN until the first duplicate of + that NAK is seen after the expiry of NAK_ELIM_IVL. This duplicate + MUST be forwarded in the usual manner. Once this duplicate NAK is + outstanding, network elements MUST once again discard all duplicates + of that NAK for NAK_ELIM_IVL, and so on. NAK_RDATA_IVL MUST be reset + + + + + +Speakman, et. al. Experimental [Page 30] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + each time a NAK for the corresponding TSI/SQN is confirmed (i.e., + each time NAK_ELIM_IVL is reset). NAK_ELIM_IVL must be some small + fraction of NAK_RDATA_IVL. + +7.6. NAK Shedding + + Network elements MAY implement local procedures for withholding NAK + confirmations for receivers detected to be reporting excessive loss. + The result of these procedures would ultimately be unrecoverable data + loss in the receiver. + +7.7. Addressing NAKs + + A PGM network element uses the source and group addresses (NLAs) + contained in the transport header to find the state for the + corresponding TSI, looks up the corresponding upstream PGM network + element's address, uses it to re-address the (unicast) NAK, and + unicasts it on the upstream interface for the distribution tree for + the TSI. + +7.8. Constrained RDATA Forwarding + + Network elements MUST maintain repair state for each interface on + which a given NAK is received at least once. Network elements MUST + then use this list of interfaces to constrain the forwarding of the + corresponding RDATA packet only to those interfaces in the list. An + RDATA packet corresponds to a NAK if it matches NAK_TSI and NAK_SQN. + + Network elements MUST maintain this repair state only until either + the corresponding RDATA is received and forwarded, or NAK_RDATA_IVL + passes after forwarding the most recent instance of a given NAK. + Thereafter, the corresponding repair state MUST be discarded. + + Network elements SHOULD discard and not forward RDATA packets for + which they have no repair state. Note that the consequence of this + procedure is that, while it constrains repairs to the interested + subset of the network, loss of repair state precipitates further NAKs + from neglected receivers. + +8. Packet Formats + + All of the packet formats described in this section are transport- + layer headers that MUST immediately follow the network-layer header + in the packet. Only data packet headers (ODATA and RDATA) may be + followed in the packet by application data. For each packet type, + the network-header source and destination addresses are specified in + + + + + +Speakman, et. al. Experimental [Page 31] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + addition to the format and contents of the transport layer header. + Recall from General Procedures that, for PGM over IP multicast, SPMs, + NCFs, and RDATA MUST also bear the IP Router Alert Option. + + For PGM over IP, the IP protocol number is 113. + + In all packets the descriptions of Data-Source Port, Data-Destination + Port, Type, Options, Checksum, Global Source ID (GSI), and Transport + Service Data Unit (TSDU) Length are: + + Data-Source Port: + + A random port number generated by the source. This port number + MUST be unique within the source. Source Port together with + Global Source ID forms the TSI. + + Data-Destination Port: + + A globally well-known port number assigned to the given PGM + application. + + Type: + + The high-order two bits of the Type field encode a version + number, 0x0 in this instance. The low-order nibble of the type + field encodes the specific packet type. The intervening two + bits (the low-order two bits of the high-order nibble) are + reserved and MUST be zero. + + Within the low-order nibble of the Type field: + + values in the range 0x0 through 0x3 represent SPM-like + packets (i.e., session-specific, sourced by a source, + periodic), + + values in the range 0x4 through 0x7 represent DATA-like + packets (i.e., data and repairs), + + values in the range 0x8 through 0xB represent NAK-like + packets (i.e., hop-by-hop reliable NAK forwarding + procedures), + + and values in the range 0xC through 0xF represent SPMR-like + packets (i.e., session-specific, sourced by a receiver, + asynchronous). + + + + + + +Speakman, et. al. Experimental [Page 32] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Options: + + This field encodes binary indications of the presence and + significance of any options. It also directly encodes some + options. + + bit 0 set => One or more Option Extensions are present + + bit 1 set => One or more Options are network-significant + + Note that this bit is clear when OPT_FRAGMENT and/or + OPT_JOIN are the only options present. + + bit 6 set => Packet is a parity packet for a transmission group + of variable sized packets (OPT_VAR_PKTLEN). Only present when + OPT_PARITY is also present. + + bit 7 set => Packet is a parity packet (OPT_PARITY) + + Bits are numbered here from left (0 = MSB) to right (7 = LSB). + + All the other options (option extensions) are encoded in + extensions to the PGM header. + + Checksum: + + This field is the usual 1's complement of the 1's complement + sum of the entire PGM packet including header. + + The checksum does not include a network-layer pseudo header for + compatibility with network address translation. If the + computed checksum is zero, it is transmitted as all ones. A + value of zero in this field means the transmitter generated no + checksum. + + Note that if any entity between a source and a receiver + modifies the PGM header for any reason, it MUST either + recompute the checksum or clear it. The checksum is mandatory + on data packets (ODATA and RDATA). + + Global Source ID: + + A globally unique source identifier. This ID MUST NOT change + throughout the duration of the transport session. A + RECOMMENDED identifier is the low-order 48 bits of the MD5 [9] + signature of the DNS name of the source. Global Source ID + together with Data-Source Port forms the TSI. + + + + +Speakman, et. al. Experimental [Page 33] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + TSDU Length: + + The length in octets of the transport data unit exclusive of + the transport header. + + Note that those who require the TPDU length must obtain it from + sum of the transport header length (TH) and the TSDU length. + TH length is the sum of the size of the particular PGM packet + header (type_specific_size) plus the length of any options that + might be present. + + Address Family Indicators (AFIs) are as specified in [10]. + +8.1. Source Path Messages + + SPMs are sent by a source to establish source path state in network + elements and to provide transmit window state to receivers. + + The network-header source address of an SPM is the unicast NLA of the + entity that originates the SPM. + + The network-header destination address of an SPM is a multicast group + NLA. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Port | Destination Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Options | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Global Source ID ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ... Global Source ID | TSDU Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SPM's Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Trailing Edge Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Leading Edge Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NLA AFI | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Path NLA ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + | Option Extensions when present ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + + +Speakman, et. al. Experimental [Page 34] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Source Port: + + SPM_SPORT + + Data-Source Port, together with SPM_GSI forms SPM_TSI + + Destination Port: + + SPM_DPORT + + Data-Destination Port + + Type: + + SPM_TYPE = 0x00 + + Global Source ID: + + SPM_GSI + + Together with SPM_SPORT forms SPM_TSI + + SPM's Sequence Number + + SPM_SQN + + The sequence number assigned to the SPM by the source. + + Trailing Edge Sequence Number: + + SPM_TRAIL + + The sequence number defining the current trailing edge of the + source's transmit window (TXW_TRAIL). + + Leading Edge Sequence Number: + + SPM_LEAD + + The sequence number defining the current leading edge of the + source's transmit window (TXW_LEAD). + + If SPM_TRAIL == 0 and SPM_LEAD == 0x80000000, this indicates that + no window information is present in the packet. + + + + + + + +Speakman, et. al. Experimental [Page 35] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Path NLA: + + SPM_PATH + + The NLA of the interface on the network element on which this SPM + was forwarded. Initialized by a source to the source's NLA, + rewritten by each PGM network element upon forwarding. + +8.2. Data Packets + + Data packets carry application data from a source or a repairer to + receivers. + + ODATA: + + Original data packets transmitted by a source. + + RDATA: + + Repairs transmitted by a source or by a designated local + repairer (DLR) in response to a NAK. + + The network-header source address of a data packet is the unicast NLA + of the entity that originates the data packet. + + The network-header destination address of a data packet is a + multicast group NLA. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Port | Destination Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Options | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Global Source ID ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ... Global Source ID | TSDU Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Data Packet Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Trailing Edge Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Extensions when present ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Data ... + +-+-+- ... + + + + +Speakman, et. al. Experimental [Page 36] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Source Port: + + OD_SPORT, RD_SPORT + + Data-Source Port, together with Global Source ID forms: + + OD_TSI, RD_TSI + + Destination Port: + + OD_DPORT, RD_DPORT + + Data-Destination Port + + Type: + + OD_TYPE = 0x04 RD_TYPE = 0x05 + + Global Source ID: + + OD_GSI, RD_GSI + + Together with Source Port forms: + + OD_TSI, RD_TSI + + Data Packet Sequence Number: + + OD_SQN, RD_SQN + + The sequence number originally assigned to the ODATA packet by the + source. + + Trailing Edge Sequence Number: + + OD_TRAIL, RD_TRAIL + + The sequence number defining the current trailing edge of the + source's transmit window (TXW_TRAIL). In RDATA, this MAY not be + the same as OD_TRAIL of the ODATA packet for which it is a repair. + + Data: + + Application data. + + + + + + + +Speakman, et. al. Experimental [Page 37] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +8.3. Negative Acknowledgments and Confirmations + + NAK: + + Negative Acknowledgments are sent by receivers to request the + repair of an ODATA packet detected to be missing from the + expected sequence. + + N-NAK: + + Null Negative Acknowledgments are sent by DLRs to provide flow + control feedback to the source of ODATA for which the DLR has + provided the corresponding RDATA. + + The network-header source address of a NAK is the unicast NLA of the + entity that originates the NAK. The network-header source address of + NAK is rewritten by each PGM network element with its own. + + The network-header destination address of a NAK is initialized by the + originator of the NAK (a receiver) to the unicast NLA of the upstream + PGM network element known from SPMs. The network-header destination + address of a NAK is rewritten by each PGM network element with the + unicast NLA of the upstream PGM network element to which this NAK is + forwarded. On the final hop, the network-header destination address + of a NAK is rewritten by the PGM network element with the unicast NLA + of the original source or the unicast NLA of a DLR. + + NCF: + + NAK Confirmations are sent by network elements and sources to + confirm the receipt of a NAK. + + The network-header source address of an NCF is the ODATA source's + NLA, not the network element's NLA as might be expected. + + The network-header destination address of an NCF is a multicast group + NLA. + + Note that in NAKs and N-NAKs, unlike the other packets, the field + SPORT contains the Data-Destination port and the field DPORT contains + the Data-Source port. As a general rule, the content of SPORT/DPORT + is determined by the direction of the flow: in packets which travel + down-stream SPORT is the port number chosen in the data source + (Data-Source Port) and DPORT is the data destination port number + (Data-Destination Port). The opposite holds for packets which travel + upstream. This makes DPORT the protocol endpoint in the recipient + host, regardless of the direction of the packet. + + + + +Speakman, et. al. Experimental [Page 38] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Port | Destination Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Options | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Global Source ID ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ... Global Source ID | TSDU Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Requested Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NLA AFI | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source NLA ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + | NLA AFI | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Multicast Group NLA ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + | Option Extensions when present ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... + + Source Port: + + NAK_SPORT, NNAK_SPORT + + Data-Destination Port + + NCF_SPORT + + Data-Source Port, together with Global Source ID forms NCF_TSI + + Destination Port: + + NAK_DPORT, NNAK_DPORT + + Data-Source Port, together with Global Source ID forms: + + NAK_TSI, NNAK_TSI + + NCF_DPORT + + Data-Destination Port + + + + + + +Speakman, et. al. Experimental [Page 39] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Type: + + NAK_TYPE = 0x08 NNAK_TYPE = 0x09 + + NCF_TYPE = 0x0A + + Global Source ID: + + NAK_GSI, NNAK_GSI, NCF_GSI + + Together with Data-Source Port forms + + NAK_TSI, NNAK_TSI, NCF_TSI + + Requested Sequence Number: + + NAK_SQN, NNAK_SQN + + NAK_SQN is the sequence number of the ODATA packet for which a + repair is requested. + + NNAK_SQN is the sequence number of the RDATA packet for which a + repair has been provided by a DLR. + + NCF_SQN + + NCF_SQN is NAK_SQN from the NAK being confirmed. + + Source NLA: + + NAK_SRC, NNAK_SRC, NCF_SRC + + The unicast NLA of the original source of the missing ODATA. + + Multicast Group NLA: + + NAK_GRP, NNAK_GRP, NCF_GRP + + The multicast group NLA. NCFs MAY bear OPT_REDIRECT and/or + OPT_NAK_LIST + +9. Options + + PGM specifies several end-to-end options to address specific + application requirements. PGM specifies options to support + fragmentation, late joining, and redirection. + + + + + +Speakman, et. al. Experimental [Page 40] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Options MAY be appended to PGM data packet headers only by their + original transmitters. While they MAY be interpreted by network + elements, options are neither added nor removed by network elements. + + Options are all in the TLV style, or Type, Length, Value. The Type + field is contained in the first byte, where bit 0 is the OPT_END bit, + followed by 7 bits of type. The OPT_END bit MUST be set in the last + option in the option list, whichever that might be. The Length field + is the total length of the option in bytes, and directly follows the + Type field. Following the Length field are 5 reserved bits, the + OP_ENCODED flag, the 2 Option Extensibility bits OPX and the + OP_ENCODED_NULL flag. Last are 7 bits designated for option specific + information which may be defined on a per-option basis. If not + defined for a particular option, they MUST be set to 0. + + The Option Extensibility bits dictate the desired treatment of an + option if it is unknown to the network element processing it. + + Nota Bene: Only network elements pay any attention to these bits. + + The OPX bits are defined as follows: + + 00 - Ignore the option + + 01 - Invalidate the option by changing the type to OPT_INVALID + = 0x7F + + 10 - Discard the packet + + 11 - Unsupported, and reserved for future use + + Some options present in data packet (ODATA and RDATA) are strictly + associated with the packet content (PGM payload), OPT_FRAGMENT being + an example. These options must be preserved even when the data + packet that would normally contain them is not received, but its the + payload is recovered though the use of FEC. PGM specifies a + mechanism to accomplish this that uses the F (OP_ENCODED) and U + (OP_ENCODED_NULL) bits in the option common header. OP_ENCODED and + OP_ENCODED_NULL MUST be normally set to zero except when the option + is used in FEC packets to preserve original options. See Appendix A + for details. + + There is a limit of 16 options per packet. + + + + + + + + +Speakman, et. al. Experimental [Page 41] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + General Option Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U|Opt. Specific| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Value ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...+-+-+ + +9.1. Option extension length - OPT_LENGTH + + When option extensions are appended to the standard PGM header, the + extensions MUST be preceded by an option extension length field + specifying the total length of all option extensions. + + In addition, the presence of the options MUST be encoded in the + Options field of the standard PGM header before the Checksum is + computed. + + All network-significant options MUST be appended before any + exclusively receiver-significant options. + + To provide an indication of the end of option extensions, OPT_END + (0x80) MUST be set in the Option Type field of the trailing option + extension. + +9.1.1. OPT_LENGTH - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Type | Option Length | Total length of all options | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x00 + + Option Length = 4 octets + + Total length of all options + + The total length in octets of all option extensions including + OPT_LENGTH. + + OPT_LENGTH is NOT network-significant. + + + + + + +Speakman, et. al. Experimental [Page 42] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.2. Fragmentation Option - OPT_FRAGMENT + + Fragmentation allows transport-layer entities at a source to break up + application protocol data units (APDUs) into multiple PGM data + packets (TPDUs) to conform with the MTU supported by the network + layer. The fragmentation option MAY be applied to ODATA and RDATA + packets only. + + Architecturally, the accumulation of TSDUs into APDUs is applied to + TPDUs that have already been received, duplicate eliminated, and + contiguously sequenced by the receiver. Thus APDUs MAY be + reassembled across increments of the transmit window. + +9.2.1. OPT_FRAGMENT - Packet Extension Contents + + OPT_FRAG_OFF the offset of the fragment from the beginning of the + APDU + + OPT_FRAG_LEN the total length of the original APDU + +9.2.2. OPT_FRAGMENT - Procedures - Sources + + A source fragments APDUs into a contiguous series of fragments no + larger than the MTU supported by the network layer. A source + sequentially and uniquely assigns OD_SQNs to these fragments in the + order in which they occur in the APDU. A source then sets + OPT_FRAG_OFF to the value of the offset of the fragment in the + original APDU (where the first byte of the APDU is at offset 0, and + OPT_FRAG_OFF numbers the first byte in the fragment), and set + OPT_FRAG_LEN to the value of the total length of the original APDU. + +9.2.3. OPT_FRAGMENT - Procedures - Receivers + + Receivers detect and accumulate fragmented packets until they have + received an entire contiguous sequence of packets comprising an APDU. + This sequence begins with the fragment bearing OPT_FRAG_OFF of 0, and + terminates with the fragment whose length added to its OPT_FRAG_OFF + is OPT_FRAG_LEN. + + + + + + + + + + + + + +Speakman, et. al. Experimental [Page 43] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.2.4. OPT_FRAGMENT - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | First Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Offset | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x01 + + Option Length = 12 octets + + First Sequence Number + + Sequence Number of the PGM DATA/RDATA packet containing the first + fragment of the APDU. + + Offset + + The byte offset of the fragment from the beginning of the APDU + (OPT_FRAG_OFF). + + Length + + The total length of the original APDU (OPT_FRAG_LEN). + + OPT_FRAGMENT is NOT network-significant. + +9.3. NAK List Option - OPT_NAK_LIST + + The NAK List option MAY be used in conjunction with NAKs to allow + receivers to request transmission for more than one sequence number + with a single NAK packet. The option is limited to 62 listed NAK + entries. The NAK list MUST be unique and duplicate free. It MUST be + ordered, and MUST consist of either a list of selective or a list of + parity NAKs. In general, network elements, sources and receivers + must process a NAK list as if they had received individual NAKs for + each sequence number in the list. The procedures for each are + outlined in detail earlier in this document. Clarifications and + differences are detailed here. + + + + + +Speakman, et. al. Experimental [Page 44] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.3.1. OPT_NAK_LIST - Packet Extensions Contents + + A list of sequence numbers for which retransmission is requested. + +9.3.2. OPT_NAK_LIST - Procedures - Receivers + + Receivers MAY append the NAK List option to a NAK to indicate that + they wish retransmission of a number of RDATA. + + Receivers SHOULD proceed to back off NAK transmission in a manner + consistent with the procedures outlined for single sequence number + NAKs. Note that the repair of each separate sequence number will be + completed upon receipt of a separate RDATA packet. + + Reception of an NCF or multicast NAK containing the NAK List option + suspends generation of NAKs for all sequence numbers within the NAK + list, as well as the sequence number within the NAK header. + +9.3.3. OPT_NAK_LIST - Procedures - Network Elements + + Network elements MUST immediately respond to a NAK with an identical + NCF containing the same NAK list as the NAK itself. + + Network elements MUST forward a NAK containing a NAK List option if + any one sequence number specified by the NAK (including that in the + main NAK header) is not currently outstanding. That is, it MUST + forward the NAK, if any one sequence number does not have an + elimination timer running for it. The NAK must be forwarded intact. + + Network elements MUST eliminate a NAK containing the NAK list option + only if all sequence numbers specified by the NAK (including that in + the main NAK header) are outstanding. That is, they are all running + an elimination timer. + + Upon receipt of an unsolicited NCF containing the NAK list option, a + network element MUST anticipate data for every sequence number + specified by the NAK as if it had received an NCF for every sequence + number specified by the NAK. + +9.3.4. OPT_NAK_LIST - Procedures - Sources + + A source MUST immediately respond to a NAK with an identical NCF + containing the same NAK list as the NAK itself. + + It MUST then multicast RDATA (while respecting TXW_MAX_RTE) for every + requested sequence number. + + + + + +Speakman, et. al. Experimental [Page 45] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.3.5. OPT_NAK_LIST - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Requested Sequence Number 1 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ..... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Requested Sequence Number N | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x02 + + Option Length = 4 + (4 * number of SQNs) octets + + Requested Sequence Number + + A list of up to 62 additional sequence numbers to which the NAK + applies. + + OPT_NAK_LIST is network-significant. + +9.4. Late Joining Option - OPT_JOIN + + Late joining allows a source to bound the amount of repair history + receivers may request when they initially join a particular transport + session. + + This option indicates that receivers that join a transport session in + progress MAY request repair of all data as far back as the given + minimum sequence number from the time they join the transport + session. The default is for receivers to receive data only from the + first packet they receive and onward. + +9.4.1. OPT_JOIN - Packet Extensions Contents + + OPT_JOIN_MIN the minimum sequence number for repair + +9.4.2. OPT_JOIN - Procedures - Receivers + + If a PGM packet (ODATA, RDATA, or SPM) bears OPT_JOIN, a receiver MAY + initialize the trailing edge of the receive window (RXW_TRAIL_INIT) + to the given Minimum Sequence Number and proceeds with normal data + reception. + + + + +Speakman, et. al. Experimental [Page 46] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.4.3. OPT_JOIN - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Minimum Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Option Type = 0x03 + + Option Length = 8 octets + + Minimum Sequence Number + + The minimum sequence number defining the initial trailing edge of + the receive window for a late joining receiver. + + OPT_JOIN is NOT network-significant. + +9.5. Redirect Option - OPT_REDIRECT + + Redirection MAY be used by a designated local repairer (DLR) to + advertise its own address as an alternative to the original source, + for requesting repairs. + + These procedures allow a PGM Network Element to use a DLR that is one + PGM hop from it either upstream or downstream in the multicast + distribution tree. The former are referred to as upstream DLRs. The + latter are referred to as off-tree DLRs. Off-Tree because even + though they are downstream of the point of loss, they might not lie + on the subtree affected by the loss. + + A DLR MUST receive any PGM sessions for which it wishes to provide + retransmissions. A DLR SHOULD respond to NCFs or POLLs sourced by + its PGM parent with a redirecting POLR response packet containing an + OPT_REDIRECT which provides its own network layer address. + Recipients of redirecting POLRs MAY then direct NAKs for subsequent + ODATA sequence numbers to the DLR rather than to the original source. + In addition, DLRs that receive redirected NAKs for which they have + RDATA MUST send a NULL NAK to provide flow control to the original + source without also provoking a repair from that source. + + + + + + + +Speakman, et. al. Experimental [Page 47] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.5.1. OPT_REDIRECT - Packet Extensions Contents + + OPT_REDIR_NLA the DLR's own unicast network-layer address to which + recipients of the redirecting POLR MAY direct + subsequent NAKs for the corresponding TSI. + +9.5.2. OPT_REDIRECT - Procedures - DLRs + + A DLR MUST receive any PGM sessions for which it wishes to provide a + source of repairs. In addition to acting as an ordinary PGM + receiver, a DLR MAY then respond to NCFs or relevant POLLs sourced by + parent network elements (or even by the source itself) by sending a + POLR containing an OPT_REDIRECT providing its own network-layer + address. + + If a DLR can provide FEC repairs it MUST denote this by setting + OPT_PARITY in the PGM header of its POLR response. + +9.5.2.1. Upstream DLRs + + If the NCF completes NAK transmission initiated by the DLR itself, + the DLR MUST NOT send a redirecting POLR. + + When a DLR receives an NCF from its upstream PGM parent, it SHOULD + send a redirecting POLR, multicast to the group. The DLR SHOULD + record that it is acting as an upstream DLR for the said session. + Note that this POLR MUST have both the data source's source address + and the router alert option in its network header. + + An upstream DLR MUST act as an ordinary PGM source in responding to + any NAK it receives (i.e., directed to it). That is, it SHOULD + respond first with a normal NCF and then RDATA as usual. In + addition, an upstream DLR that receives redirected NAKs for which it + has RDATA MUST send a NULL NAK to provide flow control to the + original source. If it cannot provide the RDATA it forwards the NAK + to the upstream PGM neighbor as usual. + + Nota Bene: In order to propagate on exactly the same distribution + tree as ODATA, RDATA and POLR packets transmitted by DLRs MUST + bear the ODATA source's NLA as the network-header source address, + not the DLR's NLA as might be expected. + + + + + + + + + + +Speakman, et. al. Experimental [Page 48] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.5.2.2. Off-Tree DLRs + + A DLR that receives a POLL with sub-type PGM_POLL_DLR MUST respond + with a unicast redirecting POLR if it provides the appropriate + service. The DLR SHOULD respond using the rules outlined for polling + in Appendix D of this text. If the DLR responds, it SHOULD record + that it is acting as an off-tree DLR for the said session. + + An off-tree DLR acts in a special way in responding to any NAK it + receives (i.e., directed to it). It MUST respond to a NAK directed + to it from its parent by unicasting an NCF and RDATA to its parent. + The parent will then forward the RDATA down the distribution tree. + The DLR uses its own and the parent's NLA addresses in the network + header for the source and destination respectively. The unicast NCF + and RDATA packets SHOULD not have the router alert option. In all + other ways the RDATA header should be "as if" the packet had come + from the source. + + Again, an off-tree DLR that receives redirected NAKs for which it has + RDATA MUST originate a NULL NAK to provide flow control to the + original source. It MUST originate the NULL NAK before originating + the RDATA. This must be done to reduce the state held in the network + element. + + If it cannot provide the RDATA for a given NAK, an off-tree DLR + SHOULD confirm the NAK with a unicast NCF as normal, then immediately + send a NAK for the said data packet back to its parent. + +9.5.2.3. Simultaneous Upstream and Off-Tree DLR operation + + Note that it is possible for a DLR to provide service to its parent + and to downstream network elements simultaneously. A downstream loss + coupled with a loss for the same data on some other part of the + distribution tree served by its parent could cause this. In this + case it may provide both upstream and off-tree functionality + simultaneously. + + Note that a DLR differentiates between NAKs from an NE downstream or + from its parent by comparing the network-header source address of the + NAK with it's upstream PGM parent's NLA. The DLR knows the parent's + NLA from the session's SPM messages. + + + + + + + + + + +Speakman, et. al. Experimental [Page 49] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.5.3. OPT_REDIRECT - Procedures - Network Elements + +9.5.3.1. Discovering DLRs + + When a PGM router receives notification of a loss via a NAK, it + SHOULD first try to use a known DLR to recover the loss. If such a + DLR is not known it SHOULD initiate DLR discovery. DLR discovery may + occur in two ways. If there are upstream DLRs, the NAK transmitted + by this router to its PGM parent will trigger their discovery, via a + redirecting POLR. Also, a network element SHOULD initiate a search + for off-tree DLRs using the PGM polling mechanism, and the sub-type + PGM_POLL_DLR. + + If a DLR can provide FEC repairs it will denote this by setting + OPT_PARITY in the PGM header of its POLR response. A network element + SHOULD only direct parity NAKs to a DLR that can provide FEC repairs. + +9.5.3.2. Redirected Repair + + When it can, a network element SHOULD use upstream DLRs. + + Upon receiving a redirecting POLR, network elements SHOULD record the + redirecting information for the TSI, and SHOULD redirect subsequent + NAKs for the same TSI to the network address provided in the + redirecting POLR rather than to the PGM neighbor known via the SPMs. + Note, however, that a redirecting POLR is NOT regarded as matching + the NAK that provoked it, so it does not complete the transmission of + that NAK. Only a normal matching NCF can complete the transmission + of a NAK. + + For subsequent NAKs, if the network element has recorded redirection + information for the corresponding TSI, it MAY change the destination + network address of those NAKs and attempt to transmit them to the + DLR. No NAK for a specific SQN SHOULD be sent to an off-tree DLR if + a NAK for the SQN has been seen on the interface associated with the + DLR. Instead the NAK SHOULD be forwarded upstream. Subsequent NAKs + for different SQNs MAY be forwarded to the said DLR (again assuming + no NAK for them has been seen on the interface to the DLR). + + If a corresponding NCF is not received from the DLR within + NAK_RPT_IVL, the network element MUST discard the redirecting + information for the TSI and re-attempt to forward the NAK towards the + PGM upstream neighbor. + + + + + + + + +Speakman, et. al. Experimental [Page 50] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + If a NAK is received from the DLR for a requested SQN, the network + element MUST discard the redirecting information for the SQN and re- + attempt to forward the NAK towards the PGM upstream neighbor. The + network element MAY still direct NAKs for different SQNs to the DLR. + + RDATA and NCFs from upstream DLRs will flow down the distribution + tree. However, RDATA and NCFs from off-tree DLRs will be unicast to + the network element. The network element will terminate the NCF, but + MUST put the source's NLA and the group address into the network + header and MUST add router alert before forwarding the RDATA packet + to the distribution subtree. + + NULL NAKs from an off-tree DLR for an RDATA packet requested from + that off-tree DLR MUST always be forwarded upstream. The network + element can assume that these will arrive before the matching RDATA. + Other NULL NAKs are forwarded only if matching repair state has not + already been created. Network elements MUST NOT confirm or retry + NULL NAKs and they MUST NOT add the receiving interface to the repair + state. If a NULL NAK is used to initially create repair state, this + fact must be recorded so that any subsequent non-NULL NAK will not be + eliminated, but rather will be forwarded to provoke an actual repair. + State created by a NULL NAK exists only for NAK_ELIM_IVL. + +9.5.4. OPT_REDIRECT - Procedures - Receivers + + These procedures are intended to be applied in instances where a + receiver's first hop router on the reverse path to the source is not + a PGM Network Element. So, receivers MUST ignore a redirecting POLR + from a DLR on the same IP subnet that the receiver resides on, since + this is likely to suffer identical loss to the receiver and so be + useless. Therefore, these procedures are entirely OPTIONAL. A + receiver MAY choose to ignore all redirecting POLRs since in cases + where its first hop router on the reverse path is PGM capable, it + would ignore them anyway. Also, note that receivers will never learn + of off-tree DLRs. + + Upon receiving a redirecting POLR, receivers SHOULD record the + redirecting information for the TSI, and MAY redirect subsequent NAKs + for the same TSI to the network address provided in the redirecting + POLR rather than to the PGM neighbor for the corresponding ODATA for + which the receiver is requesting repair. Note, however, that a + redirecting POLR is NOT regarded as matching the NAK that provoked + it, so it does not complete the transmission of that NAK. Only a + normal matching NCF can complete the transmission of a NAK. + + For subsequent NAKs, if the receiver has recorded redirection + information for the corresponding TSI, it MAY change the destination + network address of those NAKs and attempt to transmit them to the + + + +Speakman, et. al. Experimental [Page 51] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + DLR. If a corresponding NCF is not received within NAK_RPT_IVL, the + receiver MUST discard the redirecting information for the TSI and + re-attempt to forward the NAK to the PGM neighbor for the original + source of the missing ODATA. + +9.5.5. OPT_REDIRECT - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NLA AFI | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | DLR's NLA ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + + Option Type = 0x07 + + Option Length = 4 + NLA length + + DLR's NLA + + The DLR's own unicast network address to which recipients of the + redirecting POLR may direct subsequent NAKs. + + OPT_REDIRECT is network-significant. + +9.6. OPT_SYN - Synchronization Option + + The SYN option indicates the starting data packet for a session. It + must only appear in ODATA or RDATA packets. + + The SYN option MAY be used to provide a useful abstraction to + applications that can simplify application design by providing stream + start notification. It MAY also be used to let a late joiner to a + session know that it is indeed late (i.e. it would not see the SYN + option). + +9.6.1. OPT_SYN - Procedures - Receivers + + Procedures for receivers are implementation dependent. A receiver + MAY use the SYN to provide its applications with abstractions of the + data stream. + + + + + + + +Speakman, et. al. Experimental [Page 52] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.6.2. OPT_SYN - Procedures - Sources + + Sources MAY include OPT_SYN in the first data for a session. That + is, they MAY include the option in: + + the first ODATA sent on a session by a PGM source + + any RDATA sent as a result of loss of this ODATA packet + + all FEC packets for the first transmission group; in this case it + is interpreted as the first packet having the SYN + +9.6.3. OPT_SYN - Procedures - DLRs + + In an identical manner to sources, DLRs MUST provide OPT_SYN in + any retransmitted data that is at the start of a session. + +9.6.4. OPT_SYN - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x0D + + Option Length = 4 + + OPT_SYN is NOT network-significant. + +9.7. OPT_FIN - Session Finish Option + + This FIN option indicates the last data packet for a session and + an orderly close down. + + The FIN option MAY be used to provide an abstraction to + applications that can simplify application design by providing + stream end notification. + + This option MAY be present in the last data packet or transmission + group for a session. The FIN PGM option MUST appear in every SPM + sent after the last ODATA for a session. The SPM_LEAD sequence + number in an SPM with the FIN option indicates the last known data + successfully transmitted for the session. + + + + + + +Speakman, et. al. Experimental [Page 53] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.7.1. OPT_FIN - Procedures - Receivers + + A receiver SHOULD use receipt of a FIN to let it know that it can + tear down its data structures for the said session once a suitable + time period has expired (TXW_SECS). It MAY still try to solicit + retransmissions within the existing transmit window. + + Other than this, procedures for receivers are implementation + dependent. A receiver MAY use the FIN to provide its applications + with abstractions of the data stream and to inform its + applications that the session is ending. + + 9.7.2. OPT_FIN - Procedures - Sources + + Sources MUST include OPT_FIN in every SPM sent after it has been + determined that the application has closed gracefully. If a + source is aware at the time of transmission that it is ending a + session the source MAY include OPT_FIN in, + + the last ODATA + + any associated RDATAs for the last data + + FEC packets for the last transmission group; in this case it is + interpreted as the last packet having the FIN + + When a source detects that it needs to send an OPT_FIN it SHOULD + immediately send it. This is done either by appending it to the last + data packet or transmission group or by immediately sending an SPM + and resetting the SPM heartbeat timer (i.e. it does not wait for a + timer to expire before sending the SPM). After sending an OPT_FIN, + the session SHOULD not close and stop sending SPMs until after a time + period equal to TXW_SECS. + +9.7.3. OPT_FIN - Procedures - DLRs + + In an identical manner to sources, DLRs MUST provide OPT_FIN in any + retransmitted data that is at the end of a session. + + + + + + + + + + + + + +Speakman, et. al. Experimental [Page 54] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.7.4. OPT_FIN - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x0E + + Option Length = 4 + + OPT_FIN is NOT network-significant. + +9.8. OPT_RST - Session Reset Option + + The RST option MAY appear in every SPM sent after an unrecoverable + error is identified by the source. This acts to notify the receivers + that the session is being aborted. This option MAY appear only in + SPMs. The SPM_LEAD sequence number in an SPM with the RST option + indicates the last known data successfully transmitted for the + session. + +9.8.1. OPT_RST - Procedures - Receivers + + Receivers SHOULD treat the reception of OPT_RST in an SPM as an abort + of the session. + + A receiver that receives an SPM with an OPT_RST with the N bit set + SHOULD not send any more NAKs for the said session towards the + source. If the N bit (see 9.8.5) is not set, the receiver MAY + continue to try to solicit retransmit data within the current + transmit window. + +9.8.2. OPT_RST - Procedures - Sources + + Sources SHOULD include OPT_RST in every SPM sent after it has been + determined that an unrecoverable error condition has occurred. The N + bit of the OPT_RST SHOULD only be sent if the source has determined + that it cannot process NAKs for the session. The cause of the + OPT_RST is set to an implementation specific value. If the error + code is unknown, then the value of 0x00 is used. When a source + detects that it needs to send an OPT_RST it SHOULD immediately send + it. This is done by immediately sending an SPM and resetting the SPM + heartbeat timer (i.e. it does not wait for a timer to expire before + sending the SPM). After sending an OPT_RST, the session SHOULD not + close and stop sending SPMs until after a time period equal to + TXW_SECS. + + + +Speakman, et. al. Experimental [Page 55] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +9.8.3. OPT_RST - Procedures - DLRs + + None. + +9.8.4. OPT_RST - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U|N|Error Code | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x0F + + Option Length = 4 + + N bit + + The N bit is set to 1 to indicate that NAKs for previous ODATA + will go unanswered from the source. The application will tell the + source to turn this bit on or off. + + Error Code + + The 6 bit error code field is used to forward an error code down + to the receivers from the source. + + The value of 0x00 indicates an unknown reset reason. Any other + value indicates the application purposely aborted and gave a + reason (the error code value) that may have meaning to the end + receiver application. These values are entirely application + dependent. + + OPT_RST is NOT network-significant. + +10. Security Considerations + + In addition to the usual problems of end-to-end authentication, PGM + is vulnerable to a number of security risks that are specific to the + mechanisms it uses to establish source path state, to establish + repair state, to forward NAKs, to identify DLRs, and to distribute + repairs. These mechanisms expose PGM network elements themselves to + security risks since network elements not only switch but also + interpret SPMs, NAKs, NCFs, and RDATA, all of which may legitimately + be transmitted by PGM sources, receivers, and DLRs. Short of full + authentication of all neighboring sources, receivers, DLRs, and + network elements, the protocol is not impervious to abuse. + + + + +Speakman, et. al. Experimental [Page 56] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + So putting aside the problems of rogue PGM network elements for the + moment, there are enough potential security risks to network elements + associated with sources, receivers, and DLRs alone. These risks + include denial of service through the exhausting of both CPU + bandwidth and memory, as well as loss of (repair) data connectivity + through the muddling of repair state. + + False SPMs may cause PGM network elements to mis-direct NAKs intended + for the legitimate source with the result that the requested RDATA + would not be forthcoming. + + False NAKs may cause PGM network elements to establish spurious + repair state that will expire only upon time-out and could lead to + memory exhaustion in the meantime. + + False NCFs may cause PGM network elements to suspend NAK forwarding + prematurely (or to mis-direct NAKs in the case of redirecting POLRs) + resulting eventually in loss of RDATA. + + False RDATA may cause PGM network elements to tear down legitimate + repair state resulting eventually in loss of legitimate RDATA. + + The development of precautions for network elements to protect + themselves against incidental or unsophisticated versions of these + attacks is work outside of this spec and includes: + + Damping of jitter in the value of either the network-header source + address of SPMs or the path NLA in SPMs. While the network-header + source address is expected to change seldom, the path NLA is + expected to change occasionally as a consequence of changes in + underlying multicast routing information. + + The extension of NAK shedding procedures to control the volume, not + just the rate, of confirmed NAKs. In either case, these procedures + assist network elements in surviving NAK attacks at the expense of + maintaining service. More efficiently, network elements may use the + knowledge of TSIs and their associated transmit windows gleaned from + SPMs to control the proliferation of repair state. + + A three-way handshake between network elements and DLRs that would + permit a network element to ascertain with greater confidence that an + alleged DLR is identified by the alleged network-header source + address, and is PGM conversant. + + + + + + + + +Speakman, et. al. Experimental [Page 57] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +11. Appendix A - Forward Error Correction + +11.1. Introduction + + The following procedures incorporate packet-level Reed Solomon + Erasure correcting techniques as described in [11] and [12] into PGM. + This approach to Forward Error Correction (FEC) is based upon the + computation of h parity packets from k data packets for a total of n + packets such that a receiver can reconstruct the k data packets out + of any k of the n packets. The original k data packets are referred + to as the Transmission Group, and the total n packets as the FEC + Block. + + These procedures permit any combination of pro-active FEC or on- + demand FEC with conventional ARQ (selective retransmission) within a + given TSI to provide any flavor of layered or integrated FEC. The + two approaches can be used by the same or different receivers in a + single transport session without conflict. Once provided by a + source, the actual use of FEC or selective retransmission for loss + recovery in the session is entirely at the discretion of the + receivers. Note however that receivers SHOULD NOT ask for selective + retransmissions when FEC is available, nevertheless sources MUST + provide selective retransmissions in response to selective NAKs from + the leading partial transmission group (i.e. the most recent + transmission group, which is not yet full). For any group that is + full, the source SHOULD provide FEC on demand in response to a + selective NAK. + + Pro-active FEC refers to the technique of computing parity packets at + transmission time and transmitting them as a matter of course + following the data packets. Pro-active FEC is RECOMMENDED for + providing loss recovery over simplex or asymmetric multicast channels + over which returning repair requests is either impossible or costly. + It provides increased reliability at the expense of bandwidth. + + On-demand FEC refers to the technique of computing parity packets at + repair time and transmitting them only upon demand (i.e., receiver- + based loss detection and repair request). On-demand FEC is + RECOMMENDED for providing loss recovery of uncorrelated loss in very + large receiver populations in which the probability of any single + packet being lost is substantial. It provides equivalent reliability + to selective NAKs (ARQ) at no more and typically less expense of + bandwidth. + + Selective NAKs are NAKs that request the retransmission of specific + packets by sequence number corresponding to the sequence number of + any data packets detected to be missing from the expected sequence + (conventional ARQ). Selective NAKs can be used for recovering losses + + + +Speakman, et. al. Experimental [Page 58] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + occurring in leading partial transmission groups, i.e. in the most + recent transmission group, which is not yet full. The RECOMMENDED + way of handling partial transmission groups, however, is for the data + source to use variable-size transmission groups (see below). + + Parity NAKs are NAKs that request the transmission of a specific + number of parity packets by count corresponding to the count of the + number of data packets detected to be missing from a group of k data + packets (on-demand FEC). + + The objective of these procedures is to incorporate these FEC + techniques into PGM so that: + + sources MAY provide parity packets either pro-actively or on- + demand, interchangeably within the same TSI, + + receivers MAY use either selective or parity NAKs interchangeably + within the same TSI (however, in a session where on-demand parity + is available receivers SHOULD only use parity NAKs). + + network elements maintain repair state based on either selective + or parity NAKs in the same data structure, altering only search, + RDATA constraint, and deletion algorithms in either case, + + and only OPTION additions to the basic packet formats are + REQUIRED. + +11.2. Overview + + Advertising FEC parameters in the transport session + + Sources add OPT_PARITY_PRM to SPMs to provide session-specific + parameters such as the number of packets (TGSIZE == k) in a + transmission group. This option lets receivers know how many packets + there are in a transmission group, and it lets network elements sort + repair state by transmission group number. This option includes an + indication of whether pro-active and/or on-demand parity is available + from the source. + + Distinguishing parity packets from data packets + + Sources send pro-active parity packets as ODATA (NEs do not forward + RDATA unless a repair state is present) and on-demand parity packets + as RDATA. A source MUST add OPT_PARITY to the ODATA/RDATA packet + header of parity packets to permit network elements and receivers to + distinguish them from data packets. + + + + + +Speakman, et. al. Experimental [Page 59] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Data and parity packet numbering + + Parity packets MUST be calculated over a fixed number k of data + packets known as the Transmission Group. Grouping of packets into + transmission groups effectively partitions a packet sequence number + into a high-order portion (TG_SQN) specifying the transmission group + (TG), and a low-order portion (PKT_SQN) specifying the packet number + (PKT-NUM in the range 0 through k-1) within that group. From an + implementation point of view, it's handy if k, the TG size, is a + power of 2. If so, then TG_SQN and PKT_SQN can be mapped side-by- + side into the 32 bit SQN. log2(TGSIZE) is then the size in bits of + PKT_SQN. + + This mapping does not reduce the effective sequence number space + since parity packets marked with OPT_PARITY allow the sequence space + (PKT_SQN) to be completely reused in order to number the h parity + packets, as long as h is not greater than k. + + In the case where h is greater than k, a source MUST add + OPT_PARITY_GRP to any parity packet numbered j greater than k-1, + specifying the number m of the group of k parity packets to which the + packet belongs, where m is just the quotient from the integer + division of j by k. Correspondingly, PKT-NUM for such parity packets + is just j modulo k. In other words, when a source needs to generate + more parity packets than there were original data packets (perhaps + because of a particularly lossy line such that a receiver lost not + only the original data but some of the parity RDATA as well), use the + OPT_PARITY_GRP option in order to number and identify the + transmission group of the extra packets that would exceed the normal + sequential number space. + + Note that parity NAKs (and consequently their corresponding parity + NCFs) MUST also contain the OPT_PARITY flag in the options field of + the fixed header, and that in these packets, PKT_SQN MUST contain + PKT_CNT, the number of missing packets, rather than PKT_NUM, the SQN + of a specific missing packet. More on all this later. + + Variable Transmission Group Size + + The transmission group size advertised in the OPT_PARITY_PRM option + on SPMs MUST be a power of 2 and constant for the duration of the + session. However, the actual transmission group size used MAY not be + constant for the duration of the session, and MAY not be a power of + 2. When a TG size different from the one advertised in + OPT_PARITY_PRM is used, the TG size advertised in OPT_PARITY_PRM MUST + be interpreted as specifying the maximum effective size of the TG. + + + + + +Speakman, et. al. Experimental [Page 60] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + When the actual TG size is not a power of 2 or is smaller than the + max TG size, there will be sparse utilization of the sequence number + space since some of the sequence numbers that would have been + consumed in numbering a maximum sized TG will not be assigned to + packets in the smaller TG. The start of the next transmission group + will always begin on the boundary of the maximum TG size as though + each of the sequence numbers had been utilized. + + When the source decides to use a smaller group size than that + advertised in OPT_PARITY_PRM, it appends OPT_CURR_TGSIZE to the last + data packet (ODATA) in the truncated transmission group. This lets + the receiver know that it should not expect any more packets in this + transmission group, and that it may start requesting repairs for any + missing packets. If the last data packet itself went missing, the + receiver will detect the end of the group when it receives a parity + packet for the group, an SPM with SPM_LEAD equal to OD_SQN of the + last data packet, or the first packet of the next group, whichever + comes first. In addition, any parity packet from this TG will also + carry the OPT_CURR_TGSIZE option as will any SPM sent with SPM_LEAD + equal to OD_SQN of the last data packet. + + Variable TSDU length + + If a non constant TSDU length is used within a given transmission + group, the size of parity packets in the corresponding FEC block MUST + be equal to the size of the largest original data packet in the + block. Parity packets MUST be computed by padding the original + packets with zeros up to the size of the largest data packet. Note + that original data packets are transmitted without padding. + + Receivers using a combination of original packets and FEC packets to + rebuild missing packets MUST pad the original packets in the same way + as the source does. The receiver MUST then feed the padded original + packets plus the parity packets to the FEC decoder. The decoder + produces the original packets padded with zeros up to the size of the + largest original packet in the group. In order for the receiver to + eliminate the padding on the reconstructed data packets, the original + size of the packet MUST be known, and this is accomplished as + follows: + + The source, along with the packet payloads, encodes the TSDU + length and appends the 2-byte encoded length to the padded FEC + packets. + + Receivers pad the original packets that they received to the + largest original packet size and then append the TSDU length to + the padded packets. They then pass them and the FEC packets to + the FEC decoder. + + + +Speakman, et. al. Experimental [Page 61] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + The decoder produces padded original packets with their original + TSDU length appended. Receivers MUST now use this length to get + rid of the padding. + + A source that transmits variable size packets MUST take into account + the fact that FEC packets will have a size equal to the maximum size + of the original packets plus the size of the length field (2 bytes). + + If a fixed packet size is used within a transmission group, the + encoded length is not appended to the parity packets. The presence + of the fixed header option flag OPT_VAR_PKTLEN in parity packets + allows receivers to distinguish between transmission groups with + variable sized packets and fixed-size ones, and behave accordingly. + + Payload-specific options + + Some options present in data packet (ODATA and RDATA) are strictly + associated with the packet content (PGM payload), OPT_FRAGMENT being + an example. These options must be preserved even when the data + packet that would normally contain them is not received, but its the + payload is recovered though the use of FEC. + + To achieve this, PGM encodes the content of these options in special + options that are inserted in parity packets. Two flags present in + the the option common-header are used for this process: bit F + (OP_ENCODED) and bit U (OP_ENCODED_NULL). + + Whenever at least one of the original packets of a TG contains a + payload-specific option of a given type, the source MUST include an + encoded version of that option type in all the parity packets it + transmits. The encoded option is computed by applying FEC encoding + to the whole option with the exception of the first three bytes of + the option common-header (E, Option Type, Option Length, OP_ENCODED + and OPX fields). The type, length and OPX of the encoded option are + the same as the type, length and OPX in the original options. + OP_ENCODED is set to 1 (all original option have OP_ENCODED = 0). + + The encoding is performed using the same process that is used to + compute the payload of the parity packet. i.e. the FEC encoder is fed + with one copy of that option type for each original packet in the TG. + If one (or more) original packet of the TG does not contain that + option type, an all zeroes option is used for the encoding process. + To be able to distinguish this "dummy" option from valid options with + all-zeroes payload, OP_ENCODED_NULL is used. OP_ENCODED_NULL is set + to 0 in all the original options, but the value of 1 is used in the + encoding process if the option did not exist in the original packet. + On the receiver side, all option with OP_ENCODED_NULL equal to 1 are + discarded after decoding. + + + +Speakman, et. al. Experimental [Page 62] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + When a receiver recovers a missing packet using FEC repair packets, + it MUST also recover payload-specific options, if any. The presence + of these can be unequivocally detected through the presence of + encoded options in parity packets (encoded options have OP_ENCODED + set to 1). Receivers apply FEC-recovery to encoded options and + possibly original options, as they do to recover packet payloads. + The FEC decoding is applied to the whole option with the exception of + the first three bytes of the option common-header (E, Option Type, + Option Length, OP_ENCODED and OPX fields). Each decoded option is + associated with the relative payload, unless OP_ENCODED_NULL turns + out to be 1, in which case the decoded option is discarded. + + The decoding MUST be performed using the 1st occurrence of a given + option type in original/parity packets. If one or more original + packets do not contain that option type, an option of the same type + with zero value must be used. This option MUST have OP_ENCODED_NULL + equal to 1. + +11.3. Packet Contents + + This section just provides enough short-hand to make the Procedures + intelligible. For the full details of packet contents, please refer + to Packet Formats below. + + OPT_PARITY indicated in pro-active (ODATA) and on-demand + (RDATA) parity packets to distinguish them from + data packets. This option is directly encoded in + the "Option" field of the fixed PGM header + + OPT_VAR_PKTLEN MAY be present in pro-active (ODATA) and on-demand + (RDATA) parity packets to indicate that the + corresponding transmission group is composed of + variable size data packets. This option is + directly encoded in the "Option" field of the fixed + PGM header + + OPT_PARITY_PRM appended by sources to SPMs to specify session- + specific parameters such as the transmission group + size and the availability of pro-active and/or on- + demand parity from the source + + OPT_PARITY_GRP the number of the group (greater than 0) of h + parity packets to which the parity packet belongs + when more than k parity packets are provided by the + source + + + + + + +Speakman, et. al. Experimental [Page 63] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + OPT_CURR_TGSIZE appended by sources to the last data packet and any + parity packets in a variable sized transmission + group to indicate to the receiver the actual size + of a transmission group. May also be appended to + certain SPMs + +11.3.1. Parity NAKs + + NAK_TG_SQN the high-order portion of NAK_SQN specifying the + transmission group for which parity packets are + requested + + NAK_PKT_CNT the low-order portion of NAK_SQN specifying the + number of missing data packets for which parity + packets are requested + + Nota Bene: NAK_PKT_CNT (and NCF_PKT_CNT) are 0-based counters, + meaning that NAK_PKT_CNT = 0 means that 1 FEC RDATA is being + requested, and in general NAK_PKT_CNT = k - 1 means that k FEC + RDATA are being requested. + +11.3.2. Parity NCFs + + NCF_TG_SQN the high-order portion of NCF_SQN specifying the + transmission group for which parity packets were + requested + + NCF_PKT_CNT the low-order portion of NCF_SQN specifying the + number of missing data packets for which parity + packets were requested + + Nota Bene: NCF_PKT_CNT (and NAK_PKT_CNT) are 0-based counters, + meaning that NAK_PKT_CNT = 0 means that 1 FEC RDATA is being + requested, and in general NAK_PKT_CNT = k - 1 means that k FEC + RDATA are being requested. + +11.3.3. On-demand Parity + + RDATA_TG_SQN the high-order portion of RDATA_SQN specifying the + transmission group to which the parity packet + belongs + + RDATA_PKT_SQN the low-order portion of RDATA_SQN specifying the + parity packet sequence number within the + transmission group + + + + + + +Speakman, et. al. Experimental [Page 64] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +11.3.4. Pro-active Parity + + ODATA_TG_SQN the high-order portion of ODATA_SQN specifying the + transmission group to which the parity packet + belongs + + ODATA_PKT_SQN the low-order portion of ODATA_SQN specifying the + parity packet sequence number within the + transmission group + +11.4. Procedures - Sources + + If a source elects to provide parity for a given transport session, + it MUST first provide the transmission group size PARITY_PRM_TGS in + the OPT_PARITY_PRM option of its SPMs. This becomes the maximum + effective transmission group size in the event that the source elects + to send smaller size transmission groups. If a source elects to + provide proactive parity for a given transport session, it MUST set + PARITY_PRM_PRO in the OPT_PARITY_PRM option of its SPMs. If a source + elects to provide on-demand parity for a given transport session, it + MUST set PARITY_PRM_OND in the OPT_PARITY_PRM option of its SPMs. + + A source MUST send any pro-active parity packets for a given + transmission group only after it has first sent all of the + corresponding k data packets in that group. Pro-active parity + packets MUST be sent as ODATA with OPT_PARITY in the fixed header. + + If a source elects to provide on-demand parity, it MUST respond to a + parity NAK for a transmission group with a parity NCF. The source + MUST complete the transmission of the k original data packets and the + proactive parity packets, possibly scheduled, before starting the + transmission of on-demand parity packets. Subsequently, the source + MUST send the number of parity packets requested by that parity NAK. + On-demand parity packets MUST be sent as RDATA with OPT_PARITY in the + fixed header. Previously transmitted pro-active parity packets + cannot be reused as on-demand parity packets, these MUST be computed + with new, previously unused, indexes. + + In either case, the source MUST provide selective retransmissions + only in response to selective NAKs from the leading partial + transmission group. For any group that is full, the source SHOULD + provide FEC on demand in response to a selective retransmission + request. + + In the absence of data to transmit, a source SHOULD prematurely + terminate the current transmission group by including OPT_CURR_TGSIZE + to the last data packet or to any proactive parity packets provided. + + + + +Speakman, et. al. Experimental [Page 65] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + If the last data packet has already been transmitted and there is no + provision for sending proactive parity packets, an SPM with + OPT_CURR_TGSIZE SHOULD be sent. + + A source consolidates requests for on-demand parity in the same + transmission group according to the following procedures. If the + number of pending (i.e., unsent) parity packets from a previous + request for on-demand parity packets is equal to or greater than + NAK_PKT_CNT in a subsequent NAK, that subsequent NAK MUST be + confirmed but MAY otherwise be ignored. If the number of pending + (i.e., unsent) parity packets from a previous request for on-demand + parity packets is less than NAK_PKT_CNT in a subsequent NAK, that + subsequent NAK MUST be confirmed but the source need only increase + the number of pending parity packets to NAK_PKT_CNT. + + When a source provides parity packets relative to a transmission + group with variable sized packets, it MUST compute parity packets by + padding the smaller original packets with zeroes out to the size of + the largest of the original packets. The source MUST also append the + encoded TSDU lengths at the end of any padding or directly to the end + of the largest packet, and add the OPT_VAR_PKTLEN option as specified + in the overview description. + + When a source provides variable sized transmission groups, it SHOULD + append the OPT_CURR_TGSIZE option to the last data packet in the + shortened group, and it MUST append the OPT_CURR_TGSIZE option to any + parity packets it sends within that group. In case the the last data + packet is sent before a determination has been made to shorten the + group and there is no provision for sending proactive parity packets, + an SPM with OPT_CURR_TGSIZE SHOULD be sent. The source MUST also add + OPT_CURR_TGSIZE to any SPM that it sends with SPM_LEAD equal to + OD_SQN of the last data packet. + + A receiver MUST NAK for the entire number of packets missing based on + the maximum TG size, even if it already knows that the actual TG size + is smaller. The source MUST take this into account and compute the + number of packets effectively needed as the difference between + NAK_PKT_CNT and an offset computed as the difference between the max + TG size and the effective TG size. + +11.5. Procedures - Receivers + + If a receiver elects to make use of parity packets for loss recovery, + it MUST first learn the transmission group size PARITY_PRM_TGS from + OPT_PARITY_PRM in the SPMs for the TSI. The transmission group size + is used by a receiver to determine the sequence number boundaries + between transmission groups. + + + + +Speakman, et. al. Experimental [Page 66] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Thereafter, if PARITY_PRM_PRO is also set in the SPMs for the TSI, a + receiver SHOULD use any pro-active parity packets it receives for + loss recovery, and if PARITY_PRM_OND is also set in the SPMs for the + TSI, it MAY solicit on-demand parity packets upon loss detection. If + PARITY_PRM_OND is set, a receiver MUST NOT send selective NAKs, + except in partial transmission groups if the source does not use the + variable transmission-group size option. Parity packets are ODATA + (pro-active) or RDATA (on-demand) packets distinguished by OPT_PARITY + which lets receivers know that ODATA/RDATA_TG_SQN identifies the + group of PARITY_PRM_TGS packets to which the parity may be applied + for loss recovery in the corresponding transmission group, and that + ODATA/RDATA_PKT_SQN is being reused to number the parity packets + within that group. Receivers order parity packets and eliminate + duplicates within a transmission group based on ODATA/RDATA_PKT_SQN + and on OPT_PARITY_GRP if present. + + To solicit on-demand parity packets, a receiver MUST send parity NAKs + upon loss detection. For the purposes of soliciting on-demand + parity, loss detection occurs at transmission group boundaries, i.e. + upon receipt of the last data packet in a transmission group, upon + receipt of any data packet in any subsequent transmission group, or + upon receipt of any parity packet in the current or a subsequent + transmission group. + + A parity NAK is simply a NAK with OPT_PARITY and NAK_PKT_CNT set to + the count of the number of packets detected to be missing from the + transmission group specified by NAK_TG_SQN. Note that this + constrains the receiver to request no more parity packets than there + are data packets in the transmission group. + + A receiver SHOULD bias the value of NAK_BO_IVL for parity NAKs + inversely proportional to NAK_PKT_CNT so that NAKs for larger losses + are likely to be scheduled ahead of NAKs for smaller losses in the + same receiver population. + + A confirming NCF for a parity NAK is a parity NCF with NCF_PKT_CNT + equal to or greater than that specified by the parity NAK. + + A receiver's NAK_RDATA_IVL timer is not cancelled until all requested + parity packets have been received. + + In the absence of data (detected from SPMs bearing SPM_LEAD equal to + RXW_LEAD) on non-transmission-group boundaries, receivers MAY resort + to selective NAKs for any missing packets in that partial + transmission group. + + + + + + +Speakman, et. al. Experimental [Page 67] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + When a receiver handles parity packets belonging to a transmission + group with variable sized packets, (detected from the presence of the + OPT_VAR_PKTLEN option in the parity packets), it MUST decode them as + specified in the overview description and use the decoded TSDU length + to get rid of the padding in the decoded packet. + + If the source was using a variable sized transmission group via the + OPT_CURR_TGSIZE, the receiver might learn this before having + requested (and received) any retransmission. The above happens if it + sees OPT_CURR_TGSIZE in the last data packet of the TG, in any + proactive parity packet or in a SPM. If the receivers learns this + and determines that it has missed one or more packets in the + shortened transmission group, it MAY then NAK for them without + waiting for the start of the next transmission group. Otherwise it + will start NAKing at the start of the next transmission group. + + In both cases, the receiver MUST NAK for the number of packets + missing assuming that the size of the transmission group is the + maximum effective transmission group. In other words, the receivers + cannot exploit the fact that it might already know that the + transmission group was smaller but MUST always NAK for the number of + packets it believes are missing, plus the number of packets required + to bring the total packets up to the maximum effective transmission + group size. + + After the first parity packet has been delivered to the receiver, the + actual TG size is known to him, either because already known or + because discovered via OPT_CURR_TGSIZE contained in the parity + packet. Hence the receiver can decode the whole group as soon as the + minimum number of parity packets needed is received. + +11.6. Procedures - Network Elements + + Pro-active parity packets (ODATA with OPT_PARITY) are switched by + network elements without transport-layer intervention. + + On-demand parity packets (RDATA with OPT_PARITY) necessitate modified + request, confirmation and repair constraint procedures for network + elements. In the context of these procedures, repair state is + maintained per NAK_TSI and NAK_TG_SQN, and in addition to recording + the interfaces on which corresponding NAKs have been received, + records the largest value of NAK_PKT_CNT seen in corresponding NAKs + on each interface. This value is referred to as the known packet + count. The largest of the known packet counts recorded for any + interface in the repair state for the transmit group or carried by an + NCF is referred to as the largest known packet count. + + + + + +Speakman, et. al. Experimental [Page 68] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Upon receipt of a parity NAK, a network element responds with the + corresponding parity NCF. The corresponding parity NCF is just an + NCF formed in the usual way (i.e., a multicast copy of the NAK with + the packet type changed), but with the addition of OPT_PARITY and + with NCF_PKT_CNT set to the larger of NAK_PKT_CNT and the known + packet count for the receiving interface. The network element then + creates repair state in the usual way with the following + modifications. + + If repair state for the receiving interface does not exist, the + network element MUST create it and additionally record NAK_PKT_CNT + from the parity NAK as the known packet count for the receiving + interface. + + If repair state for the receiving interface already exists, the + network element MUST eliminate the NAK only if NAK_ELIM_IVL has not + expired and NAK_PKT_CNT is equal to or less than the largest known + packet count. If NAK_PKT_CNT is greater than the known packet count + for the receiving interface, the network element MUST update the + latter with the larger NAK_PKT_CNT. + + Upon either adding a new interface or updating the known packet count + for an existing interface, the network element MUST determine if + NAK_PKT_CNT is greater than the largest known packet count. If so or + if NAK_ELIM_IVL has expired, the network element MUST forward the + parity NAK in the usual way with a value of NAK_PKT_CNT equal to the + largest known packet count. + + Upon receipt of an on-demand parity packet, a network element MUST + locate existing repair state for the corresponding RDATA_TSI and + RDATA_TG_SQN. If no such repair state exists, the network element + MUST discard the RDATA as usual. + + If corresponding repair state exists, the largest known packet count + MUST be decremented by one, then the network element MUST forward the + RDATA on all interfaces in the existing repair state, and decrement + the known packet count by one for each. Any interfaces whose known + packet count is thereby reduced to zero MUST be deleted from the + repair state. If the number of interfaces is thereby reduced to + zero, the repair state itself MUST be deleted. + + Upon reception of a parity NCF, network elements MUST cancel pending + NAK retransmission only if NCF_PKT_CNT is greater or equal to the + largest known packet count. Network elements MUST use parity NCFs to + anticipate NAKs in the usual way with the addition of recording + NCF_PKT_CNT from the parity NCF as the largest known packet count + with the anticipated state so that any subsequent NAKs received with + NAK_PKT_CNT equal to or less than NCF_PKT_CNT will be eliminated, and + + + +Speakman, et. al. Experimental [Page 69] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + any with NAK_PKT_CNT greater than NCF_PKT_CNT will be forwarded. + Network elements which receive a parity NCF with NCF_PKT_CNT larger + than the largest known packet count MUST also use it to anticipate + NAKs, increasing the largest known packet count to reflect + NCF_PKT_CNT (partial anticipation). + + Parity NNAKs follow the usual elimination procedures with the + exception that NNAKs are eliminated only if existing NAK state has a + NAK_PKT_CNT greater than NNAK_PKT_CNT. + + Network elements must take extra precaution when the source is using + a variable sized transmission group. Network elements learn that the + source is using a TG size smaller than the maximum from + OPT_CURR_TGSIZE in parity RDATAs or in SPMs. When this happens, they + compute a TG size offset as the difference between the maximum TG + size and the actual TG size advertised by OPT_CURR_TGSIZE. Upon + reception of parity RDATA, the TG size offset is used to update the + repair state as follows: + + Any interface whose known packet count is reduced to the TG size + offset is deleted from the repair state. + + This replaces the normal rule for deleting interfaces that applies + when the TG size is equal to the maximum TG size. + +11.7. Procedures - DLRs + + A DLR with the ability to provide FEC repairs MUST indicate this by + setting the OPT_PARITY bit in the redirecting POLR. It MUST then + process any redirected FEC NAKs in the usual way. + +11.8. Packet Formats + +11.8.1. OPT_PARITY_PRM - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| |P O| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Transmission Group Size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x08 + + Option Length = 8 octets + + P-bit (PARITY_PRM_PRO) + + + +Speakman, et. al. Experimental [Page 70] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Indicates when set that the source is providing pro-active parity + packets. + + O-bit (PARITY_PRM_OND) + + Indicates when set that the source is providing on-demand parity + packets. + + At least one of PARITY_PRM_PRO and PARITY_PRM_OND MUST be set. + + Transmission Group Size (PARITY_PRM_TGS) + + The number of data packets in the transmission group over which + the parity packets are calculated. If a variable transmission + group size is being used, then this becomes the maximum effective + transmission group size across the session. + + OPT_PARITY_PRM MAY be appended only to SPMs. + + OPT_PARITY_PRM is network-significant. + +11.8.2. OPT_PARITY_GRP - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Parity Group Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x09 + + Option Length = 8 octets + + Parity Group Number (PRM_GROUP) + + The number of the group of k parity packets amongst the h parity + packets within the transmission group to which the parity packet + belongs, where the first k parity packets are in group zero. + PRM_GROUP MUST NOT be zero. + + OPT_PARITY_GRP MAY be appended only to parity packets. + + OPT_PARITY_GRP is NOT network-significant. + + + + + + +Speakman, et. al. Experimental [Page 71] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +11.8.3. OPT_CURR_TGSIZE - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Actual Transmission Group Size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x0A + + Option Length = 8 octets + + Actual Transmission Group Size (PRM_ATGSIZE) + + The actual number of data packets in this transmission group. + This MUST be less than or equal to the maximum transmission group + size PARITY_PRM_TGS in OPT_PARITY_PRM. + + OPT_CURR_TGSIZE MAY be appended to data and parity packets (ODATA or + RDATA) and to SPMs. + + OPT_CURR_TGSIZE is network-significant except when appended to ODATA. + +12. Appendix B - Support for Congestion Control + +12.1. Introduction + + A source MUST implement strategies for congestion avoidance, aimed at + providing overall network stability, fairness among competing PGM + flows, and some degree of fairness towards coexisting TCP flows [13]. + In order to do this, the source must be provided with feedback on the + status of the network in terms of traffic load. This appendix + specifies NE procedures that provide such feedback to the source in a + scalable way. (An alternative TCP-friendly scheme for congestion + control that does not require NE support can be found in [16]). + + The procedures specified in this section enable the collection and + selective forwarding of three types of feedback to the source: + + o Worst link load as measured in network elements. + + o Worst end-to-end path load as measured in network elements. + + o Worst end-to-end path load as reported by receivers. + + + + + +Speakman, et. al. Experimental [Page 72] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + This specification defines in detail NE procedures, receivers + procedures and packet formats. It also defines basic procedures in + receivers for generating congestion reports. This specification does + not define the procedures used by PGM sources to adapt their + transmission rates in response of congestion reports. Those + procedures depend upon the specific congestion control scheme. + + PGM defines a header option that PGM receivers may append to NAKs + (OPT_CR). OPT_CR carries congestion reports in NAKs that propagate + upstream towards the source. + + During the process of hop-by-hop reverse NAK forwarding, NEs examine + OPT_CR and possibly modify its contents prior to forwarding the NAK + upstream. Forwarding CRs also has the side effect of creating + congestion report state in the NE. The presence of OPT_CR and its + contents also influences the normal NAK suppression rules. Both the + modification performed on the congestion report and the additional + suppression rules depend on the content of the congestion report and + on the congestion report state recorded in the NE as detailed below. + + OPT_CR contains the following fields: + + OPT_CR_NE_WL Reports the load in the worst link as detected though + NE internal measurements + + OPT_CR_NE_WP Reports the load in the worst end-to-end path as + detected though NE internal measurements + + OPT_CR_RX_WP Reports the load in the worst end-to-end path as + detected by receivers + + A load report is either a packet drop rate (as measured at an NE's + interfaces) or a packet loss rate (as measured in receivers). Its + value is linearly encoded in the range 0-0xFFFF, where 0xFFFF + represents a 100% loss/drop rate. Receivers that send a NAK bearing + OPT_CR determine which of the three report fields are being reported. + + OPT_CR also contains the following fields: + + OPT_CR_NEL A bit indicating that OPT_CR_NE_WL is being reported. + + OPT_CR_NEP A bit indicating that OPT_CR_NE_WP is being reported. + + OPT_CR_RXP A bit indicating that OPT_CR_RX_WP is being reported. + + + + + + + +Speakman, et. al. Experimental [Page 73] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + OPT_CR_LEAD A SQN in the ODATA space that serves as a temporal + reference for the load report values. This is + initialized by receivers with the leading edge of the + transmit window as known at the moment of transmitting + the NAK. This value MAY be advanced in NEs that + modify the content of OPT_CR. + + OPT_CR_RCVR The identity of the receiver that generated the worst + OPT_CR_RX_WP. + + The complete format of the option is specified later. + +12.2. NE-Based Worst Link Report + + To permit network elements to report worst link, receivers append + OPT_CR to a NAK with bit OPT_CR_NEL set and OPT_CR_NE_WL set to zero. + NEs receiving NAKs that contain OPT_CR_NE_WL process the option and + update per-TSI state related to it as described below. The ultimate + result of the NEs' actions ensures that when a NAK leaves a sub-tree, + OPT_CR_NE_WL contains a congestion report that reflects the load of + the worst link in that sub-tree. To achieve this, NEs rewrite + OPT_CR_NE_WL with the worst value among the loads measured on the + local (outgoing) links for the session and the congestion reports + received from those links. + + Note that the mechanism described in this sub-section does not permit + the monitoring of the load on (outgoing) links at non-PGM-capable + multicast routers. For this reason, NE-Based Worst Link Reports + SHOULD be used in pure PGM topologies only. Otherwise, this + mechanism might fail in detecting congestion. To overcome this + limitation PGM sources MAY use a heuristic that combines NE-Based + Worst Link Reports and Receiver-Based Reports. + +12.3. NE-Based Worst Path Report + + To permit network elements to report a worst path, receivers append + OPT_CR to a NAK with bit OPT_CR_NEP set and OPT_CR_NE_WP set to zero. + The processing of this field is similar to that of OPT_CR_NE_WL with + the difference that, on the reception of a NAK, the value of + OPT_CR_NE_WP is adjusted with the load measured on the interface on + which the NAK was received according to the following formula: + + OPT_CR_NE_WP = if_load + OPT_CR_NE_WP * (100% - if_loss_rate) + + The worst among the adjusted OPT_CR_NE_WP is then written in the + outgoing NAK. This results in a hop-by-hop accumulation of link loss + rates into a path loss rate. + + + + +Speakman, et. al. Experimental [Page 74] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + As with OPT_CR_NE_WL, the congestion report in OPT_CR_NE_WP may be + invalid if the multicast distribution tree includes non-PGM-capable + routers. + +12.4. Receiver-Based Worst Report + + To report a packet loss rate, receivers append OPT_CR to a NAK with + bit OPT_CR_RXP set and OPT_CR_RX_WP set to the packet loss rate. NEs + receiving NAKs that contain OPT_CR_RX_WP process the option and + update per-TSI state related to it as described below. The ultimate + result of the NEs' actions ensures that when a NAK leaves a sub-tree, + OPT_CR_RX_WP contains a congestion report that reflects the load of + the worst receiver in that sub-tree. To achieve this, NEs rewrite + OTP_CR_RE_WP with the worst value among the congestion reports + received on its outgoing links for the session. In addition to this, + OPT_CR_RCVR MUST contain the NLA of the receiver that originally + measured the value of OTP_CR_RE_WP being forwarded. + +12.5. Procedures - Receivers + + To enable the generation of any type of congestion report, receivers + MUST insert OPT_CR in each NAK they generate and provide the + corresponding field (OPT_CR_NE_WL, OPT_CR_NE_WP, OPT_CR_RX_WP). The + specific fields to be reported will be advertised to receivers in + OPT_CRQST on the session's SPMs. Receivers MUST provide only those + options requested in OPT_CRQST. + + Receivers MUST initialize OPT_CR_NE_WL and OPT_CR_NE_WP to 0 and they + MUST initialize OPT_CR_RCVR to their NLA. At the moment of sending + the NAK, they MUST also initialize OPT_CR_LEAD to the leading edge of + the transmission window. + + Additionally, if a receiver generates a NAK with OPT_CR with + OPT_CR_RX_WP, it MUST initialize OPT_CR_RX_WP to the proper value, + internally computed. + +12.6. Procedures - Network Elements + + Network elements start processing each OPT_CR by selecting a + reference SQN in the ODATA space. The reference SQN selected is the + highest SQN known to the NE. Usually this is OPT_CR_LEAD contained + in the NAK received. + + They use the selected SQN to age the value of load measurement as + follows: + + o locally measured load values (e.g. interface loads) are + considered up-to-date + + + +Speakman, et. al. Experimental [Page 75] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + o load values carried in OPT_CR are considered up-to-date and are + not aged so as to be independent of variance in round-trip + times from the network element to the receivers + + o old load values recorded in the NE are exponentially aged + according to the difference between the selected reference SQN + and the reference SQN associated with the old load value. + + The exponential aging is computed so that a recorded value gets + scaled down by a factor exp(-1/2) each time the expected inter-NAK + time elapses. Hence the aging formula must include the current loss + rate as follows: + + aged_loss_rate = loss_rate * exp( - SQN_difference * loss_rate / + 2) + + Note that the quantity 1/loss_rate is the expected SQN_lag between + two NAKs, hence the formula above can also be read as: + + aged_loss_rate = loss_rate * exp( - 1/2 * SQN_difference / + SQN_lag) + + which equates to (loss_rate * exp(-1/2)) when the SQN_difference is + equal to expected SQN_lag between two NAKs. + + All the subsequent computations refer to the aged load values. + + Network elements process OPT_CR by handling the three possible types + of congestion reports independently. + + For each congestion report in an incoming NAK, a new value is + computed to be used in the outgoing NAK: + + o The new value for OPT_CR_NE_WL is the maximum of the load + measured on the outgoing interfaces for the session, the value + of OPT_CR_NE_WL of the incoming NAK, and the value previously + sent upstream (recorded in the NE). All these values are as + obtained after the aging process. + + o The new value for OPT_CR_NE_WP is the maximum of the value + previously sent upstream (after aging) and the value of + OPT_CR_NE_WP in the incoming NAK adjusted with the load on the + interface upon which the NAK was received (as described above). + + o The new value for OPT_CR_RX_WP is the maximum of the value + previously sent upstream (after aging) and the value of + OPT_CR_RX_WP in the incoming NAK. + + + + +Speakman, et. al. Experimental [Page 76] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + o If OPT_CR_RX_WP was selected from the incoming NAK, the new + value for OPT_CR_RCVR is the one in the incoming NAK. + Otherwise it is the value previously sent upstream. + + o The new value for OPT_CR_LEAD is the reference SQN selected for + the aging procedure. + +12.6.1. Overriding Normal Suppression Rules + + Normal suppression rules hold to determine if a NAK should be + forwarded upstream or not. However if any of the outgoing congestion + reports has changed by more than 5% relative to the one previously + sent upstream, this new NAK is not suppressed. + +12.6.2. Link Load Measurement + + PGM routers monitor the load on all their outgoing links and record + it in the form of per-interface loss rate statistics. "load" MUST be + interpreted as the percentage of the packets meant to be forwarded on + the interface that were dropped. Load statistics refer to the + aggregate traffic on the links and not to PGM traffic only. + + This document does not specify the algorithm to be used to collect + such statistics, but requires that such algorithm provide both + accuracy and responsiveness in the measurement process. As far as + accuracy is concerned, the expected measurement error SHOULD be + upper-limited (e.g. less than than 10%). As far as responsiveness is + concerned, the measured load SHOULD converge to the actual value in a + limited time (e.g. converge to 90% of the actual value in less than + 200 milliseconds), when the instantaneous offered load changes. + Whenever both requirements cannot be met at the same time, accuracy + SHOULD be traded for responsiveness. + + + + + + + + + + + + + + + + + + + +Speakman, et. al. Experimental [Page 77] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +12.7. Packet Formats + +12.7.1. OPT_CR - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| L P R| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Congestion Report Reference SQN | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NE Worst Link | NE Worst Path | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Rcvr Worst Path | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NLA AFI | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Worst Receiver's NLA ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + + Option Type = 0x10 + + Option Length = 20 octets + NLA length + + L OPT_CR_NEL bit : set indicates OPT_CR_NE_WL is being reported + + P OPT_CR_NEP bit : set indicates OPT_CR_NE_WP is being reported + + R OPT_CR_RXP bit : set indicates OPT_CR_RX_WP is being reported + + Congestion Report Reference SQN (OPT_CR_LEAD). + + A SQN in the ODATA space that serves as a temporal reference point + for the load report values. + + NE Worst Link (OPT_CR_NE_WL). + + Reports the load in the worst link as detected though NE internal + measurements + + NE Worst Path (OPT_CR_NE_WP). + + Reports the load in the worst end-to-end path as detected though + NE internal measurements + + + + + + + +Speakman, et. al. Experimental [Page 78] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Rcvr Worst Path (OPT_CR_RX_WP). + + Reports the load in the worst end-to-end path as detected by + receivers + + Worst Receiver's NLA (OPT_CR_RCVR). + + The unicast address of the receiver that generated the worst + OPT_CR_RX_WP. + + OPT_CR MAY be appended only to NAKs. + + OPT-CR is network-significant. + +12.7.2. OPT_CRQST - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| L P R| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x11 + + Option Length = 4 octets + + L OPT_CRQST_NEL bit : set indicates OPT_CR_NE_WL is being + requested + + P OPT_CRQST_NEP bit : set indicates OPT_CR_NE_WP is being + requested + + R OPT_CRQST_RXP bit : set indicates OPT_CR_RX_WP is being + requested + + OPT_CRQST MAY be appended only to SPMs. + + OPT-CRQST is network-significant. + +13. Appendix C - SPM Requests + +13.1. Introduction + + SPM Requests (SPMRs) MAY be used to solicit an SPM from a source in a + non-implosive way. The typical application is for late-joining + receivers to solicit SPMs directly from a source in order to be able + to NAK for missing packets without having to wait for a regularly + scheduled SPM from that source. + + + +Speakman, et. al. Experimental [Page 79] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +13.2. Overview + + Allowing for SPMR implosion protection procedures, a receiver MAY + unicast an SPMR to a source to solicit the most current session, + window, and path state from that source any time after the receiver + has joined the group. A receiver may learn the TSI and source to + which to direct the SPMR from any other PGM packet it receives in the + group, or by any other means such as from local configuration or + directory services. The receiver MUST use the usual SPM procedures + to glean the unicast address to which it should direct its NAKs from + the solicited SPM. + +13.3. Packet Contents + + This section just provides enough short-hand to make the Procedures + intelligible. For the full details of packet contents, please refer + to Packet Formats below. + +13.3.1. SPM Requests + + SPMRs are transmitted by receivers to solicit SPMs from a source. + + SPMs are unicast to a source and contain: + + SPMR_TSI the source-assigned TSI for the session to which the + SPMR corresponds + +13.4. Procedures - Sources + + A source MUST respond immediately to an SPMR with the corresponding + SPM rate limited to once per IHB_MIN per TSI. The corresponding SPM + matches SPM_TSI to SPMR_TSI and SPM_DPORT to SPMR_DPORT. + +13.5. Procedures - Receivers + + To moderate the potentially implosive behavior of SPMRs at least on a + densely populated subnet, receivers MUST use the following back-off + and suppression procedure based on multicasting the SPMR with a TTL + of 1 ahead of and in addition to unicasting the SPMR to the source. + The role of the multicast SPMR is to suppress the transmission of + identical SPMRs from the subnet. + + More specifically, before unicasting a given SPMR, receivers MUST + choose a random delay on SPMR_BO_IVL (~250 msecs) during which they + listen for a multicast of an identical SPMR. If a receiver does not + see a matching multicast SPMR within its chosen random interval, it + MUST first multicast its own SPMR to the group with a TTL of 1 before + then unicasting its own SPMR to the source. If a receiver does see a + + + +Speakman, et. al. Experimental [Page 80] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + matching multicast SPMR within its chosen random interval, it MUST + refrain from unicasting its SPMR and wait instead for the + corresponding SPM. + + In addition, receipt of the corresponding SPM within this random + interval SHOULD cancel transmission of an SPMR. + + In either case, the receiver MUST wait at least SPMR_SPM_IVL before + attempting to repeat the SPMR by choosing another delay on + SPMR_BO_IVL and repeating the procedure above. + + The corresponding SPMR matches SPMR_TSI to SPMR_TSI and SPMR_DPORT to + SPMR_DPORT. The corresponding SPM matches SPM_TSI to SPMR_TSI and + SPM_DPORT to SPMR_DPORT. + +13.6. SPM Requests + + SPMR: + + SPM Requests are sent by receivers to request the immediate + transmission of an SPM for the given TSI from a source. + + The network-header source address of an SPMR is the unicast NLA of + the entity that originates the SPMR. + + The network-header destination address of an SPMR is the unicast NLA + of the source from which the corresponding SPM is requested. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Port | Destination Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Options | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Global Source ID ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ... Global Source ID | TSDU Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Extensions when present ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... + + Source Port: + + SPMR_SPORT + + Data-Destination Port + + + + +Speakman, et. al. Experimental [Page 81] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Destination Port: + + SPMR_DPORT + + Data-Source Port, together with Global Source ID forms SPMR_TSI + + Type: + + SPMR_TYPE = 0x0C + + Global Source ID: + + SPMR_GSI + + Together with Source Port forms + + SPMR_TSI + +14. Appendix D - Poll Mechanism + +14.1. Introduction + + These procedures provide PGM network elements and sources with the + ability to poll their downstream PGM neighbors to solicit replies + in an implosion-controlled way. + + Both general polls and specific polls are possible. The former + provide a PGM (parent) node with a way to check if there are any + PGM (children) nodes connected to it, both network elements and + receivers, and to estimate their number. The latter may be used + by PGM parent nodes to search for nodes with specific properties + among its PGM children. An example of application for this is DLR + discovery. + + Polling is implemented using two additional PGM packets: + + POLL a Poll Request that PGM parent nodes multicast to the group to + perform the poll. Similarly to NCFs, POLL packets stop at the + first PGM node they reach, as they are not forwarded by PGM + network elements. + + POLR a Poll Response that PGM children nodes (either network elements + or receivers) use to reply to a Poll Request by addressing it + to the NLA of the interface from which the triggering POLL was + sent. + + + + + + +Speakman, et. al. Experimental [Page 82] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + The polling mechanism dictates that PGM children nodes that receive a + POLL packet reply to it only if certain conditions are satisfied and + ignore the POLL otherwise. Two types of condition are possible: a + random condition that defines a probability of replying for the + polled child, and a deterministic condition. Both the random + condition and the deterministic condition are controlled by the + polling PGM parent node by specifying the probability of replying and + defining the deterministic condition(s) respectively. Random-only + poll, deterministic-only poll or a combination of the two are + possible. + + The random condition in polls allows the prevention of implosion of + replies by controlling their number. Given a probability of replying + P and assuming that each receiver makes an independent decision, the + number of expected replies to a poll is P*N where N is the number of + PGM children relative to the polling PGM parent. The polling node + can control the number of expected replies by specifying P in the + POLL packet. + +14.2. Packet Contents + + This section just provides enough short-hand to make the Procedures + intelligible. For the full details of packet contents, please refer + to Packet Formats below. + +14.2.1. POLL (Poll Request) + + POLL_SQN a sequence number assigned sequentially by the polling + parent in unit increments and scoped by POLL_PATH and + the TSI of the session. + + POLL_ROUND a poll round sequence number. Multiple poll rounds + are possible within a POLL_SQN. + + POLL_S_TYPE the sub-type of the poll request + + POLL_PATH the network-layer address (NLA) of the interface on + the PGM network element or source on which the POLL is + transmitted + + POLL_BO_IVL the back-off interval that MUST be used to compute the + random back-off time to wait before sending the + response to a poll. POLL_BO_IVL is expressed in + microseconds. + + POLL_RAND a random string used to implement the randomness in + replying + + + + +Speakman, et. al. Experimental [Page 83] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + POLL_MASK a bit-mask used to determine the probability of random + replies + + Poll request MAY also contain options which specify deterministic + conditions for the reply. No options are currently defined. + +14.2.2. POLR (Poll Response) + + POLR_SQN POLL_SQN of the poll request for which this is a reply + + POLR_ROUND POLL_ROUND of the poll request for which this is a + reply + + Poll response MAY also contain options. No options are currently + defined. + +14.3. Procedures - General + +14.3.1. General Polls + + General Polls may be used to check for and count PGM children that + are 1 PGM hop downstream of an interface of a given node. They have + POLL_S_TYPE equal to PGM_POLL_GENERAL. PGM children that receive a + general poll decide whether to reply to it only based on the random + condition present in the POLL. + + To prevent response implosion, PGM parents that initiate a general + poll SHOULD establish the probability of replying to the poll, P, so + that the expected number of replies is contained. The expected + number of replies is N * P, where N is the number of children. To be + able to compute this number, PGM parents SHOULD already have a rough + estimate of the number of children. If they do not have a recent + estimate of this number, they SHOULD send the first poll with a very + low probability of replying and increase it in subsequent polls in + order to get the desired number of replies. + + To prevent poll-response implosion caused by a sudden increase in the + children population occurring between two consecutive polls with + increasing probability of replying, PGM parents SHOULD use poll + rounds. Poll rounds allow PGM parents to "freeze" the size of the + children population when they start a poll and to maintain it + constant across multiple polls (with the same POLL_SQN but different + POLL_ROUND). This works by allowing PGM children to respond to a + poll only if its POLL_ROUND is zero or if they have previously + received a poll with the same POLL_SQN and POLL_ROUND equal to zero. + + + + + + +Speakman, et. al. Experimental [Page 84] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + In addition to this PGM children MUST observe a random back-off in + replying to a poll. This spreads out the replies in time and allows + a PGM parent to abort the poll if too many replies are being + received. To abort an ongoing poll a PGM parent MUST initiate + another poll with different POLL_SQN. PGM children that receive a + POLL MUST cancel any pending reply for POLLs with POLL_SQN different + from the one of the last POLL received. + + For a given poll with probability of replying P, a PGM parent + estimates the number of children as M / P, where M is the number of + responses received. PGM parents SHOULD keep polling periodically and + use some average of the result of recent polls as their estimate for + the number of children. + +14.3.2. Specific Polls + + Specific polls provide a way to search for PGM children that comply + to specific requisites. As an example specific poll could be used to + search for down-stream DLRs. A specific poll is characterized by a + POLL_S_TYPE different from PGM_POLL_GENERAL. PGM children decide + whether to reply to a specific poll or not based on the POLL_S_TYPE, + on the random condition and on options possibly present in the POLL. + The way options should be interpreted is defined by POLL_S_TYPE. The + random condition MUST be interpreted as an additional condition to be + satisfied. To disable the random condition PGM parents MUST specify + a probability of replying P equal to 1. + + PGM children MUST ignore a POLL packet if they do not understand + POLL_S_TYPE. Some specific POLL_S_TYPE may also require that the + children ignore a POLL if they do not fully understand all the PGM + options present in the packet. + +14.4. Procedures - PGM Parents (Sources or Network Elements) + + A PGM parent (source or network element), that wants to poll the + first PGM-hop children connected to one of its outgoing interfaces + MUST send a POLL packet on that interface with: + + POLL_SQN equal to POLL_SQN of the last POLL sent incremented by + one. If poll rounds are used, this must be equal to + POLL_SQN of the last group of rounds incremented by + one. + + POLL_ROUND The round of the poll. If the poll has a single + round, this must be zero. If the poll has multiple + rounds, this must be one plus the last POLL_ROUND for + the same POLL_SQN, or zero if this is the first round + within this POLL_SQN. + + + +Speakman, et. al. Experimental [Page 85] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + POLL_S_TYPE the type of the poll. For general poll use + PGM_POLL_GENERAL + + POLL_PATH set to the NLA of the outgoing interface + + POLL_BO_IVL set to the wanted reply back-off interval. As far as + the choice of this is concerned, using NAK_BO_IVL is + usually a conservative option, however a smaller value + MAY be used, if the number of expected replies can be + determined with a good confidence or if a + conservatively low probability of reply (P) is being + used (see POLL_MASK next). When the number of + expected replies is unknown, a large POLL_BO_IVL + SHOULD be used, so that the poll can be effectively + aborted if the number of replies being received is too + large. + + POLL_RAND MUST be a random string re-computed each time a new + poll is sent on a given interface + + POLL_MASK determines the probability of replying, P, according + to the relationship P = 1 / ( 2 ^ B ), where B is the + number of bits set in POLL_MASK [15]. If this is a + deterministic poll, B MUST be 0, i.e. POLL_MASK MUST + be a all-zeroes bit-mask. + + Nota Bene: POLLs transmitted by network elements MUST bear the + ODATA source's network-header source address, not the network + element's NLA. POLLs MUST also be transmitted with the IP + + Router Alert Option [6], to be allow PGM network element to + intercept them. + + A PGM parent that has started a poll by sending a POLL packet SHOULD + wait at least POLL_BO_IVL before starting another poll. During this + interval it SHOULD collect all the valid response (the one with + POLR_SQN and POLR_ROUND matching with the outstanding poll) and + process them at the end of the collection interval. + + A PGM parent SHOULD observe the rules mentioned in the description of + general procedures, to prevent implosion of response. These rules + should in general be observed both for generic polls and specific + polls. The latter however can be performed using deterministic poll + (with no implosion prevention) if the expected number of replies is + known to be small. A PGM parent that issue a generic poll with the + intent of estimating the children population size SHOULD use poll + rounds to "freeze" the children that are involved in the measure + process. This allows the sender to "open the door wider" across + + + +Speakman, et. al. Experimental [Page 86] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + subsequent rounds (by increasing the probability of response), + without fear of being flooded by late joiners. Note the use of + rounds has the drawback of introducing additional delay in the + estimate of the population size, as the estimate obtained at the end + of a round-group refers to the condition present at the time of the + first round. + + A PGM parent that has started a poll SHOULD monitor the number of + replies during the collection phase. If this become too large, the + PGM parent SHOULD abort the poll by immediately starting a new poll + (different POLL_SQN) and specifying a very low probability of + replying. + + + When polling is being used to estimate the receiver population for + the purpose of calculating NAK_BO_IVL, OPT_NAK_BO_IVL (see 16.4.1 + below) MUST be appended to SPMs, MAY be appended to NCFs and POLLs, + and in all cases MUST have NAK_BO_IVL_SQN set to POLL_SQN of the most + recent complete round of polls, and MUST bear that round's + corresponding derived value of NAK_BAK_IVL. In this way, + OPT_NAK_BO_IVL provides a current value for NAK_BO_IVL at the same + time as information is being gathered for the calculation of a future + value of NAK_BO_IVL. + +14.5. Procedures - PGM Children (Receivers or Network Elements) + + PGM receivers and network elements MUST compute a 32-bit random node + identifier (RAND_NODE_ID) at startup time. When a PGM child + (receiver or network element) receives a POLL it MUST use its + RAND_NODE_ID to match POLL_RAND of incoming POLLs. The match is + limited to the bits specified by POLL_MASK. If the incoming POLL + contain a POLL_MASK made of all zeroes, the match is successful + despite the content of POLL_RAND (deterministic reply). If the match + fails, then the receiver or network element MUST discard the POLL + without any further action, otherwise it MUST check the fields + POLL_ROUND, POLL_S_TYPE and any PGM option included in the POLL to + determine whether it SHOULD reply to the poll. + + If POLL_ROUND is non-zero and the PGM receiver has not received a + previous poll with the same POLL_SQN and a zero POLL_ROUND, it MUST + discard the poll without further action. + + If POLL_S_TYPE is equal to PGM_POLL_GENERAL, the PGM child MUST + schedule a reply to the POLL despite the presence of PGM options on + the POLL packet. + + + + + + +Speakman, et. al. Experimental [Page 87] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + If POLL_S_TYPE is different from PGM_POLL_GENERAL, the decision on + whether a reply should be scheduled depends on the actual type and on + the options possibly present in the POLL. + + If POLL_S_TYPE is unknown to the recipient of the POLL, it MUST NOT + reply and ignore the poll. Currently the only POLL_S_TYPE defined + are PGM_POLL_GENERAL and PGM_POLL_DLR. + + If a PGM receiver or network element has decided to reply to a POLL, + it MUST schedule the transmission of a single POLR at a random time + in the future. The random delay is chosen in the interval [0, + POLL_BO_IVL]. POLL_BO_IVL is the one contained in the POLL received. + When this timer expires, it MUST send a POLR using POLL_PATH of the + received POLL as destination address. POLR_SQN MUST be equal to + POLL_SQN and POLR_ROUND must be equal to POLL_ROUND. The POLR MAY + contain PGM options according to the semantic of POLL_S_TYPE or the + semantic of PGM options possibly present in the POLL. If POLL_S_TYPE + is PGM_POLL_GENERAL no option is REQUIRED. + + A PGM receiver or network element MUST cancel any pending + transmission of POLRs if a new POLL is received with POLL_SQN + different from POLR_SQN of the poll that scheduled POLRs. + +14.6. Constant Definition + + The POLL_S_TYPE values currently defined are: + + PGM_POLL_GENERAL 0 + + PGM_POLL_DLR 1 + +14.7. Packet Formats + + The packet formats described in this section are transport-layer + headers that MUST immediately follow the network-layer header in the + packet. + + The descriptions of Data-Source Port, Data-Destination Port, Options, + Checksum, Global Source ID (GSI), and TSDU Length are those provided + in Section 8. + +14.7.1. Poll Request + + POLL are sent by PGM parents (sources or network elements) to + initiate a poll among their first PGM-hop children. + + + + + + +Speakman, et. al. Experimental [Page 88] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + POLLs are sent to the ODATA multicast group. The network-header + source address of a POLL is the ODATA source's NLA. POLL MUST be + transmitted with the IP Router Alert Option. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Port | Destination Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Options | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Global Source ID ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ... Global Source ID | TSDU Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | POLL's Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | POLL's Round | POLL's Sub-type | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NLA AFI | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Path NLA ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + | POLL's Back-off Interval | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Random String | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Matching Bit-Mask | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Extensions when present ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Source Port: + + POLL_SPORT + + Data-Source Port, together with POLL_GSI forms POLL_TSI + + Destination Port: + + POLL_DPORT + + Data-Destination Port + + Type: + + POLL_TYPE = 0x01 + + + + +Speakman, et. al. Experimental [Page 89] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Global Source ID: + + POLL_GSI + + Together with POLL_SPORT forms POLL_TSI + + POLL's Sequence Number + + POLL_SQN + + The sequence number assigned to the POLL by the originator. + + POLL's Round + + POLL_ROUND + + The round number within the poll sequence number. + + POLL's Sub-type + + POLL_S_TYPE + + The sub-type of the poll request. + + Path NLA: + + POLL_PATH + + The NLA of the interface on the source or network element on which + this POLL was forwarded. + + POLL's Back-off Interval + + POLL_BO_IVL + + The back-off interval used to compute a random back-off for the + reply, expressed in microseconds. + + Random String + + POLL_RAND + + A random string used to implement the random condition in + replying. + + + + + + + +Speakman, et. al. Experimental [Page 90] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Matching Bit-Mask + + POLL_MASK + + A bit-mask used to determine the probability of random replies. + +14.7.2. Poll Response + + POLR are sent by PGM children (receivers or network elements) to + reply to a POLL. + + The network-header source address of a POLR is the unicast NLA of the + entity that originates the POLR. The network-header destination + address of a POLR is initialized by the originator of the POLL to the + unicast NLA of the upstream PGM element (source or network element) + known from the POLL that triggered the POLR. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Port | Destination Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Options | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Global Source ID ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ... Global Source ID | TSDU Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | POLR's Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | POLR's Round | reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Option Extensions when present ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Source Port: + + POLR_SPORT + + Data-Destination Port + + Destination Port: + + POLR_DPORT + + Data-Source Port, together with Global Source ID forms POLR_TSI + + + + + +Speakman, et. al. Experimental [Page 91] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Type: + + POLR_TYPE = 0x02 + + Global Source ID: + + POLR_GSI + + Together with POLR_DPORT forms POLR_TSI + + POLR's Sequence Number + + POLR_SQN + + The sequence number (POLL_SQN) of the POLL packet for which this + is a reply. + + POLR's Round + + POLR_ROUND + + The round number (POLL_ROUND) of the POLL packet for which this is + a reply. + +15. Appendix E - Implosion Prevention + +15.1. Introduction + + These procedures are intended to prevent NAK implosion and to limit + its extent in case of the loss of all or part of the suppressing + multicast distribution tree. They also provide a means to adaptively + tune the NAK back-off interval, NAK_BO_IVL. + + The PGM virtual topology is established and refreshed by SPMs. + Between one SPM and the next, PGM nodes may have an out-of-date view + of the PGM topology due to multicast routing changes, flapping, or a + link/router failure. If any of the above happens relative to a PGM + parent node, a potential NAK implosion problem arises because the + parent node is unable to suppress the generation of duplicate NAKs as + it cannot reach its children using NCFs. The procedures described + below introduce an alternative way of performing suppression in this + case. They also attempt to prevent implosion by adaptively tuning + NAK_BO_IVL. + + + + + + + + +Speakman, et. al. Experimental [Page 92] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +15.2. Tuning NAK_BO_IVL + + Sources and network elements continuously monitor the number of + duplicated NAKs received and use this observation to tune the NAK + back-off interval (NAK_BO_IVL) for the first PGM-hop receivers + connected to them. Receivers learn the current value of NAK_BO_IVL + through OPT_NAK_BO_IVL appended to NCFs or SPMs. + +15.2.1. Procedures - Sources and Network Elements + + For each TSI, sources and network elements advertise the value of + NAK_BO_IVL that their first PGM-hop receivers should use. They + advertise a separate value on all the outgoing interfaces for the TSI + and keep track of the last values advertised. + + For each interface and TSI, sources and network elements count the + number of NAKs received for a specific repair state (i.e., per + sequence number per TSI) from the time the interface was first added + to the repair state list until the time the repair state is + discarded. Then they use this number to tune the current value of + NAK_BO_IVL as follows: + + Increase the current value NAK_BO_IVL when the first duplicate NAK + is received for a given SQN on a particular interface. + + Decrease the value of NAK_BO_IVL if no duplicate NAKs are received on + a particular interface for the last NAK_PROBE_NUM measurements where + each measurement corresponds to the creation of a new repair state. + + An upper and lower limit are defined for the possible value of + NAK_BO_IVL at any time. These are NAK_BO_IVL_MAX and NAK_BO_IVL_MIN + respectively. The initial value that should be used as a starting + point to tune NAK_BO_IVL is NAK_BO_IVL_DEFAULT. The policies + RECOMMENDED for increasing and decreasing NAK_BO_IVL are multiplying + by two and dividing by two respectively. + + Sources and network elements advertise the current value of + NAK_BO_IVL through the OPT_NAK_BO_IVL that they append to NCFs. They + MAY also append OPT_NAK_BO_IVL to outgoing SPMs. + + In order to avoid forwarding the NAK_BO_IVL advertised by the parent, + network elements must be able to recognize OPT_NAK_BO_IVL. Network + elements that receive SPMs containing OPT_NAK_BO_IVL MUST either + remove the option or over-write its content (NAK_BO_IVL) with the + current value of NAK_BO_IVL for the outgoing interface(s), before + forwarding the SPMs. + + + + + +Speakman, et. al. Experimental [Page 93] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Sources MAY advertise the value of NAK_BO_IVL_MAX and NAK_BO_IVL_MIN + to the session by appending a OPT_NAK_BO_RNG to SPMs. + +15.2.2. Procedures - Receivers + + Receivers learn the value of NAK_BO_IVL to use through the option + OPT_NAK_BO_IVL, when this is present in NCFs or SPMs. A value for + NAK_BO_IVL learned from OPT_NAK_BO_IVL MUST NOT be used by a receiver + unless either NAK_BO_IVL_SQN is zero, or the receiver has seen + POLL_RND == 0 for POLL_SQN =< NAK_BO_IVL_SQN within half the sequence + number space. The initial value of NAK_BO_IVL is set to + NAK_BO_IVL_DEFAULT. + + Receivers that receive an SPM containing OPT_NAK_BO_RNG MUST use its + content to set the local values of NAK_BO_IVL_MAX and NAK_BO_IVL_MIN. + +15.2.3. Adjusting NAK_BO_IVL in the absence of NAKs + + Monitoring the number of duplicate NAKs provides a means to track + indirectly the change in the size of first PGM-hop receiver + population and adjust NAK_BO_IVL accordingly. Note that the number + of duplicate NAKs for a given SQN is related to the number of first + PGM-hop children that scheduled (or forwarded) a NAK and not to the + absolute number of first PGM-hop children. This mechanism, however, + does not work in the absence of packet loss, hence a large number of + duplicate NAKs is possible after a period without NAKs, if many new + receivers have joined the session in the meanwhile. To address this + issue, PGM Sources and network elements SHOULD periodically poll the + number of first PGM-hop children using the "general poll" procedures + described in Appendix D. If the result of the polls shows that the + population size has increased significantly during a period without + NAKs, they SHOULD increase NAK_BO_IVL as a safety measure. + +15.3. Containing Implosion in the Presence of Network Failures + +15.3.1. Detecting Network Failures + + In some cases PGM (parent) network elements can promptly detect the + loss of all or part of the suppressing multicast distribution tree + (due to network failures or route changes) by checking their + multicast connectivity, when they receive NAKs. In some other cases + this is not possible as the connectivity problem might occur at some + other non-PGM node downstream or might take time to reflect in the + multicast routing table. To address these latter cases, PGM uses a + simple heuristic: a failure is assumed for a TSI when the count of + duplicated NAKs received for a repair state reaches the value + DUP_NAK_MAX in one of the interfaces. + + + + +Speakman, et. al. Experimental [Page 94] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +15.3.2. Containing Implosion + + When a PGM source or network element detects or assumes a failure for + which it looses multicast connectivity to down-stream PGM agents + (either receivers or other network elements), it sends unicast NCFs + to them in response to NAKs. Downstream PGM network elements which + receive unicast NCFs and have multicast connectivity to the multicast + session send special SPMs to prevent further NAKs until a regular SPM + sent by the source refreshes the PGM tree. + + Procedures - Sources and Network Elements + + PGM sources or network elements which detect or assume a failure that + prevents them from reaching down-stream PGM agents through multicast + NCFs revert to confirming NAKs through unicast NCFs for a given TSI + on a given interface. If the PGM agent is the source itself, than it + MUST generate an SPM for the TSI, in addition to sending the unicast + NCF. + + Network elements MUST keep using unicast NCFs until they receive a + regular SPM from the source. + + When a unicast NCF is sent for the reasons described above, it MUST + contain the OPT_NBR_UNREACH option and the OPT_PATH_NLA option. + OPT_NBR_UNREACH indicates that the sender is unable to use multicast + to reach downstream PGM agents. OPT_PATH_NLA carries the network + layer address of the NCF sender, namely the NLA of the interface + leading to the unreachable subtree. + + When a PGM network element receives an NCF containing the + OPT_NBR_UNREACH option, it MUST ignore it if OPT_PATH_NLA specifies + an upstream neighbour different from the one currently known to be + the upstream neighbor for the TSI. Assuming the network element + matches the OPT_PATH_NLA of the upstream neighbour address, it MUST + stop forwarding NAKs for the TSI until it receives a regular SPM for + the TSI. In addition, it MUST also generate a special SPM to prevent + downstream receivers from sending more NAKs. This special SPM MUST + contain the OPT_NBR_UNREACH option and SHOULD have a SPM_SQN equal to + SPM_SQN of the last regular SPM forwarded. The OPT_NBR_UNREACH + option invalidates the windowing information in SPMs (SPM_TRAIL and + SPM_LEAD). The PGM network element that adds the OPT_NBR_UNREACH + option SHOULD invalidate the windowing information by setting + SPM_TRAIL to 0 and SPM_LEAD to 0x80000000. + + PGM network elements which receive an SPM containing the + OPT_NBR_UNREACH option and whose SPM_PATH matches the currently known + PGM parent, MUST forward them in the normal way and MUST stop + + + + +Speakman, et. al. Experimental [Page 95] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + forwarding NAKs for the TSI until they receive a regular SPM for the + TSI. If the SPM_PATH does not match the currently known PGM parent, + the SPM containing the OPT_NBR_UNREACH option MUST be ignored. + + Procedures - Receivers + + PGM receivers which receive either an NCF or an SPM containing the + OPT_NBR_UNREACH option MUST stop sending NAKs until a regular SPM is + received for the TSI. + + On reception of a unicast NCF containing the OPT_NBR_UNREACH option + receivers MUST generate a multicast copy of the packet with TTL set + to one on the RPF interface for the data source. This will prevent + other receivers in the same subnet from generating NAKs. + + Receivers MUST ignore windowing information in SPMs which contain the + OPT_NBR_UNREACH option. + + Receivers MUST ignore NCFs containing the OPT_NBR_UNREACH option if + the OPT_PATH_NLA specifies a neighbour different than the one + currently know to be the PGM parent neighbour. Similarly receivers + MUST ignore SPMs containing the OPT_NBR_UNREACH option if SPM_PATH + does not match the current PGM parent. + +15.4. Packet Formats + +15.4.1. OPT_NAK_BO_IVL - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NAK Back-Off Interval | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NAK Back-Off Interval SQN | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x04 + + NAK Back-Off Interval + + The value of NAK-generation Back-Off Interval in microseconds. + + + + + + + + +Speakman, et. al. Experimental [Page 96] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + NAK Back-Off Interval Sequence Number + + The POLL_SQN to which this value of NAK_BO_IVL corresponds. Zero + is reserved and means NAK_BO_IVL is NOT being determined through + polling (see Appendix D) and may be used immediately. Otherwise, + NAK_BO_IVL MUST NOT be used unless the receiver has also seen + POLL_ROUND = 0 for POLL_SQN =< NAK_BO_IVL_SQN within half the + sequence number space. + + OPT_NAK_BO_IVL MAY be appended to NCFs, SPMs, or POLLs. + + OPT_NAK_BO_IVL is network-significant. + +15.4.2. OPT_NAK_BO_RNG - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Maximum NAK Back-Off Interval | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Minimum NAK Back-Off Interval | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x05 + + Maximum NAK Back-Off Interval + + The maximum value of NAK-generation Back-Off Interval in + microseconds. + + Minimum NAK Back-Off Interval + + The minimum value of NAK-generation Back-Off Interval in + microseconds. + + OPT_NAK_BO_RNG MAY be appended to SPMs. + + OPT_NAK_BO_RNG is network-significant. + +15.4.3. OPT_NBR_UNREACH - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +Speakman, et. al. Experimental [Page 97] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Option Type = 0x0B + + When present in SPMs, it invalidates the windowing information. + + OPT_NBR_UNREACH MAY be appended to SPMs and NCFs. + + OPT_NBR_UNREACH is network-significant. + +15.4.4. OPT_PATH_NLA - Packet Extension Format + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |E| Option Type | Option Length |Reserved |F|OPX|U| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Path NLA | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Option Type = 0x0C + + Path NLA + + The NLA of the interface on the originating PGM network element + that it uses to send multicast SPMs to the recipient of the packet + containing this option. + + OPT_PATH_NLA MAY be appended to NCFs. + + OPT_PATH_NLA is network-significant. + +16. Appendix F - Transmit Window Example + + Nota Bene: The concept of and all references to the increment + window (TXW_INC) and the window increment (TXW_ADV_SECS) + throughout this document are for illustrative purposes only. They + provide the shorthand with which to describe the concept of + advancing the transmit window without also implying any particular + implementation or policy of advancement. + + The size of the transmit window in seconds is simply TXW_SECS. The + size of the transmit window in bytes (TXW_BYTES) is (TXW_MAX_RTE * + TXW_SECS). The size of the transmit window in sequence numbers + (TXW_SQNS) is (TXW_BYTES / bytes-per-packet). + + The fraction of the transmit window size (in seconds of data) by + which the transmit window is advanced (TXW_ADV_SECS) is called the + window increment. The trailing (oldest) such fraction of the + transmit window itself is called the increment window. + + + +Speakman, et. al. Experimental [Page 98] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + In terms of sequence numbers, the increment window is the range of + sequence numbers that will be the first to be expired from the + transmit window. The trailing (or left) edge of the increment window + is just TXW_TRAIL, the trailing (or left) edge of the transmit + window. The leading (or right) edge of the increment window + (TXW_INC) is defined as one less than the sequence number of the + first data packet transmitted by the source TXW_ADV_SECS after + transmitting TXW_TRAIL. + + A data packet is described as being "in" the transmit or increment + window, respectively, if its sequence number is in the range defined + by the transmit or increment window, respectively. + + The transmit window is advanced across the increment window by the + source when it increments TXW_TRAIL to TXW_INC. When the transmit + window is advanced across the increment window, the increment window + is emptied (i.e., TXW_TRAIL is momentarily equal to TXW_INC), begins + to refill immediately as transmission proceeds, is full again + TXW_ADV_SECS later (i.e., TXW_TRAIL is separated from TXW_INC by + TXW_ADV_SECS of data), at which point the transmit window is advanced + again, and so on. + +16.1. Advancing across the Increment Window + + In anticipation of advancing the transmit window, the source starts a + timer TXW_ADV_IVL_TMR which runs for time period TXW_ADV_IVL. + TXW_ADV_IVL has a value in the range (0, TXW_ADV_SECS). The value + MAY be configurable or MAY be determined statically by the strategy + used for advancing the transmit window. + + When TXW_ADV_IVL_TMR is running, a source MAY reset TXW_ADV_IVL_TMR + if NAKs are received for packets in the increment window. In + addition, a source MAY transmit RDATA in the increment window with + priority over other data within the transmit window. + + When TXW_ADV_IVL_TMR expires, a source SHOULD advance the trailing + edge of the transmit window from TXW_TRAIL to TXW_INC. + + Once the transmit window is advanced across the increment window, + SPM_TRAIL, OD_TRAIL and RD_TRAIL are set to the new value of + TXW_TRAIL in all subsequent transmitted packets, until the next + window advancement. + + PGM does not constrain the strategies that a source may use for + advancing the transmit window. The source MAY implement any scheme + or number of schemes. Three suggested strategies are outlined here. + + + + + +Speakman, et. al. Experimental [Page 99] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Consider the following example: + + Assuming a constant transmit rate of 128kbps and a constant data + packet size of 1500 bytes, if a source maintains the past 30 + seconds of data for repair and increments its transmit window in 5 + second increments, then + + TXW_MAX_RTE = 16kBps + TXW_ADV_SECS = 5 seconds, + TXW_SECS = 35 seconds, + TXW_BYTES = 560kB, + TXW_SQNS = 383 (rounded up), + + and the size of the increment window in sequence numbers + (TXW_MAX_RTE * TXW_ADV_SECS / 1500) = 54 (rounded down). + + Continuing this example, the following is a diagram of the transmit + window and the increment window therein in terms of sequence numbers. + + + TXW_TRAIL TXW_LEAD + | | + | | + |--|--------------- Transmit Window -------------|----| + v | | v + v v + n-1 | n | n+1 | ... | n+53 | n+54 | ... | n+381 | n+382 | n+383 + ^ + ^ | ^ + |--- Increment Window|---| + | + | + TXW_INC + + So the values of the sequence numbers defining these windows are: + + TXW_TRAIL = n + TXW_INC = n+53 + TXW_LEAD = n+382 + + Nota Bene: In this example the window sizes in terms of sequence + numbers can be determined only because of the assumption of a + constant data packet size of 1500 bytes. When the data packet + sizes are variable, more or fewer sequence numbers MAY be consumed + transmitting the same amount (TXW_BYTES) of data. + + So, for a given transport session identified by a TSI, a source + maintains: + + + +Speakman, et. al. Experimental [Page 100] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + TXW_MAX_RTE a maximum transmit rate in kBytes per second, the + cumulative transmit rate of some combination of SPMs, + ODATA, and RDATA depending on the transmit window + advancement strategy + + TXW_TRAIL the sequence number defining the trailing edge of the + transmit window, the sequence number of the oldest + data packet available for repair + + TXW_LEAD the sequence number defining the leading edge of the + transmit window, the sequence number of the most + recently transmitted ODATA packet + + TXW_INC the sequence number defining the leading edge of the + increment window, the sequence number of the most + recently transmitted data packet amongst those that + will expire upon the next increment of the transmit + window + + PGM does not constrain the strategies that a source may use for + advancing the transmit window. A source MAY implement any scheme or + number of schemes. This is possible because a PGM receiver must obey + the window provided by the source in its packets. Three strategies + are suggested within this document. + + In the first, called "Advance with Time", the transmit window + maintains the last TXW_SECS of data in real-time, regardless of + whether any data was sent in that real time period or not. The + actual number of bytes maintained at any instant in time will vary + between 0 and TXW_BYTES, depending on traffic during the last + TXW_SECS. In this case, TXW_MAX_RTE is the cumulative transmit rate + of SPMs and ODATA. + + In the second, called "Advance with Data", the transmit window + maintains the last TXW_BYTES bytes of data for repair. That is, it + maintains the theoretical maximum amount of data that could be + transmitted in the time period TXW_SECS, regardless of when they were + transmitted. In this case, TXW_MAX_RTE is the cumulative transmit + rate of SPMs, ODATA, and RDATA. + + The third strategy leaves control of the window in the hands of the + application. The API provided by a source implementation for this, + could allow the application to control the window in terms of APDUs + and to manually step the window. This gives a form of Application + Level Framing (ALF). In this case, TXW_MAX_RTE is the cumulative + transmit rate of SPMs, ODATA, and RDATA. + + + + + +Speakman, et. al. Experimental [Page 101] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +16.2. Advancing with Data + + In the first strategy, TXW_MAX_RTE is calculated from SPMs and both + ODATA and RDATA, and NAKs reset TXW_ADV_IVL_TMR. In this mode of + operation the transmit window maintains the last TXW_BYTES bytes of + data for repair. That is, it maintains the theoretical maximum + amount of data that could be transmitted in the time period TXW_SECS. + This means that the following timers are not treated as real-time + timers, instead they are "data driven". That is, they expire when + the amount of data that could be sent in the time period they define + is sent. They are the SPM ambient time interval, TXW_ADV_SECS, + TXW_SECS, TXW_ADV_IVL, TXW_ADV_IVL_TMR and the join interval. Note + that the SPM heartbeat timers still run in real-time. + + While TXW_ADV_IVL_TMR is running, a source uses the receipt of a NAK + for ODATA within the increment window to reset timer TXW_ADV_IVL_TMR + to TXW_ADV_IVL so that transmit window advancement is delayed until + no NAKs for data in the increment window are seen for TXW_ADV_IVL + seconds. If the transmit window should fill in the meantime, further + transmissions would be suspended until the transmit window can be + advanced. + + A source MUST advance the transmit window across the increment window + only upon expiry of TXW_ADV_IVL_TMR. + + This mode of operation is intended for non-real-time, messaging + applications based on the receipt of complete data at the expense of + delay. + +16.3. Advancing with Time + + This strategy advances the transmit window in real-time. In this + mode of operation, TXW_MAX_RTE is calculated from SPMs and ODATA only + to maintain a constant data throughput rate by consuming extra + bandwidth for repairs. TXW_ADV_IVL has the value 0 which advances + the transmit window without regard for whether NAKs for data in the + increment window are still being received. + + In this mode of operation, all timers are treated as real-time + timers. + + This mode of operation is intended for real-time, streaming + applications based on the receipt of timely data at the expense of + completeness. + + + + + + + +Speakman, et. al. Experimental [Page 102] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +16.4. Advancing under explicit application control + + Some applications may wish more explicit control of the transmit + window than that provided by the advance with data / time strategies + above. An implementation MAY provide this mode of operation and + allow an application to explicitly control the window in terms of + APDUs. + +17. Appendix G - Applicability Statement + + As stated in the introduction, PGM has been designed with a specific + class of applications in mind in recognition of the fact that a + general solution for reliable multicast has proven elusive. The + applicability of PGM is narrowed further, and perhaps more + significantly, by the prototypical nature of at least four of the + transport elements the protocol incorporates. These are congestion + control, router assist, local retransmission, and a programmatic API + for reliable multicast protocols of this class. At the same time as + standardization efforts address each of these elements individually, + this publication is intended to foster experimentation with these + elements in general, and to inform that standardization process with + results from practise. + + This section briefly describes some of the experimental aspects of + PGM and makes non-normative references to some examples of current + practise based upon them. + + At least 3 different approaches to congestion control can be explored + with PGM: a receiver-feedback based approach, a router-assist based + approach, and layer-coding based approach. The first is supported by + the negative acknowledgement mechanism in PGM augmented by an + application-layer acknowledgement mechanism. The second is supported + by the router exception processing mechanism in PGM. The third is + supported by the FEC mechanisms in PGM. An example of a receiver- + feedback based approach is provided in [16], and a proposal for a + router-assist based approach was proposed in [17]. Open issues for + the researchers include how do each of these approaches behave in the + presence of multiple competing sessions of the same discipline or of + different disciplines, TCP most notably; how do each of them behave + over a particular range of topologies, and over a particular range of + loads; and how do each of them scale as a function of the size of the + receiver population. + + Router assist has applications not just to implosion control and + retransmit constraint as described in this specification, but also to + congestion control as described above, and more generally to any + feature which may be enhanced by access to per-network-element state + and processing. The full range of these features is as yet + + + +Speakman, et. al. Experimental [Page 103] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + unexplored, but a general mechanism for providing router assist in a + transport-protocol independent way (GRA) is a topic of active + research [18]. That effort has been primarily informed by the router + assist component of PGM, and implementation and deployment experience + with PGM will continue to be fed back into the specification and + eventual standardization of GRA. Open questions facing the + researchers ([19], [20], [21]) include how router-based state scales + relative to the feature benefit obtained, how system-wide factors + (such as throughput and retransmit latency) vary relative to the + scale and topology of deployed router assistance, and how incremental + deployment considerations affect the tractability of router-assist + based features. Router assist may have additional implications in + the area of congestion control to the extent that it may be applied + in multi-group layered coding schemes to increase the granularity and + reduce the latency of receiver based congestion control. + + GRA itself explicitly incorporates elements of active networking, and + to the extent that the router assist component of PGM is reflected in + GRA, experimentation with the narrowly defined network-element + functionality of PGM will provide some of the first real world + experience with this promising if controversial technology. + + Local retransmission is not a new idea in general in reliable + multicast, but the specific approach taken in PGM of locating re- + transmitters on the distribution tree for the session, diverting + repair requests from network elements to the re-transmitters, and + then propagating repairs downward from the repair point on the + distribution tree raises interesting questions concerning where to + locate re-transmitters in a given topology, and how network elements + locate those re-transmitters and evaluate their efficiency relative + to other available sources of retransmissions, most notably the + source itself. This particular aspect of PGM, while fully specified, + has only been implemented on the network element side, and awaits a + host-side implementation before questions like these can be + addressed. + + PGM presents the opportunity to develop a programming API for + reliable multicast applications that reflects both those + applications' service requirements as well as the services provided + by PGM in support of those applications that may usefully be made + visible above the transport interface. At least a couple of host- + side implementations of PGM and a concomitant API have been developed + for research purposes ([22], [23]), and are available as open source + explicitly for the kind of experimentation described in this section. + + Perhaps the broadest experiment that PGM can enable in a community of + researchers using a reasonable scale experimental transport protocol + is simply in the definition, implementation, and deployment of IP + + + +Speakman, et. al. Experimental [Page 104] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + multicast applications for which the reliability provided by PGM is a + significant enabler. Experience with such applications will not just + illuminate the value of reliable multicast, but will also provoke + practical examination of and responses to the attendant policy issues + (such as peering, billing, access control, firewalls, NATs, etc.), + and, if successful, will ultimately encourage more wide spread + deployment of IP multicast itself. + +18. Abbreviations + + ACK Acknowledgment + AFI Address Family Indicator + ALF Application Level Framing + APDU Application Protocol Data Unit + ARQ Automatic Repeat reQuest + DLR Designated Local Repairer + GSI Globally Unique Source Identifier + FEC Forward Error Correction + MD5 Message-Digest Algorithm + MTU Maximum Transmission Unit + NAK Negative Acknowledgment + NCF NAK Confirmation + NLA Network Layer Address + NNAK Null Negative Acknowledgment + ODATA Original Data + POLL Poll Request + POLR Poll Response + RDATA Repair Data + RSN Receive State Notification + SPM Source Path Message + SPMR SPM Request + TG Transmission Group + TGSIZE Transmission Group Size + TPDU Transport Protocol Data Unit + TSDU Transport Service Data Unit + TSI Transport Session Identifier + TSN Transmit State Notification + + + + + + + + + + + + + + +Speakman, et. al. Experimental [Page 105] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +19. Acknowledgements + + The design and specification of PGM has been substantially influenced + by reviews and revisions provided by several people who took the time + to read and critique this document. These include, in alphabetical + order: + + Bob Albrightson + Joel Bion + Mark Bowles + Steve Deering + Tugrul Firatli + Dan Harkins + Dima Khoury + Gerard Newman + Dave Oran + Denny Page + Ken Pillay + Chetan Rai + Yakov Rekhter + Dave Rossetti + Paul Stirpe + Brian Whetten + Kyle York + +20. References + + [1] B. Whetten, T. Montgomery, S. Kaplan, "A High Performance + Totally Ordered Multicast Protocol", in "Theory and Practice in + Distributed Systems", Springer Verlag LCNS938, 1994. + + [2] S. Floyd, V. Jacobson, C. Liu, S. McCanne, L. Zhang, "A + Reliable Multicast Framework for Light-weight Sessions and + Application Level Framing", ACM Transactions on Networking, + November 1996. + + [3] J. C. Lin, S. Paul, "RMTP: A Reliable Multicast Transport + Protocol", ACM SIGCOMM August 1996. + + [4] Miller, K., Robertson, K., Tweedly, A. and M. White, "Multicast + File Transfer Protocol (MFTP) Specification", Work In Progress. + + [5] Deering, S., "Host Extensions for IP Multicasting", STD 5, RFC + 1112, August 1989. + + [6] Katz, D., "IP Router Alert Option", RFC 2113, February 1997. + + [7] C. Partridge, "Gigabit Networking", Addison Wesley 1994. + + + +Speakman, et. al. Experimental [Page 106] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + [8] H. W. Holbrook, S. K. Singhal, D. R. Cheriton, "Log-Based + Receiver-Reliable Multicast for Distributed Interactive + Simulation", ACM SIGCOMM 1995. + + [9] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April + 1992. + + [10] Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, RFC + 1700, October 1994. + + [11] J. Nonnenmacher, E. Biersack, D. Towsley, "Parity-Based Loss + Recovery for Reliable Multicast Transmission", ACM SIGCOMM + September 1997. + + [12] L. Rizzo, "Effective Erasure Codes for Reliable Computer + Communication Protocols", Computer Communication Review, April + 1997. + + [13] V. Jacobson, "Congestion Avoidance and Control", ACM SIGCOMM + August 1988. + + [14] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", BCP, 14, RFC 2119, March 1997. + + [15] J. Bolot, T. Turletti, I. Wakeman, "Scalable Feedback Control + for Multicast Video Distribution in the Internet", Proc. + ACM/Sigcomm 94, pp. 58-67. + + [16] L. Rizzo, "pgmcc: A TCP-friendly Single-Rate Multicast + Congestion Control Scheme", Proc. of ACM SIGCOMM August 2000. + + [17] M. Luby, L. Vicisano, T. Speakman. "Heterogeneous multicast + congestion control based on router packet filtering", RMT + working group, June 1999, Pisa, Italy. + + [18] Cain, B., Speakman, T. and D. Towsley, "Generic Router Assist + (GRA) Building Block, Motivation and Architecture", Work In + Progress. + + [19] C. Papadopoulos, and E. Laliotis,"Incremental Deployment of a + Router-assisted Reliable Multicast Scheme,", Proc. of Networked + Group Communications (NGC2000), Stanford University, Palo Alto, + CA. November 2000. + + + + + + + + +Speakman, et. al. Experimental [Page 107] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + [20] C. Papadopoulos, "RAIMS: an Architecture for Router-Assisted + Internet Multicast Services." Presented at ETH, Zurich, + Switzerland, October 23 2000. + + [21] J. Chesterfield, A. Diana, A. Greenhalgh, M. Lad, and M. Lim, + "A BSD Router Implementation of PGM", + http://www.cs.ucl.ac.uk/external/m.lad/rpgm/ + + [22] L. Rizzo, "A PGM Host Implementation for FreeBSD", + http://www.iet.unipi.it/~luigi/pgm.html + + [23] M. Psaltaki, R. Araujo, G. Aldabbagh, P. Kouniakis, and A. + Giannopoulos, "Pragmatic General Multicast (PGM) host + implementation for FreeBSD.", + http://www.cs.ucl.ac.uk/research/darpa/pgm/PGM_FINAL.html + +21. Authors' Addresses + + Tony Speakman + EMail: speakman@cisco.com + + Dino Farinacci + Procket Networks + 3850 North First Street + San Jose, CA 95134 + USA + EMail: dino@procket.com + + Steven Lin + Juniper Networks + 1194 N. Mathilda Ave. + Sunnyvale, CA 94086 + USA + EMail: steven@juniper.net + + Alex Tweedly + EMail: agt@cisco.com + + Nidhi Bhaskar + EMail: nbhaskar@cisco.com + + Richard Edmonstone + EMail: redmonst@cisco.com + + Rajitha Sumanasekera + EMail: rajitha@cisco.com + + + + + +Speakman, et. al. Experimental [Page 108] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Lorenzo Vicisano + Cisco Systems, Inc. + 170 West Tasman Drive, + San Jose, CA 95134 + USA + EMail: lorenzo@cisco.com + + Jon Crowcroft + Department of Computer Science + University College London + Gower Street + London WC1E 6BT + UK + EMail: j.crowcroft@cs.ucl.ac.uk + + Jim Gemmell + Microsoft Bay Area Research Center + 301 Howard Street, #830 + San Francisco, CA 94105 + USA + EMail: jgemmell@microsoft.com + + Dan Leshchiner + Tibco Software + 3165 Porter Dr. + Palo Alto, CA 94304 + USA + EMail: dleshc@tibco.com + + Michael Luby + Digital Fountain, Inc. + 39141 Civic Center Drive + Fremont CA 94538 + USA + EMail: luby@digitalfountain.com + + Todd L. Montgomery + Talarian Corporation + 124 Sherman Ave. + Morgantown, WV 26501 + USA + EMail: todd@talarian.com + + + + + + + + + +Speakman, et. al. Experimental [Page 109] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + + Luigi Rizzo + Dip. di Ing. dell'Informazione + Universita` di Pisa + via Diotisalvi 2 + 56126 Pisa + Italy + EMail: luigi@iet.unipi.it + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Speakman, et. al. Experimental [Page 110] + +RFC 3208 PGM Reliable Transport Protocol December 2001 + + +22. Full Copyright Statement + + Copyright (C) The Internet Society (2001). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Speakman, et. al. Experimental [Page 111] + diff --git a/3rdparty/openpgm-svn-r1135/pgm/COPYING b/3rdparty/openpgm-svn-r1135/pgm/COPYING new file mode 100644 index 0000000..5ab7695 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/3rdparty/openpgm-svn-r1135/pgm/INSTALL b/3rdparty/openpgm-svn-r1135/pgm/INSTALL new file mode 100644 index 0000000..3ba60e5 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/INSTALL @@ -0,0 +1,4 @@ +For building instructions, see: + + http://code.google.com/p/openpgm/wiki/OpenPgm3CReferenceBuildLibrary + diff --git a/3rdparty/openpgm-svn-r1135/pgm/LICENSE b/3rdparty/openpgm-svn-r1135/pgm/LICENSE new file mode 100644 index 0000000..fabbeef --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/LICENSE @@ -0,0 +1,19 @@ +Most of OpenPGM is licensed under the terms of the GNU Lesser Public License, +the LGPL, with a special exception: + + As a special exception, the copyright holders of this library give + you permission to link this library with independent modules to + produce an executable, regardless of the license terms of these + independent modules, and to copy and distribute the resulting + executable under terms of your choice, provided that you also meet, + for each linked independent module, the terms and conditions of the + license of that module. An independent module is a module which is + not derived from or based on this library. If you modify this + library, you must extend this exception to your version of the + library. + +See the file COPYING for details of the LGPL. + +Hence you should treat the libraries libpgm, libpgmsnmp, and libpgmhttp of +OpenPGM as being LGPL licensed, with the special exception. + diff --git a/3rdparty/openpgm-svn-r1135/pgm/README b/3rdparty/openpgm-svn-r1135/pgm/README new file mode 100644 index 0000000..ece7aa1 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/README @@ -0,0 +1,7 @@ +OpenPGM is a library implementing the PGM reliable multicast network protocol. + +For more information about OpenPGM, see: + + http://openpgm.googlecode.com/ + + diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgm b/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgm new file mode 100644 index 0000000..2aaa3ce --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgm @@ -0,0 +1,171 @@ +# -*- mode: python -*- +# OpenPGM build script +# $Id$ + +import os; +Import('env') + +src = Split(""" + thread.c + mem.c + string.c + list.c + slist.c + queue.c + hashtable.c + messages.c + error.c + math.c + packet_parse.c + packet_test.c + sockaddr.c + time.c + if.c + getifaddrs.c + getnodeaddr.c + indextoaddr.c + indextoname.c + nametoindex.c + inet_network.c + md5.c + rand.c + gsi.c + tsi.c + txw.c + rxw.c + skbuff.c + socket.c + source.c + receiver.c + recv.c + engine.c + timer.c + net.c + rate_control.c + checksum.c + reed_solomon.c + galois_tables.c + wsastrerror.c + histogram.c +""") + +e = env.Clone(); +e.Append(CCFLAGS = '-DGETTEXT_PACKAGE=\'"pgm"\''); + +# Galois tables +e.Command ('galois_tables.c', 'galois_generator.pl', "perl $SOURCE > $TARGET"); + +# Version stamping +e.Command ('version.c', 'version_generator.py', "python $SOURCE > $TARGET"); +e.Depends ('version.c', src); +src += ['version.c']; + +e.StaticLibrary('libpgm', src); +e.StaticSharedLibrary('libpgm-pic', src); + +#----------------------------------------------------------------------------- +# unit testing + +if env['WITH_CHECK'] == 'true': + te = e.Clone(); + te.MergeFlags(env['GLIB_FLAGS']); + newCCFLAGS = []; + for flag in te['CCFLAGS']: + if ("-W" != flag[:2]) and ("-pedantic" != flag[:9]): + newCCFLAGS.append(flag); + te['CCFLAGS'] = newCCFLAGS; + te.ParseConfig ('pkg-config --cflags --libs check'); +# log dependencies + tlog = [ e.Object('messages.c'), + e.Object('thread.c'), + e.Object('galois_tables.c'), + e.Object('mem.c'), + e.Object('histogram.c'), + e.Object('string.c'), + e.Object('slist.c') + ]; +# framework + te.Program (['atomic_unittest.c']); + te.Program (['checksum_unittest.c'] + tlog); + te.Program (['error_unittest.c'] + tlog); + te.Program (['md5_unittest.c'] + tlog); + te.Program (['getifaddrs_unittest.c', + e.Object('error.c'), + e.Object('sockaddr.c'), + e.Object('list.c')] + tlog); + te.Program (['getnodeaddr_unittest.c', + e.Object('error.c'), + e.Object('sockaddr.c')] + tlog); + te.Program (['indextoaddr_unittest.c', + e.Object('error.c'), + e.Object('sockaddr.c')] + tlog); + te.Program (['inet_network_unittest.c', + e.Object('sockaddr.c')] + tlog); + te.Program (['rate_control_unittest.c'] + tlog); + te.Program (['reed_solomon_unittest.c'] + tlog); + te.Program (['time_unittest.c', + e.Object('error.c')] + tlog); +# collate + tframework = [ e.Object('checksum.c'), + e.Object('error.c'), + e.Object('galois_tables.c'), + e.Object('getifaddrs.c'), + e.Object('getnodeaddr.c'), + e.Object('hashtable.c'), + e.Object('histogram.c'), + e.Object('indextoaddr.c'), + e.Object('indextoname.c'), + e.Object('inet_network.c'), + e.Object('list.c'), + e.Object('math.c'), + e.Object('md5.c'), + e.Object('mem.c'), + e.Object('messages.c'), + e.Object('nametoindex.c'), + e.Object('queue.c'), + e.Object('rand.c'), + e.Object('rate_control.c'), + e.Object('reed_solomon.c'), + e.Object('slist.c'), + e.Object('sockaddr.c'), + e.Object('string.c'), + e.Object('thread.c'), + e.Object('time.c'), + e.Object('wsastrerror.c') + ]; +# library + te.Program (['txw_unittest.c', + e.Object('tsi.c'), + e.Object('skbuff.c')] + tframework); + te.Program (['rxw_unittest.c', + e.Object('tsi.c'), + e.Object('skbuff.c')] + tframework); + te.Program (['engine_unittest.c', + e.Object('version.c')] + tframework); + te.Program (['gsi_unittest.c', + e.Object('if.c')] + tframework); + te.Program (['tsi_unittest.c'] + tframework); + te.Program (['if_unittest.c'] + tframework); + te.Program (['socket_unittest.c', + e.Object('if.c'), + e.Object('tsi.c')] + tframework); + te.Program (['source_unittest.c', + e.Object('skbuff.c')] + tframework); + te.Program (['receiver_unittest.c', + e.Object('tsi.c')] + tframework); + te.Program (['recv_unittest.c', + e.Object('tsi.c'), + e.Object('gsi.c'), + e.Object('skbuff.c')] + tframework); + te.Program (['net_unittest.c'] + tframework); + te.Program (['timer_unittest.c'] + tframework); + te.Program (['packet_parse_unittest.c'] + tframework); + te.Program (['packet_test_unittest.c'] + tframework); + te.Program (['ip_unittest.c', + e.Object('if.c')] + tframework); +# performance tests + te.Program (['checksum_perftest.c', + e.Object('time.c'), + e.Object('error.c')] + tlog); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgm89 b/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgm89 new file mode 100644 index 0000000..5092157 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgm89 @@ -0,0 +1,83 @@ +# -*- mode: python -*- +# OpenPGM build script +# $Id$ + +import os; +import string; +Import('env') + +src = Split(""" + thread.c + mem.c + string.c + list.c + slist.c + queue.c + hashtable.c + messages.c + error.c + math.c + packet_parse.c + packet_test.c + sockaddr.c + time.c + if.c + getifaddrs.c + getnodeaddr.c + indextoaddr.c + indextoname.c + nametoindex.c + inet_network.c + md5.c + rand.c + gsi.c + tsi.c + txw.c + rxw.c + skbuff.c + socket.c + source.c + receiver.c + recv.c + engine.c + timer.c + net.c + rate_control.c + checksum.c + reed_solomon.c + galois_tables.c + wsastrerror.c + histogram.c +""") + +e = env.Clone(); +e.Append(CCFLAGS = '-DGETTEXT_PACKAGE=\'"pgm"\''); + +# Galois tables +e.Command ('galois_tables.c', 'galois_generator.pl', "perl $SOURCE > $TARGET"); + +# Version stamping +e.Command ('version.c', 'version_generator.py', "python $SOURCE > $TARGET"); +e.Depends ('version.c', src); +src += ['version.c']; + +# C89 degrading +c89source = Builder(action = 'cp $SOURCE $TARGET && if test -f "${SOURCE}.c89.patch"; then patch -i ${SOURCE}.c89.patch $TARGET; fi', + suffix = '.c89.c', + src_suffix = '.c', + single_source = 1); +e.Append(BUILDERS = {'C89Source' : c89source}) + +c89src = [] +for c99file in src: + c89file = c99file.replace('.c', '.c89.c'); + c89src += [ c89file ]; + patchFile = c99file + '.c89.patch'; + if os.path.exists (patchFile): + e.Depends (c89file, patchFile); + e.C89Source(c99file); + +e.StaticLibrary('libpgm89', c89src); +e.StaticSharedLibrary('libpgm89-pic', c89src); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmex b/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmex new file mode 100644 index 0000000..b508a04 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmex @@ -0,0 +1,18 @@ +# -*- mode: python -*- +# OpenPGM build script +# $Id$ + +Import('env') + +e = env.Clone(); +e.MergeFlags(env['GLIB_FLAGS']); + +src = Split(""" + log.c + backtrace.c + signal.c +""") + +e.StaticLibrary('libpgmex', src); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmhttp b/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmhttp new file mode 100644 index 0000000..9824b3c --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmhttp @@ -0,0 +1,53 @@ +# -*- mode: python -*- +# OpenPGM build script +# $Id$ + +Import('env') + +e = env.Clone() +e.Append(CCFLAGS = '-DGETTEXT_PACKAGE=\'"pgm-http"\''); + +# add binary tree to include path to find embedded htdocs +e.Append(CPPPATH = ['.']); + +src = Split(""" + http.c +""") + +htdocs = Split(""" + htdocs/404.html + htdocs/base.css + htdocs/robots.txt + htdocs/xhtml10_strict.doctype +""") + +pgmhttp = e.StaticLibrary('libpgmhttp', src); +pgmhttppic = e.StaticSharedLibrary('libpgmhttp-pic', src); + +# embed htdocs into C headers +embed_htdoc = Builder(action = './htdocs/convert_to_macro.pl $SOURCE > $TARGET') +e.Append(BUILDERS = {'EmbedHtdoc' : embed_htdoc}) + +for htdoc in htdocs: + embedded = htdoc + '.h' + e.EmbedHtdoc(embedded, htdoc) + +#----------------------------------------------------------------------------- +# unit testing + +if env['WITH_CHECK'] == 'true': + te = e.Clone(); +# add new suffix so we can re-use libpgm objects + te['SHOBJSUFFIX'] = '.http' + te['SHOBJSUFFIX']; + te['OBJSUFFIX'] = '.http' + te['OBJSUFFIX']; + + newCCFLAGS = []; + for flag in te['CCFLAGS']: + if ("-W" != flag[:2]) and ("-pedantic" != flag[:9]): + newCCFLAGS.append(flag); + te['CCFLAGS'] = newCCFLAGS; + te.ParseConfig ('pkg-config --cflags --libs check'); + te.Program (['http_unittest.c', te.Object('sockaddr.c'), te.Object('getifaddrs.c')]); + + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmsnmp b/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmsnmp new file mode 100644 index 0000000..8e35aab --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConscript.libpgmsnmp @@ -0,0 +1,35 @@ +# -*- mode: python -*- +# OpenPGM build script +# $Id$ + +Import('env') + +e = env.Clone() +e.Append(CCFLAGS = '-DGETTEXT_PACKAGE=\'"pgm-snmp"\''); + +e.MergeFlags(e['SNMP_FLAGS']); + +src = Split(""" + snmp.c + pgmMIB.c +""") + +e.StaticLibrary('libpgmsnmp', src); +e.StaticSharedLibrary('libpgmsnmp-pic', src); + +#----------------------------------------------------------------------------- +# unit testing + +if env['WITH_CHECK'] == 'true': + te = e.Clone(); + newCCFLAGS = []; + for flag in te['CCFLAGS']: + if ("-W" != flag[:2]) and ("-pedantic" != flag[:9]): + newCCFLAGS.append(flag); + te['CCFLAGS'] = newCCFLAGS; + te.ParseConfig ('pkg-config --cflags --libs check'); + te.Program ('snmp_unittest.c'); + te.Program (['pgmMIB_unittest.c', e.Object('snmp.c')]); + + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct b/3rdparty/openpgm-svn-r1135/pgm/SConstruct new file mode 100644 index 0000000..1187ef9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct @@ -0,0 +1,345 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 1, 0 ) +SConsignFile('scons.signatures' + '-' + platform.system() + '-' + platform.machine()); + +vars = Variables() +vars.AddVariables ( + EnumVariable ('BUILD', 'build environment', 'debug', + allowed_values=('release', 'debug', 'profile')), + EnumVariable ('BRANCH', 'branch prediction', 'none', + allowed_values=('none', 'profile', 'seed')), + EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', + allowed_values=('true', 'false')), + EnumVariable ('COVERAGE', 'test coverage', 'none', + allowed_values=('none', 'full')), + EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CHECK', 'Check test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_TEST', 'Network test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CC', 'C++ examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', + allowed_values=('true', 'false')), +) + +#----------------------------------------------------------------------------- +# Dependencies + +env = Environment(); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment( + variables = vars, + ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', + '-Wunsafe-loop-optimizations', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', + '-pedantic', +# C99 + '-std=gnu99', + '-D_XOPEN_SOURCE=600', + '-D_BSD_SOURCE', +# re-entrant libc + '-D_REENTRANT', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R', + '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header + '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system + '-DCONFIG_HAVE_PROC', +# example: crash handling + '-DCONFIG_HAVE_BACKTRACE', +# timing + '-DCONFIG_HAVE_PSELECT', + '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', + '-DCONFIG_HAVE_HPET', +# event handling + '-DCONFIG_HAVE_POLL', + '-DCONFIG_HAVE_EPOLL', +# interface enumeration + '-DCONFIG_HAVE_GETIFADDRS', + '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg +# '-DCONFIG_HAVE_WSACMSGHDR', +# multicast + '-DCONFIG_HAVE_MCAST_JOIN', + '-DCONFIG_HAVE_IP_MREQN', +# sprintf + '-DCONFIG_HAVE_SPRINTF_GROUPING', + '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE', +# GNU getopt + '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ '-pipe' + ], + LIBS = [ +# histogram math + 'm', +# clock_gettime() + 'rt' + ] +) + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Coverage analysis +if env['COVERAGE'] == 'full': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(CCFLAGS = '-ftest-coverage') + env.Append(LINKFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-lgcov') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = '-O2') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-gdb') + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +if env['WITH_SNMP'] == 'true': + env['SNMP_FLAGS'] = env.ParseFlags('!net-snmp-config --agent-libs'); + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); +# backup = context.env.Clone().Dictionary(); + lastASFLAGS = context.env.get('ASFLAGS', ''); + lastCCFLAGS = context.env.get('CCFLAGS', ''); + lastCFLAGS = context.env.get('CFLAGS', ''); + lastCPPDEFINES = context.env.get('CPPDEFINES', ''); + lastCPPFLAGS = context.env.get('CPPFLAGS', ''); + lastCPPPATH = context.env.get('CPPPATH', ''); + lastLIBPATH = context.env.get('LIBPATH', ''); + lastLIBS = context.env.get('LIBS', ''); + lastLINKFLAGS = context.env.get('LINKFLAGS', ''); + lastRPATH = context.env.get('RPATH', ''); + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); +# context.env.Replace(**backup); + context.env.Replace(ASFLAGS = lastASFLAGS, + CCFLAGS = lastCCFLAGS, + CFLAGS = lastCFLAGS, + CPPDEFINES = lastCPPDEFINES, + CPPFLAGS = lastCPPFLAGS, + CPPPATH = lastCPPPATH, + LIBPATH = lastLIBPATH, + LIBS = lastLIBS, + LINKFLAGS = lastLINKFLAGS, + RPATH = lastRPATH); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +def CheckEventFD(context): + context.Message('Checking eventfd...'); + result = context.TryLink(""" +#include +int main(int argc, char**argv) +{ + eventfd(0,0); + return 0; +} +""", '.c') + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck, + 'CheckEventFD': CheckEventFD +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +if conf.CheckEventFD(): + print 'Enabling kernel eventfd notification mechanism.'; + conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097 b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097 new file mode 100644 index 0000000..12e058a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097 @@ -0,0 +1,332 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 0, 97 ) +SConsignFile('scons.signatures'+ '-' + platform.system() + '-' + platform.machine()); + +opt = Options(None, ARGUMENTS) +opt.AddOptions ( + (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), + (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), + (EnumOption ('WITH_GETTEXT', 'l10n support via libintl', 'false', ('true', 'false'))), + (EnumOption ('WITH_GLIB', 'Build GLib dependent modules', 'false', ('true', 'false'))), + (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), + (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), + (EnumOption ('WITH_HTTP', 'HTTP administration', 'false', ('true', 'false'))), + (EnumOption ('WITH_SNMP', 'SNMP administration', 'false', ('true', 'false'))), + (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), + (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), + (EnumOption ('WITH_CC', 'C++ Examples', 'true', ('true', 'false'))), + (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), + (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), + (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), +) + +#----------------------------------------------------------------------------- +# Dependencies + +env = Environment(); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment(ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', + '-Wunsafe-loop-optimizations', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', + '-pedantic', +# C99 + '-std=gnu99', + '-D_XOPEN_SOURCE=600', + '-D_BSD_SOURCE', +# re-entrant libc + '-D_REENTRANT', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R', + '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header + '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system + '-DCONFIG_HAVE_PROC', +# example: crash handling + '-DCONFIG_HAVE_BACKTRACE', +# timing + '-DCONFIG_HAVE_PSELECT', + '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', +# event handling + '-DCONFIG_HAVE_POLL', + '-DCONFIG_HAVE_EPOLL', +# interface enumeration + '-DCONFIG_HAVE_GETIFADDRS', + '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg +# '-DCONFIG_HAVE_WSACMSGHDR', +# multicast + '-DCONFIG_HAVE_MCAST_JOIN', + '-DCONFIG_HAVE_IP_MREQN', +# sprintf + '-DCONFIG_HAVE_SPRINTF_GROUPING', + '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE', +# GNU getopt + '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ '-pipe' + ], + LIBS = [ +# histogram math + 'm', +# clock_gettime() + 'rt' + ], + PROTOBUF_CCFLAGS = '-I/miru/projects/protobuf/protobuf-2.1.0/src', + PROTOBUF_LIBS = '/miru/projects/protobuf/protobuf-2.1.0/src/.libs/libprotobuf.a', + PROTOBUF_PROTOC = '/miru/projects/protobuf/protobuf-2.1.0/src/protoc' +) +opt.Update (env) + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Coverage analysis +if env['COVERAGE'] == 'full': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(CCFLAGS = '-ftest-coverage') + env.Append(LINKFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-lgcov') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = '-O2') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-gdb') + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O0','-pg'], LINKFLAGS = '-pg') + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +if env['WITH_SNMP'] == 'true': + env['SNMP_FLAGS'] = env.ParseFlags('!net-snmp-config --cflags --agent-libs'); + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); +# backup = context.env.Clone().Dictionary(); + lastASFLAGS = context.env.get('ASFLAGS', ''); + lastCCFLAGS = context.env.get('CCFLAGS', ''); + lastCFLAGS = context.env.get('CFLAGS', ''); + lastCPPDEFINES = context.env.get('CPPDEFINES', ''); + lastCPPFLAGS = context.env.get('CPPFLAGS', ''); + lastCPPPATH = context.env.get('CPPPATH', ''); + lastLIBPATH = context.env.get('LIBPATH', ''); + lastLIBS = context.env.get('LIBS', ''); + lastLINKFLAGS = context.env.get('LINKFLAGS', ''); + lastRPATH = context.env.get('RPATH', ''); + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); +# context.env.Replace(**backup); + context.env.Replace(ASFLAGS = lastASFLAGS, + CCFLAGS = lastCCFLAGS, + CFLAGS = lastCFLAGS, + CPPDEFINES = lastCPPDEFINES, + CPPFLAGS = lastCPPFLAGS, + CPPPATH = lastCPPPATH, + LIBPATH = lastLIBPATH, + LIBS = lastLIBS, + LINKFLAGS = lastLINKFLAGS, + RPATH = lastRPATH); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +def CheckEventFD(context): + context.Message('Checking eventfd...'); + result = context.TryLink(""" +#include +int main(int argc, char**argv) +{ + eventfd(0,0); + return 0; +} +""", '.c') + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck, + 'CheckEventFD': CheckEventFD +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +if conf.CheckEventFD(): + print 'Enabling kernel eventfd notification mechanism.'; + conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.intelc b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.intelc new file mode 100644 index 0000000..337432a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.intelc @@ -0,0 +1,387 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 0, 97 ) +SConsignFile('scons.signatures'+ '-' + platform.system() + '-' + platform.machine() + '-intelc'); + +opt = Options(None, ARGUMENTS) +opt.AddOptions ( + (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), + (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), + (EnumOption ('WITH_GETTEXT', 'l10n support via libintl', 'false', ('true', 'false'))), + (EnumOption ('WITH_GLIB', 'Build GLib dependent modules', 'false', ('true', 'false'))), + (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), + (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), + (EnumOption ('WITH_HTTP', 'HTTP administration', 'false', ('true', 'false'))), + (EnumOption ('WITH_SNMP', 'SNMP administration', 'false', ('true', 'false'))), + (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), + (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), + (EnumOption ('WITH_CC', 'C++ Examples', 'true', ('true', 'false'))), + (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), + (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), + (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), +) + +#----------------------------------------------------------------------------- +# Dependencies + +def force_intelc(env): + env.Tool('intelc', version='11.1', topdir='/opt/intel/Compiler/11.1/064/bin/intel64'); + +env = Environment(); +force_intelc(env); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment(ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', +# '-Wextra', +# '-Wfloat-equal', + '-Wshadow', +# '-Wunsafe-loop-optimizations', + '-Wpointer-arith', +# '-Wbad-function-cast', +# '-Wcast-qual', +# '-Wcast-align', + '-Wwrite-strings', +# '-Waggregate-return', + '-Wstrict-prototypes', +# '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', +# '-Wmissing-noreturn', +# '-Wmissing-format-attribute', +# '-Wredundant-decls', +# '-Wnested-externs', +# Verbose inlining reports +# '-Winline', + +# 175: subscript out of range +# - Ignored for broken compiler C99 support +# e.g. tbuf[ sizeof(tbuf) ] = '\0'; + '-wd175', + +# 177: function was declared but never referenced +# - Ignored as side effect of portability pre-processor blocks. + '-wd177', + +# 181: argument is incompatible with corresponding format string conversion +# - Ignored as pre-processor fails to parse variadic printf style macros. + '-wd181', + +# 191: type qualifier is meaningless on cast type +# - Ignored as cast required for portability +# e.g. pgm_txw_state_t*const state = (pgm_txw_state_t*const)&skb->cb; + '-wd191', + +# 269: invalid format string conversion +# - Ignored with failure to display PRIu32 with (volatile uint32_t) + '-wd269', + +# 556: cannot assign to an entity of type "void *" +# - Ignored, it's a C++2003 error, valid in C99 aside of const down-converting. +# e.g. const char *s = ""; void *p = s; + '-wd556', + +# 589: transfer of control bypasses initialization +# - Ignored, it's a C++2003 error, perfectly valid in C99. + '-wd589', + +# 593: variable was set but never used +# '-wd593', + +# 981: operands are evaluated in unspecified order +# - Ignored as pedantic warning against possible side effects. +# e.g. printf ("%s.%s > ", +# pgm_gethostbyaddr((const struct in_addr*)&ip->ip_src), +# pgm_udpport_string(pgm_header->pgm_sport)); + '-wd981', + +# 2259: non-pointer conversion from "/type a/" to "/type b/" may lose significant bits +# - Ignored for really pedantic compiler temporary value conversions, +# e.g. uint16_t j = 1, i = ~j; + '-wd2259', + +# '-pedantic', +# C99 + '-std=c99', + '-D_XOPEN_SOURCE=600', + '-D_BSD_SOURCE', + '-gcc-version=420', +# re-entrant libc + '-D_REENTRANT', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R', + '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header + '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system + '-DCONFIG_HAVE_PROC', +# example: crash handling + '-DCONFIG_HAVE_BACKTRACE', +# timing + '-DCONFIG_HAVE_PSELECT', +# ioctl RTC_IRQP_SET: undefined reference to `__invalid_size_argument_for_IOC' +# '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', +# event handling + '-DCONFIG_HAVE_POLL', + '-DCONFIG_HAVE_EPOLL', +# interface enumeration + '-DCONFIG_HAVE_GETIFADDRS', + '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg +# '-DCONFIG_HAVE_WSACMSGHDR', +# multicast + '-DCONFIG_HAVE_MCAST_JOIN', + '-DCONFIG_HAVE_IP_MREQN', +# sprintf + '-DCONFIG_HAVE_SPRINTF_GROUPING', + '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE', +# GNU getopt + '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ '-pipe' + ], + LIBS = [ +# histogram math + 'm', +# clock_gettime() + 'rt' + ], + PROTOBUF_CCFLAGS = '-I/miru/projects/protobuf/protobuf-2.1.0/src', + PROTOBUF_LIBS = '/miru/projects/protobuf/protobuf-2.1.0/src/.libs/libprotobuf.a', + PROTOBUF_PROTOC = '/miru/projects/protobuf/protobuf-2.1.0/src/protoc' +) +opt.Update (env) +force_intelc(env); + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Coverage analysis +if env['COVERAGE'] == 'full': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(CCFLAGS = '-ftest-coverage') + env.Append(LINKFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-lgcov') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = '-O2') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-ggdb') + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O0','-pg'], LINKFLAGS = '-pg') + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +if env['WITH_SNMP'] == 'true': + env['SNMP_FLAGS'] = env.ParseFlags('!net-snmp-config --cflags --agent-libs'); + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); +# backup = context.env.Clone().Dictionary(); + lastASFLAGS = context.env.get('ASFLAGS', ''); + lastCCFLAGS = context.env.get('CCFLAGS', ''); + lastCFLAGS = context.env.get('CFLAGS', ''); + lastCPPDEFINES = context.env.get('CPPDEFINES', ''); + lastCPPFLAGS = context.env.get('CPPFLAGS', ''); + lastCPPPATH = context.env.get('CPPPATH', ''); + lastLIBPATH = context.env.get('LIBPATH', ''); + lastLIBS = context.env.get('LIBS', ''); + lastLINKFLAGS = context.env.get('LINKFLAGS', ''); + lastRPATH = context.env.get('RPATH', ''); + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); +# context.env.Replace(**backup); + context.env.Replace(ASFLAGS = lastASFLAGS, + CCFLAGS = lastCCFLAGS, + CFLAGS = lastCFLAGS, + CPPDEFINES = lastCPPDEFINES, + CPPFLAGS = lastCPPFLAGS, + CPPPATH = lastCPPPATH, + LIBPATH = lastLIBPATH, + LIBS = lastLIBS, + LINKFLAGS = lastLINKFLAGS, + RPATH = lastRPATH); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +def CheckEventFD(context): + context.Message('Checking eventfd...'); + result = context.TryLink(""" +#include +int main(int argc, char**argv) +{ + eventfd(0,0); + return 0; +} +""", '.c') + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck, + 'CheckEventFD': CheckEventFD +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +if conf.CheckEventFD(): + print 'Enabling kernel eventfd notification mechanism.'; + conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-intelc/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.mingw64 b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.mingw64 new file mode 100644 index 0000000..a3ffec9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.mingw64 @@ -0,0 +1,338 @@ +# -*- coding: utf-8 mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 0, 97 ) +SConsignFile('scons.signatures'+ '-Win64-' + platform.machine()); + +opt = Options(None, ARGUMENTS) +opt.AddOptions ( + (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), + (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), + (EnumOption ('WITH_GETTEXT', 'l10n support via libintl', 'false', ('true', 'false'))), + (EnumOption ('WITH_GLIB', 'Build GLib dependent modules', 'false', ('true', 'false'))), + (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), + (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), + (EnumOption ('WITH_HTTP', 'HTTP administration', 'false', ('true', 'false'))), + (EnumOption ('WITH_SNMP', 'SNMP administration', 'false', ('true', 'false'))), + (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), + (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), +# C++ broken scope + (EnumOption ('WITH_CC', 'C++ examples', 'false', ('true', 'false'))), + (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), + (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), + (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), +) + +#----------------------------------------------------------------------------- +# Dependencies + +def force_mingw(env): + env.PrependENVPath('PATH', '/opt/mingw/bin'); + env.Tool('crossmingw64', toolpath=['.']); + +env = Environment(); +force_mingw(env); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('PKG_CONFIG_PATH=win64/lib/pkgconfig pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('PKG_CONFIG_PATH=win64/lib/pkgconfig pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment(ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', + '-Wunsafe-loop-optimizations', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', + '-pedantic', + '-std=gnu99', +# ¡C89, not C99! +# '-std=gnu89', + '-D_BSD_SOURCE', + '-D_WIN32_WINNT=0x0501', +# re-entrant libc + '-D_REENTRANT', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header +# '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system +# '-DCONFIG_HAVE_PROC', +# example: crash handling +# '-DCONFIG_HAVE_BACKTRACE', +# timing +# '-DCONFIG_HAVE_PSELECT', +# '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', +# event handling +# '-DCONFIG_HAVE_POLL', +# '-DCONFIG_HAVE_EPOLL', +# interface enumeration +# '-DCONFIG_HAVE_GETIFADDRS', +# '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg + '-DCONFIG_HAVE_WSACMSGHDR', +# multicast +# '-DCONFIG_HAVE_MCAST_JOIN', +# '-DCONFIG_HAVE_IP_MREQN', +# sprintf +# '-DCONFIG_HAVE_SPRINTF_GROUPING', +# '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE' +# GNU getopt +# '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ '-pipe' + ], + LIBS = [ + 'iphlpapi.lib', + 'ws2_32.lib' + ] +) +opt.Update (env) +force_mingw(env); + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Coverage analysis +if env['COVERAGE'] == 'full': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(CCFLAGS = '-ftest-coverage') + env.Append(LINKFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-lgcov') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = '-O2') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-gdb') + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O0','-pg'], LINKFLAGS = '-pg') + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!PKG_CONFIG_PATH=win64/lib/pkgconfig pkg-config --cflags --libs glib-2.0 gthread-2.0'); + env.MergeFlags('-Iwin/include -Lwin64/lib'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +env['SNMP_FLAGS'] = { + 'CCFLAGS' : [], + 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], +}; + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); +# backup = context.env.Clone().Dictionary(); + lastASFLAGS = context.env.get('ASFLAGS', ''); + lastCCFLAGS = context.env.get('CCFLAGS', ''); + lastCFLAGS = context.env.get('CFLAGS', ''); + lastCPPDEFINES = context.env.get('CPPDEFINES', ''); + lastCPPFLAGS = context.env.get('CPPFLAGS', ''); + lastCPPPATH = context.env.get('CPPPATH', ''); + lastLIBPATH = context.env.get('LIBPATH', ''); + lastLIBS = context.env.get('LIBS', ''); + lastLINKFLAGS = context.env.get('LINKFLAGS', ''); + lastRPATH = context.env.get('RPATH', ''); + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); +# context.env.Replace(**backup); + context.env.Replace(ASFLAGS = lastASFLAGS, + CCFLAGS = lastCCFLAGS, + CFLAGS = lastCFLAGS, + CPPDEFINES = lastCPPDEFINES, + CPPFLAGS = lastCPPFLAGS, + CPPPATH = lastCPPPATH, + LIBPATH = lastLIBPATH, + LIBS = lastLIBS, + LINKFLAGS = lastLINKFLAGS, + RPATH = lastRPATH); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('PKG_CONFIG_PATH=win64/lib/pkgconfig pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +def CheckEventFD(context): + context.Message('Checking eventfd...'); + result = context.TryLink(""" +#include +int main(int argc, char**argv) +{ + eventfd(0,0); + return 0; +} +""", '.c') + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck, + 'CheckEventFD': CheckEventFD +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +if conf.CheckEventFD(): + print 'Enabling kernel eventfd notification mechanism.'; + conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-Win64-' + platform.machine() + '/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm89'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript89'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.sunstudio b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.sunstudio new file mode 100644 index 0000000..86323d5 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.097.sunstudio @@ -0,0 +1,332 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 0, 97 ) +SConsignFile('scons.signatures'+ '-' + platform.system() + '-' + platform.machine() + '-sunstudio'); + +opt = Options(None, ARGUMENTS) +opt.AddOptions ( + (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), + (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), + (EnumOption ('WITH_GETTEXT', 'l10n support via libintl', 'false', ('true', 'false'))), + (EnumOption ('WITH_GLIB', 'Build GLib dependent modules', 'false', ('true', 'false'))), + (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), + (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), + (EnumOption ('WITH_HTTP', 'HTTP administration', 'false', ('true', 'false'))), + (EnumOption ('WITH_SNMP', 'SNMP administration', 'false', ('true', 'false'))), + (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), + (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), + (EnumOption ('WITH_CC', 'C++ Examples', 'true', ('true', 'false'))), + (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), + (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), + (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), +) + +#----------------------------------------------------------------------------- +# Dependencies + +def force_sunstudio(env): + env.PrependENVPath('PATH', '/opt/sun/sunstudio12.1/bin'); + env.Tool('sunc++'); + env.Tool('suncc'); + env.Tool('sunlink'); + env.Tool('sunar'); + +env = Environment(); +force_sunstudio(env); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment(ENV = os.environ, + CCFLAGS = [ '-v', +# C99 + '-xc99=all', + '-D_XOPEN_SOURCE=600', + '-D__EXTENSIONS__', + '-DBSD_COMP', + '-D_BSD_SOURCE', +# re-entrant libc + '-D_REENTRANT', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R', + '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header + '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system + '-DCONFIG_HAVE_PROC', +# example: crash handling + '-DCONFIG_HAVE_BACKTRACE', +# timing + '-DCONFIG_HAVE_PSELECT', + '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', +# event handling + '-DCONFIG_HAVE_POLL', + '-DCONFIG_HAVE_EPOLL', +# interface enumeration + '-DCONFIG_HAVE_GETIFADDRS', + '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg +# '-DCONFIG_HAVE_WSACMSGHDR', +# multicast + '-DCONFIG_HAVE_MCAST_JOIN', + '-DCONFIG_HAVE_IP_MREQN', +# sprintf + '-DCONFIG_HAVE_SPRINTF_GROUPING', + '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE', +# GNU getopt + '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ + ], + LIBS = [ +# histogram math + 'm', +# clock_gettime() + 'rt' + ], + PROTOBUF_CCFLAGS = '-I/miru/projects/protobuf/protobuf-2.1.0/src', + PROTOBUF_LIBS = '/miru/projects/protobuf/protobuf-2.1.0/src/.libs/libprotobuf.a', + PROTOBUF_PROTOC = '/miru/projects/protobuf/protobuf-2.1.0/src/protoc' +) +opt.Update (env) +force_sunstudio(env); + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Coverage analysis +if env['COVERAGE'] == 'full': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(CCFLAGS = '-ftest-coverage') + env.Append(LINKFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-lgcov') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = '-O2') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG','-g'], LINKFLAGS = '-g') + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O0','-pg'], LINKFLAGS = '-pg') + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +def list_remove(list, target): + newlist = []; + for item in str(list).split(' '): + if item != target: + newlist.append(item); + return newlist; + +# managed environment for libpgmsnmp, libpgmhttp +if env['WITH_SNMP'] == 'true': + env['SNMP_FLAGS'] = env.ParseFlags('!net-snmp-config --cflags --agent-libs'); +# strip out GCC only flags + ccflags = env['SNMP_FLAGS'].get('CCFLAGS', ''); + env['SNMP_FLAGS']['CCFLAGS'] = list_remove(ccflags, '-Wall'); + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); +# backup = context.env.Clone().Dictionary(); + lastASFLAGS = context.env.get('ASFLAGS', ''); + lastCCFLAGS = context.env.get('CCFLAGS', ''); + lastCFLAGS = context.env.get('CFLAGS', ''); + lastCPPDEFINES = context.env.get('CPPDEFINES', ''); + lastCPPFLAGS = context.env.get('CPPFLAGS', ''); + lastCPPPATH = context.env.get('CPPPATH', ''); + lastLIBPATH = context.env.get('LIBPATH', ''); + lastLIBS = context.env.get('LIBS', ''); + lastLINKFLAGS = context.env.get('LINKFLAGS', ''); + lastRPATH = context.env.get('RPATH', ''); + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); +# context.env.Replace(**backup); + context.env.Replace(ASFLAGS = lastASFLAGS, + CCFLAGS = lastCCFLAGS, + CFLAGS = lastCFLAGS, + CPPDEFINES = lastCPPDEFINES, + CPPFLAGS = lastCPPFLAGS, + CPPPATH = lastCPPPATH, + LIBPATH = lastLIBPATH, + LIBS = lastLIBS, + LINKFLAGS = lastLINKFLAGS, + RPATH = lastRPATH); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +def CheckEventFD(context): + context.Message('Checking eventfd...'); + result = context.TryLink(""" +#include +int main(int argc, char**argv) +{ + eventfd(0,0); + return 0; +} +""", '.c') + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck, + 'CheckEventFD': CheckEventFD +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +if conf.CheckEventFD(): + print 'Enabling kernel eventfd notification mechanism.'; + conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-sunstudio/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Debian4 b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Debian4 new file mode 100644 index 0000000..952013e --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Debian4 @@ -0,0 +1,281 @@ +# -*- mode: python -*- +# OpenPGM build script + +import os +import time +import sys + +EnsureSConsVersion( 0, 97 ) +SConsignFile('scons.signatures'); + +opt = Options(None, ARGUMENTS) +opt.AddOptions ( + (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), + (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), + (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), + (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), + (EnumOption ('WITH_HTTP', 'HTTP administration', 'true', ('true', 'false'))), + (EnumOption ('WITH_SNMP', 'SNMP administration', 'true', ('true', 'false'))), + (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), + (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), + (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), + (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), + (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), + (EnumOption ('WITH_PLUS', 'libpgmplus GPL library', 'false', ('true', 'false'))), +) + +#----------------------------------------------------------------------------- +# Dependencies + +env = Environment(); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' + Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' + Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' + Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment(ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', + '-Wunsafe-loop-optimizations', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', + '-pedantic', + '-std=gnu99', + '--param', 'max-inline-insns-single=600', + '-D_REENTRANT', + '-D_GNU_SOURCE', + '-D__need_IOV_MAX', + '-DCONFIG_16BIT_CHECKSUM', + '-DCONFIG_HAVE_PROC', + '-DCONFIG_HAVE_BACKTRACE', + '-DCONFIG_HAVE_PSELECT', + '-DCONFIG_HAVE_POLL', + '-DCONFIG_HAVE_EPOLL', + '-DCONFIG_HAVE_CLOCK_GETTIME', + '-DCONFIG_HAVE_CLOCK_NANOSLEEP', + '-DCONFIG_HAVE_NANOSLEEP', + '-DCONFIG_HAVE_USLEEP', + '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', + '-DCONFIG_HAVE_IFR_NETMASK', + '-DCONFIG_HAVE_GETIFADDRS', + '-DCONFIG_HAVE_GETHOSTBYNAME2', + '-DCONFIG_HAVE_GETPROTOBYNAME_R', + '-DCONFIG_HAVE_MCAST_JOIN', + '-DCONFIG_HAVE_IP_MREQN', + '-DCONFIG_HAVE_DSO_VISIBILITY', + '-DCONFIG_BIND_INADDR_ANY', + '-DCONFIG_GALOIS_MUL_LUT', + ], + LINKFLAGS = [ '-pipe', + '-lm' + ] +) +opt.Update (env) + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Coverage analysis +if env['COVERAGE'] == 'full': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(CCFLAGS = '-ftest-coverage') + env.Append(LINKFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-lgcov') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = '-O2') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = '-ggdb', LINKFLAGS = '-gdb') + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +env.ParseConfig('pkg-config --cflags --libs glib-2.0 gthread-2.0'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +env['SNMP_FLAGS'] = { + 'CCFLAGS' : [], + 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], +}; + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); + lastLIBS = context.env['LIBS']; + lastCCFLAGS= context.env['CCFLAGS']; + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); + context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +def CheckEventFD(context): + context.Message('Checking eventfd...'); + result = context.TryLink(""" +#include +int main(int argc, char**argv) +{ + eventfd(0,0); + return 0; +} +""", '.c') + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck, + 'CheckEventFD': CheckEventFD +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Enabling extra Red Hat dependencies for Net-SNMP.'; + conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); + lastLIBS = conf.env['LIBS']; + conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); + conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); + conf.env.Replace(LIBS = lastLIBS); + if not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +if conf.CheckEventFD(): + print 'Enabling kernel eventfd notification mechanism.'; + conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); + +env = conf.Finish(); + +# DSO visibility flags +if '-DCONFIG_HAVE_DSO_VISIBILITY' in env['CCFLAGS']: + env.Append(CCFLAGS = '-DPGM_GNUC_INTERNAL=G_GNUC_INTERNAL') +else: + env.Append(CCFLAGS = '-DPGM_GNUC_INTERNAL=') + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +SConscript(ref_node + 'SConscript.libpgm'); +SConscript(ref_node + 'SConscript.libpgmex'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.FreeBSD80 b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.FreeBSD80 new file mode 100644 index 0000000..62b49f7 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.FreeBSD80 @@ -0,0 +1,351 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 1, 0 ) +SConsignFile('scons.signatures' + '-' + platform.system() + '-' + platform.machine()); + +vars = Variables() +vars.AddVariables ( + EnumVariable ('BUILD', 'build environment', 'debug', + allowed_values=('release', 'debug', 'profile')), + EnumVariable ('BRANCH', 'branch prediction', 'none', + allowed_values=('none', 'profile', 'seed')), + EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', + allowed_values=('true', 'false')), + EnumVariable ('COVERAGE', 'test coverage', 'none', + allowed_values=('none', 'full')), + EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CHECK', 'Check test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_TEST', 'Network test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CC', 'C++ examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', + allowed_values=('true', 'false')), +) + +#----------------------------------------------------------------------------- +# Dependencies + +env = Environment(); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment( + variables = vars, + ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', + '-Wunsafe-loop-optimizations', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', + '-pedantic', +# C99 + '-std=gnu99', +# re-entrant libc + '-D_REENTRANT', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header +# '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system +# '-DCONFIG_HAVE_PROC', +# example: crash handling +# '-DCONFIG_HAVE_BACKTRACE', +# timing + '-DCONFIG_HAVE_PSELECT', +# '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', +# '-DCONFIG_HAVE_HPET', +# event handling + '-DCONFIG_HAVE_POLL', +# '-DCONFIG_HAVE_EPOLL', +# interface enumeration + '-DCONFIG_HAVE_GETIFADDRS', + '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg +# '-DCONFIG_HAVE_WSACMSGHDR', +# multicast +# '-DCONFIG_HAVE_MCAST_JOIN', + '-DCONFIG_HAVE_IP_MREQN', +# sprintf + '-DCONFIG_HAVE_SPRINTF_GROUPING', + '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD + '-DCONFIG_HOST_ORDER_IP_LEN', + '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE', +# GNU getopt + '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ '-pipe' + ], + LIBS = [ +# histogram math + 'm', +# clock_gettime() + 'rt', +# ftime() + 'compat', +# POSIX threads + 'pthread' + ] +) + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Coverage analysis +if env['COVERAGE'] == 'full': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(CCFLAGS = '-ftest-coverage') + env.Append(LINKFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-lgcov') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = '-O2') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-gdb') + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +if env['WITH_SNMP'] == 'true': + env['SNMP_FLAGS'] = env.ParseFlags('!net-snmp-config --cflags --agent-libs'); + +def restore_env(env, backup): + for var in backup.keys(): + env[var] = backup[var]; + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); +# backup = context.env.Clone().Dictionary(); + lastASFLAGS = context.env.get('ASFLAGS', ''); + lastCCFLAGS = context.env.get('CCFLAGS', ''); + lastCFLAGS = context.env.get('CFLAGS', ''); + lastCPPDEFINES = context.env.get('CPPDEFINES', ''); + lastCPPFLAGS = context.env.get('CPPFLAGS', ''); + lastCPPPATH = context.env.get('CPPPATH', ''); + lastLIBPATH = context.env.get('LIBPATH', ''); + lastLIBS = context.env.get('LIBS', ''); + lastLINKFLAGS = context.env.get('LINKFLAGS', ''); + lastRPATH = context.env.get('RPATH', ''); + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); +# context.env.Replace(**backup); + context.env.Replace(ASFLAGS = lastASFLAGS, + CCFLAGS = lastCCFLAGS, + CFLAGS = lastCFLAGS, + CPPDEFINES = lastCPPDEFINES, + CPPFLAGS = lastCPPFLAGS, + CPPPATH = lastCPPPATH, + LIBPATH = lastLIBPATH, + LIBS = lastLIBS, + LINKFLAGS = lastLINKFLAGS, + RPATH = lastRPATH); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +def CheckEventFD(context): + context.Message('Checking eventfd...'); + result = context.TryLink(""" +#include +int main(int argc, char**argv) +{ + eventfd(0,0); + return 0; +} +""", '.c') + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck, + 'CheckEventFD': CheckEventFD +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +if conf.CheckEventFD(): + print 'Enabling kernel eventfd notification mechanism.'; + conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.OpenSolaris b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.OpenSolaris new file mode 100644 index 0000000..c9833ed --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.OpenSolaris @@ -0,0 +1,310 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 1, 0 ) +SConsignFile('scons.signatures'+ '-OpenSolaris-' + platform.machine() + '-gcc'); + +vars = Variables() +vars.AddVariables ( + EnumVariable ('BUILD', 'build environment', 'debug', + allowed_values=('release', 'debug', 'profile')), + EnumVariable ('BRANCH', 'branch prediction', 'none', + allowed_values=('none', 'profile', 'seed')), + EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CHECK', 'Check test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_TEST', 'Network test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CC', 'C++ examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', + allowed_values=('true', 'false')), +) + +#----------------------------------------------------------------------------- +# Dependencies + +env = Environment(); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment( + variables = vars, + ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', +# '-Wunsafe-loop-optimizations', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', + '-pedantic', +# C99 + '-std=gnu99', + '-D_XOPEN_SOURCE=600', + '-D__EXTENSIONS__', + '-DBSD_COMP', + '-D_BSD_SOURCE', +# re-entrant libc + '-D_REENTRANT', + '-DCONFIG_HAVE_GETPROTOBYNAME_R', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header + '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system +# '-DCONFIG_HAVE_PROC', +# example: crash handling +# '-DCONFIG_HAVE_BACKTRACE', +# timing + '-DCONFIG_HAVE_PSELECT', +# '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', +# '-DCONFIG_HAVE_HPET', +# event handling + '-DCONFIG_HAVE_POLL', +# '-DCONFIG_HAVE_EPOLL', +# interface enumeration +# '-DCONFIG_HAVE_GETIFADDRS', +# '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg +# '-DCONFIG_HAVE_WSACMSGHDR', +# multicast + '-DCONFIG_HAVE_MCAST_JOIN', +# '-DCONFIG_HAVE_IP_MREQN', +# sprintf + '-DCONFIG_HAVE_SPRINTF_GROUPING', +# '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE', +# GNU getopt + '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ '-pipe' + ], + LIBS = [ +# histogram math + 'm', +# clock_gettime() + 'rt', +# Solaris sockets + 'resolv', + 'socket', + 'nsl' + ] +) + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = ['-O2'], LINKFLAGS = []) + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG', '-ggdb'], LINKFLAGS = ['-gdb']) + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = ['-pg']) + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +env['SNMP_FLAGS'] = { + 'CCFLAGS' : [], + 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp', + 'ssl', 'kstat', 'wrap', 'adm' ], + 'CPPPATH' : ['/opt/cws/include'], + 'LIBPATH' : ['/opt/csw/lib'], +}; + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); + lastLIBS = context.env['LIBS']; + lastCCFLAGS= context.env['CCFLAGS']; + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); + context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-OpenSolaris-' + platform.machine() + '-gcc/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.RHEL4 b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.RHEL4 new file mode 100644 index 0000000..1637ea5 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.RHEL4 @@ -0,0 +1,279 @@ +# -*- mode: python -*- +# OpenPGM build script + +import os +import time +import sys + +EnsureSConsVersion( 0, 97 ) +SConsignFile('scons.signatures'); + +opt = Options(None, ARGUMENTS) +opt.AddOptions ( + (EnumOption ('BUILD', 'build environment', 'debug', ('release', 'debug', 'profile'))), + (EnumOption ('BRANCH', 'branch prediction', 'none', ('none', 'profile', 'seed'))), + (EnumOption ('COVERAGE', 'test coverage', 'none', ('none', 'full'))), + (EnumOption ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', ('true', 'false'))), + (EnumOption ('WITH_HTTP', 'HTTP administration', 'true', ('true', 'false'))), + (EnumOption ('WITH_SNMP', 'SNMP administration', 'true', ('true', 'false'))), + (EnumOption ('WITH_CHECK', 'Check test system', 'false', ('true', 'false'))), + (EnumOption ('WITH_TEST', 'Network test system', 'false', ('true', 'false'))), + (EnumOption ('WITH_EXAMPLES', 'Examples', 'true', ('true', 'false'))), + (EnumOption ('WITH_NCURSES', 'NCURSES examples', 'false', ('true', 'false'))), + (EnumOption ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', ('true', 'false'))), + (EnumOption ('WITH_PLUS', 'libpgmplus GPL library', 'false', ('true', 'false'))), +) + +#----------------------------------------------------------------------------- +# Dependencies + +env = Environment(); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('PKG_CONFIG_PATH=/usr/evolution28/lib/pkgconfig:/usr/lib/pkconfig pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('PKG_CONFIG_PATH=/usr/evolution28/lib/pkgconfig:/usr/lib/pkconfig pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' + Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' + Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' + Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment(ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', + '-pedantic', + '-std=gnu99', + '--param', 'max-inline-insns-single=600', + '-D_REENTRANT', + '-D_GNU_SOURCE', + '-D__need_IOV_MAX', + '-DCONFIG_16BIT_CHECKSUM', + '-DCONFIG_HAVE_PROC', + '-DCONFIG_HAVE_BACKTRACE', + '-DCONFIG_HAVE_PSELECT', + '-DCONFIG_HAVE_POLL', + '-DCONFIG_HAVE_EPOLL', + '-DCONFIG_HAVE_CLOCK_GETTIME', + '-DCONFIG_HAVE_CLOCK_NANOSLEEP', + '-DCONFIG_HAVE_NANOSLEEP', + '-DCONFIG_HAVE_USLEEP', + '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', + '-DCONFIG_HAVE_GETIFADDRS', + '-DCONFIG_HAVE_GETHOSTBYNAME2', + '-DCONFIG_HAVE_GETPROTOBYNAME_R', + '-DCONFIG_HAVE_MCAST_JOIN', + '-DCONFIG_HAVE_IP_MREQN', + '-DCONFIG_HAVE_DSO_VISIBILITY', + '-DCONFIG_BIND_INADDR_ANY', + '-DCONFIG_GALOIS_MUL_LUT', + ], + LINKFLAGS = [ '-pipe', + '-lm' + ] +) +opt.Update (env) + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Coverage analysis +if env['COVERAGE'] == 'full': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(CCFLAGS = '-ftest-coverage') + env.Append(LINKFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-lgcov') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = '-O2') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = '-ggdb', LINKFLAGS = '-gdb') + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +env.ParseConfig('PKG_CONFIG_PATH=/usr/evolution28/lib/pkgconfig:/usr/lib/pkconfig pkg-config --cflags --libs glib-2.0 gthread-2.0'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +env['SNMP_FLAGS'] = { + 'CCFLAGS' : [], + 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], +}; + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); + lastLIBS = context.env['LIBS']; + lastCCFLAGS= context.env['CCFLAGS']; + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); + context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +def CheckEventFD(context): + context.Message('Checking eventfd...'); + result = context.TryLink(""" +#include +int main(int argc, char**argv) +{ + eventfd(0,0); + return 0; +} +""", '.c') + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck, + 'CheckEventFD': CheckEventFD +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Enabling extra Red Hat dependencies for Net-SNMP.'; + conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); + lastLIBS = conf.env['LIBS']; + conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); + conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); + conf.env.Replace(LIBS = lastLIBS); + if not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +if conf.CheckEventFD(): + print 'Enabling kernel eventfd notification mechanism.'; + conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); + +env = conf.Finish(); + +# DSO visibility flags +if '-DCONFIG_HAVE_DSO_VISIBILITY' in env['CCFLAGS']: + env.Append(CCFLAGS = '-DPGM_GNUC_INTERNAL=G_GNUC_INTERNAL') +else: + env.Append(CCFLAGS = '-DPGM_GNUC_INTERNAL=') + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +SConscript(ref_node + 'SConscript.libpgm'); +SConscript(ref_node + 'SConscript.libpgmex'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.gcc64 b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.gcc64 new file mode 100644 index 0000000..01508dd --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.gcc64 @@ -0,0 +1,350 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 1, 0 ) +SConsignFile('scons.signatures' + '-' + platform.system() + '-' + platform.machine() + '-gcc64'); + +vars = Variables() +vars.AddVariables ( + EnumVariable ('BUILD', 'build environment', 'debug', + allowed_values=('release', 'debug', 'profile', 'thirtytwo')), + EnumVariable ('BRANCH', 'branch prediction', 'none', + allowed_values=('none', 'profile', 'seed')), + EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CHECK', 'Check test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_TEST', 'Network test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CC', 'C++ examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_PLUS', 'libpgmplus GPL library', 'false', + allowed_values=('true', 'false')), +) + +#----------------------------------------------------------------------------- +# Dependencies + +def force_gcc(env): + env.PrependENVPath('PATH', '/usr/sfw/bin'); + env.PrependENVPath('PATH', '/opt/glib-gcc64/bin'); + env.PrependENVPath('PATH', '/usr/local/bin'); + env.Tool('gcc'); + env.Tool('g++'); + +env = Environment(); +force_gcc(env); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment( + variables = vars, + ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', +# '-Wunsafe-loop-optimizations', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', + '-pedantic', +# C99 + '-std=gnu99', + '-D_XOPEN_SOURCE=600', + '-D__EXTENSIONS__', + '-DBSD_COMP', + '-D_BSD_SOURCE', +# re-entrant libc + '-D_REENTRANT', + '-DCONFIG_HAVE_GETPROTOBYNAME_R', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header + '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system +# '-DCONFIG_HAVE_PROC', +# example: crash handling +# '-DCONFIG_HAVE_BACKTRACE', +# timing +# '-DCONFIG_HAVE_PSELECT', +# '-DCONFIG_HAVE_RTC', +# '-DCONFIG_HAVE_TSC', +# '-DCONFIG_HAVE_HPET', +# event handling + '-DCONFIG_HAVE_POLL', +# '-DCONFIG_HAVE_EPOLL', +# interface enumeration +# '-DCONFIG_HAVE_GETIFADDRS', +# '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg +# '-DCONFIG_HAVE_WSACMSGHDR', +# multicast + '-DCONFIG_HAVE_MCAST_JOIN', +# '-DCONFIG_HAVE_IP_MREQN', +# sprintf +# '-DCONFIG_HAVE_SPRINTF_GROUPING', +# '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE', +# GNU getopt + '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ '-pipe' + ], + LIBS = [ +# histogram math + 'm', +# clock_gettime() + 'rt', +# Solaris sockets + 'resolv', + 'socket', + 'nsl' + ], + PROTOBUF_CCFLAGS = '-I/opt/glib-gcc64/include', + PROTOBUF_LIBS = '/opt/glib-gcc64/lib/sparcv9/libprotobuf.a', + PROTOBUF_PROTOC = '/opt/glib-gcc64/bin/protoc' +) +force_gcc(env); + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = ['-O2','-m64'], LINKFLAGS = '-m64') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb','-m64'], LINKFLAGS = ['-gdb','-m64']) + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O2','-pg','-m64'], LINKFLAGS = ['-pg','-m64']) + +thirtytwo = env.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = ['-O2','-m32'], LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +def list_remove(list, target): + newlist = []; + for item in str(list).split(' '): + if item != target: + newlist.append(item); + return newlist; + +# managed environment for libpgmsnmp, libpgmhttp +if env['WITH_SNMP'] == 'true': +# net-snmp-config is broken in Solaris 10 and requires two separate calls + env['SNMP_FLAGS'] = env.ParseFlags(['!net-snmp-config-64 --cflags', + '!net-snmp-config-64 --agent-libs']); +# GCC error: language arch=v9 not recognized + ccflags = env['SNMP_FLAGS'].get('CCFLAGS', ''); + env['SNMP_FLAGS']['CCFLAGS'] = list_remove(ccflags, '-xarch=v9'); + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); +# backup = context.env.Clone().Dictionary(); + lastASFLAGS = context.env.get('ASFLAGS', ''); + lastCCFLAGS = context.env.get('CCFLAGS', ''); + lastCFLAGS = context.env.get('CFLAGS', ''); + lastCPPDEFINES = context.env.get('CPPDEFINES', ''); + lastCPPFLAGS = context.env.get('CPPFLAGS', ''); + lastCPPPATH = context.env.get('CPPPATH', ''); + lastLIBPATH = context.env.get('LIBPATH', ''); + lastLIBS = context.env.get('LIBS', ''); + lastLINKFLAGS = context.env.get('LINKFLAGS', ''); + lastRPATH = context.env.get('RPATH', ''); + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); +# context.env.Replace(**backup); + context.env.Replace(ASFLAGS = lastASFLAGS, + CCFLAGS = lastCCFLAGS, + CFLAGS = lastCFLAGS, + CPPDEFINES = lastCPPDEFINES, + CPPFLAGS = lastCPPFLAGS, + CPPPATH = lastCPPPATH, + LIBPATH = lastLIBPATH, + LIBS = lastLIBS, + LINKFLAGS = lastLINKFLAGS, + RPATH = lastRPATH); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-gcc64/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.sungcc b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.sungcc new file mode 100644 index 0000000..9d50481 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.sungcc @@ -0,0 +1,337 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 1, 0 ) +SConsignFile('scons.signatures'+ '-' + platform.system() + '-' + platform.machine() + '-sungcc'); + +vars = Variables() +vars.AddVariables ( + EnumVariable ('BUILD', 'build environment', 'debug', + allowed_values=('release', 'debug', 'profile')), + EnumVariable ('BRANCH', 'branch prediction', 'none', + allowed_values=('none', 'profile', 'seed')), + EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CHECK', 'Check test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_TEST', 'Network test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CC', 'C++ examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', + allowed_values=('true', 'false')), +) + +#----------------------------------------------------------------------------- +# Dependencies + +def force_gcc(env): + env.PrependENVPath('PATH', '/usr/sfw/bin'); + env.PrependENVPath('PATH', '/opt/glib-gcc/bin'); + env.Tool('gcc'); + env.Tool('g++'); + +env = Environment(); +force_gcc(env); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment( + variables = vars, + ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', +# '-Wunsafe-loop-optimizations', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', + '-pedantic', +# C99 + '-std=gnu99', + '-D_XOPEN_SOURCE=600', + '-D__EXTENSIONS__', + '-DBSD_COMP', + '-D_BSD_SOURCE', +# re-entrant libc + '-D_REENTRANT', + '-DCONFIG_HAVE_GETPROTOBYNAME_R', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header + '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system +# '-DCONFIG_HAVE_PROC', +# example: crash handling +# '-DCONFIG_HAVE_BACKTRACE', +# timing +# '-DCONFIG_HAVE_PSELECT', +# '-DCONFIG_HAVE_RTC', +# '-DCONFIG_HAVE_TSC', +# '-DCONFIG_HAVE_HPET', +# event handling + '-DCONFIG_HAVE_POLL', +# '-DCONFIG_HAVE_EPOLL', +# interface enumeration +# '-DCONFIG_HAVE_GETIFADDRS', +# '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg +# '-DCONFIG_HAVE_WSACMSGHDR', +# multicast + '-DCONFIG_HAVE_MCAST_JOIN', +# '-DCONFIG_HAVE_IP_MREQN', +# sprintf +# '-DCONFIG_HAVE_SPRINTF_GROUPING', +# '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE', +# GNU getopt + '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ '-pipe' + ], + LIBS = [ +# histogram math + 'm', +# clock_gettime() + 'rt', +# Solaris sockets + 'resolv', + 'socket', + 'nsl' + ], + PROTOBUF_CCFLAGS = '-I/opt/glib-gcc/include', + PROTOBUF_LIBS = '/opt/glib-gcc/lib/libprotobuf.a', + PROTOBUF_PROTOC = '/opt/glib-gcc/bin/protoc' +) +force_gcc(env); + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = ['-O2'], LINKFLAGS = []) + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG', '-ggdb'], LINKFLAGS = ['-gdb']) + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = ['-pg']) + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +if env['WITH_SNMP'] == 'true': +# net-snmp-config is broken in Solaris 10 and requires two separate calls + env['SNMP_FLAGS'] = env.ParseFlags(['!net-snmp-config-32 --cflags', + '!net-snmp-config-32 --agent-libs']); + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); +# backup = context.env.Clone().Dictionary(); + lastASFLAGS = context.env.get('ASFLAGS', ''); + lastCCFLAGS = context.env.get('CCFLAGS', ''); + lastCFLAGS = context.env.get('CFLAGS', ''); + lastCPPDEFINES = context.env.get('CPPDEFINES', ''); + lastCPPFLAGS = context.env.get('CPPFLAGS', ''); + lastCPPPATH = context.env.get('CPPPATH', ''); + lastLIBPATH = context.env.get('LIBPATH', ''); + lastLIBS = context.env.get('LIBS', ''); + lastLINKFLAGS = context.env.get('LINKFLAGS', ''); + lastRPATH = context.env.get('RPATH', ''); + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); +# context.env.Replace(**backup); + context.env.Replace(ASFLAGS = lastASFLAGS, + CCFLAGS = lastCCFLAGS, + CFLAGS = lastCFLAGS, + CPPDEFINES = lastCPPDEFINES, + CPPFLAGS = lastCPPFLAGS, + CPPPATH = lastCPPPATH, + LIBPATH = lastLIBPATH, + LIBS = lastLIBS, + LINKFLAGS = lastLINKFLAGS, + RPATH = lastRPATH); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-sungcc/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.sunstudio b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.sunstudio new file mode 100644 index 0000000..0144291 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.Solaris.sunstudio @@ -0,0 +1,322 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 1, 0 ) +SConsignFile('scons.signatures' + '-' + platform.system() + '-' + platform.machine() + '-sunstudio'); + +vars = Variables() +vars.AddVariables ( + EnumVariable ('BUILD', 'build environment', 'debug', + allowed_values=('release', 'debug', 'profile')), + EnumVariable ('BRANCH', 'branch prediction', 'none', + allowed_values=('none', 'profile', 'seed')), + EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CHECK', 'Check test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_TEST', 'Network test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CC', 'C++ examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_PLUS', 'libpgmplus GPL library', 'false', + allowed_values=('true', 'false')), +) + +#----------------------------------------------------------------------------- +# Dependencies + +def force_sunstudio(env): + env.PrependENVPath('PATH', '/usr/ccs/bin'); + env.PrependENVPath('PATH', '/opt/glib-sunstudio/bin'); + env.PrependENVPath('PATH', '/opt/sunstudio12.1/bin'); + env.Tool('sunc++'); + env.Tool('suncc'); + env.Tool('sunlink'); + env.Tool('sunar'); + +env = Environment(); +force_sunstudio(env); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' + Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' + Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' + Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment( + variables = vars, + ENV = os.environ, + CCFLAGS = [ '-v', +# C99 + '-xc99=all', + '-D_XOPEN_SOURCE=600', + '-D__EXTENSIONS__', + '-DBSD_COMP', + '-D_BSD_SOURCE', +# re-entrant libc + '-D_REENTRANT', + '-DCONFIG_HAVE_GETPROTOBYNAME_R', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header + '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system +# '-DCONFIG_HAVE_PROC', +# example: crash handling +# '-DCONFIG_HAVE_BACKTRACE', +# timing +# '-DCONFIG_HAVE_PSELECT', +# '-DCONFIG_HAVE_RTC', +# '-DCONFIG_HAVE_TSC', +# '-DCONFIG_HAVE_HPET', +# event handling + '-DCONFIG_HAVE_POLL', +# '-DCONFIG_HAVE_EPOLL', +# interface enumeration +# '-DCONFIG_HAVE_GETIFADDRS', +# '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg +# '-DCONFIG_HAVE_WSACMSGHDR', +# multicast + '-DCONFIG_HAVE_MCAST_JOIN', +# '-DCONFIG_HAVE_IP_MREQN', +# sprintf +# '-DCONFIG_HAVE_SPRINTF_GROUPING', +# '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE', +# GNU getopt + '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [], + LIBS = [ +# histogram math + 'm', +# clock_gettime() + 'rt', +# Solaris sockets + 'resolv', + 'socket', + 'nsl' + ], + PROTOBUF_CCFLAGS = '-I/opt/glib-sunstudio/include', + PROTOBUF_LIBS = '/opt/glib-sunstudio/lib/sparcv9/libprotobuf.a', + PROTOBUF_PROTOC = '/opt/glib-sunstudio/bin/protoc' +) +force_sunstudio(env); + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = ['-xO2','-m64'], LINKFLAGS = '-m64') + +# outstanding defect with 12u1 cannot compile extended asm without optimization.:w +# +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG','-xO1', '-g','-m64'], LINKFLAGS = ['-g','-m64']) + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-xO2','-pg','-m64'], LINKFLAGS = ['-pg','-m64']) + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = ['-xO2','-m32'], LINKFLAGS = '-m32'); + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +if env['WITH_SNMP'] == 'true': +# net-snmp-config is broken in Solaris 10 and requires two separate calls + env['SNMP_FLAGS'] = env.ParseFlags(['!/usr/sfw/bin/net-snmp-config-64 --cflags', + '!/usr/sfw/bin/net-snmp-config-64 --agent-libs']); + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); +# backup = context.env.Clone().Dictionary(); + lastASFLAGS = context.env.get('ASFLAGS', ''); + lastCCFLAGS = context.env.get('CCFLAGS', ''); + lastCFLAGS = context.env.get('CFLAGS', ''); + lastCPPDEFINES = context.env.get('CPPDEFINES', ''); + lastCPPFLAGS = context.env.get('CPPFLAGS', ''); + lastCPPPATH = context.env.get('CPPPATH', ''); + lastLIBPATH = context.env.get('LIBPATH', ''); + lastLIBS = context.env.get('LIBS', ''); + lastLINKFLAGS = context.env.get('LINKFLAGS', ''); + lastRPATH = context.env.get('RPATH', ''); + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); +# context.env.Replace(**backup); + context.env.Replace(ASFLAGS = lastASFLAGS, + CCFLAGS = lastCCFLAGS, + CFLAGS = lastCFLAGS, + CPPDEFINES = lastCPPDEFINES, + CPPFLAGS = lastCPPFLAGS, + CPPPATH = lastCPPPATH, + LIBPATH = lastLIBPATH, + LIBS = lastLIBS, + LINKFLAGS = lastLINKFLAGS, + RPATH = lastRPATH); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-sunstudio/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.clang b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.clang new file mode 100644 index 0000000..beed2db --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.clang @@ -0,0 +1,351 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 1, 0 ) +SConsignFile('scons.signatures' + '-' + platform.system() + '-' + platform.machine() + '-clang'); + +vars = Variables() +vars.AddVariables ( + EnumVariable ('BUILD', 'build environment', 'debug', + allowed_values=('release', 'debug', 'profile')), + EnumVariable ('BRANCH', 'branch prediction', 'none', + allowed_values=('none', 'profile', 'seed')), + EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', + allowed_values=('true', 'false')), + EnumVariable ('COVERAGE', 'test coverage', 'none', + allowed_values=('none', 'full')), + EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CHECK', 'Check test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_TEST', 'Network test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CC', 'C++ examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', + allowed_values=('true', 'false')), +) + +#----------------------------------------------------------------------------- +# Dependencies + +def force_clang(env): + env['CC'] = 'clang'; + +env = Environment(); +force_clang(env); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment( + variables = vars, + ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', +# '-Wunsafe-loop-optimizations', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', +# '-pedantic', +# C99 + '-std=gnu99', + '-D_XOPEN_SOURCE=600', + '-D_BSD_SOURCE', +# re-entrant libc + '-D_REENTRANT', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R', + '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header + '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system + '-DCONFIG_HAVE_PROC', +# example: crash handling + '-DCONFIG_HAVE_BACKTRACE', +# timing + '-DCONFIG_HAVE_PSELECT', + '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', + '-DCONFIG_HAVE_HPET', +# event handling + '-DCONFIG_HAVE_POLL', + '-DCONFIG_HAVE_EPOLL', +# interface enumeration + '-DCONFIG_HAVE_GETIFADDRS', + '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg +# '-DCONFIG_HAVE_WSACMSGHDR', +# multicast + '-DCONFIG_HAVE_MCAST_JOIN', + '-DCONFIG_HAVE_IP_MREQN', +# sprintf +# NB: raises invalid conversion specifier ''' [-Wformat] in clang +# '-DCONFIG_HAVE_SPRINTF_GROUPING', + '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE', +# GNU getopt + '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ '-pipe' + ], + LIBS = [ +# histogram math + 'm', +# clock_gettime() + 'rt' + ] +) +force_clang(env); + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Coverage analysis +if env['COVERAGE'] == 'full': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(CCFLAGS = '-ftest-coverage') + env.Append(LINKFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-lgcov') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = '-O2') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = '-gdb') + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!pkg-config --cflags --libs glib-2.0 gthread-2.0'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +if env['WITH_SNMP'] == 'true': + env['SNMP_FLAGS'] = env.ParseFlags('!net-snmp-config --cflags --agent-libs'); + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); +# backup = context.env.Clone().Dictionary(); + lastASFLAGS = context.env.get('ASFLAGS', ''); + lastCCFLAGS = context.env.get('CCFLAGS', ''); + lastCFLAGS = context.env.get('CFLAGS', ''); + lastCPPDEFINES = context.env.get('CPPDEFINES', ''); + lastCPPFLAGS = context.env.get('CPPFLAGS', ''); + lastCPPPATH = context.env.get('CPPPATH', ''); + lastLIBPATH = context.env.get('LIBPATH', ''); + lastLIBS = context.env.get('LIBS', ''); + lastLINKFLAGS = context.env.get('LINKFLAGS', ''); + lastRPATH = context.env.get('RPATH', ''); + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); +# context.env.Replace(**backup); + context.env.Replace(ASFLAGS = lastASFLAGS, + CCFLAGS = lastCCFLAGS, + CFLAGS = lastCFLAGS, + CPPDEFINES = lastCPPDEFINES, + CPPFLAGS = lastCPPFLAGS, + CPPPATH = lastCPPPATH, + LIBPATH = lastLIBPATH, + LIBS = lastLIBS, + LINKFLAGS = lastLINKFLAGS, + RPATH = lastRPATH); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +def CheckEventFD(context): + context.Message('Checking eventfd...'); + result = context.TryLink(""" +#include +int main(int argc, char**argv) +{ + eventfd(0,0); + return 0; +} +""", '.c') + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck, + 'CheckEventFD': CheckEventFD +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +if conf.CheckEventFD(): + print 'Enabling kernel eventfd notification mechanism.'; + conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-' + platform.system() + '-' + platform.machine() + '-clang/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.mingw b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.mingw new file mode 100644 index 0000000..c896256 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.mingw @@ -0,0 +1,331 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 1, 0 ) +SConsignFile('scons.signatures' + '-Win32-' + platform.machine()); + +vars = Variables() +vars.AddVariables ( + EnumVariable ('BUILD', 'build environment', 'debug', + allowed_values=('release', 'debug', 'profile')), + EnumVariable ('BRANCH', 'branch prediction', 'none', + allowed_values=('none', 'profile', 'seed')), + EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', + allowed_values=('true', 'false')), + EnumVariable ('COVERAGE', 'test coverage', 'none', + allowed_values=('none', 'full')), + EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CHECK', 'Check test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_TEST', 'Network test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CC', 'C++ examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', + allowed_values=('true', 'false')), +) + +#----------------------------------------------------------------------------- +# Dependencies + +def force_mingw(env): + env.Tool('crossmingw', toolpath=['.']); + +env = Environment(); +force_mingw(env); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment( + variables = vars, + ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', + '-Wunsafe-loop-optimizations', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', + '-pedantic', +# C99 + '-std=gnu99', + '-D_BSD_SOURCE', + '-D_WIN32_WINNT=0x0501', +# re-entrant libc + '-D_REENTRANT', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header +# '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system +# '-DCONFIG_HAVE_PROC', +# example: crash handling +# '-DCONFIG_HAVE_BACKTRACE', +# timing +# '-DCONFIG_HAVE_PSELECT', +# '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', +# '-DCONFIG_HAVE_HPET', +# event handling +# '-DCONFIG_HAVE_POLL', +# '-DCONFIG_HAVE_EPOLL', +# interface enumeration +# '-DCONFIG_HAVE_GETIFADDRS', +# '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg + '-DCONFIG_HAVE_WSACMSGHDR', +# multicast +# '-DCONFIG_HAVE_MCAST_JOIN', +# '-DCONFIG_HAVE_IP_MREQN', +# sprintf +# '-DCONFIG_HAVE_SPRINTF_GROUPING', +# '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support +# '-DCONFIG_TARGET_WINE', +# GNU getopt +# '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ '-pipe' + ], + LIBS = [ + 'iphlpapi.lib', + 'ws2_32.lib' + ] +) +force_mingw(env); + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Coverage analysis +if env['COVERAGE'] == 'full': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(CCFLAGS = '-ftest-coverage') + env.Append(LINKFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-lgcov') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = '-O2') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = ['-gdb']) + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --cflags --libs glib-2.0 gthread-2.0'); + env.MergeFlags('-Iwin/include -Lwin/lib'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +if env['WITH_SNMP'] == 'true': +# no command line helper, so hard code + env['SNMP_FLAGS'] = env.ParseFlags('-Iwin/include -Lwin/lib -lnetsnmpagent -lnetsnmphelpers -lnetsnmpmibs -lnetsnmp'); + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); + lastLIBS = context.env['LIBS']; + lastCCFLAGS= context.env['CCFLAGS']; + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); + context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +def CheckEventFD(context): + context.Message('Checking eventfd...'); + result = context.TryLink(""" +#include +int main(int argc, char**argv) +{ + eventfd(0,0); + return 0; +} +""", '.c') + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck, + 'CheckEventFD': CheckEventFD +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +if conf.CheckEventFD(): + print 'Enabling kernel eventfd notification mechanism.'; + conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-Win32-' + platform.machine() + '/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/SConstruct.mingw-wine b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.mingw-wine new file mode 100644 index 0000000..6af1e0a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/SConstruct.mingw-wine @@ -0,0 +1,339 @@ +# -*- mode: python -*- +# OpenPGM build script + +import platform +import os +import time +import sys + +EnsureSConsVersion( 1, 0 ) +SConsignFile('scons.signatures' + '-Wine-' + platform.machine()); + +vars = Variables() +vars.AddVariables ( + EnumVariable ('BUILD', 'build environment', 'debug', + allowed_values=('release', 'debug', 'profile')), + EnumVariable ('BRANCH', 'branch prediction', 'none', + allowed_values=('none', 'profile', 'seed')), + EnumVariable ('WITH_GETTEXT', 'l10n support via libintl', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_GLIB', 'Build GLib dependent modules', 'false', + allowed_values=('true', 'false')), + EnumVariable ('COVERAGE', 'test coverage', 'none', + allowed_values=('none', 'full')), + EnumVariable ('WITH_HISTOGRAMS', 'Runtime statistical information', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_HTTP', 'HTTP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_SNMP', 'SNMP administration', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CHECK', 'Check test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_TEST', 'Network test system', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_CC', 'C++ examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_EXAMPLES', 'Examples', 'true', + allowed_values=('true', 'false')), + EnumVariable ('WITH_NCURSES', 'NCURSES examples', 'false', + allowed_values=('true', 'false')), + EnumVariable ('WITH_PROTOBUF', 'Google Protocol Buffer examples', 'false', + allowed_values=('true', 'false')), +) + +#----------------------------------------------------------------------------- +# Dependencies + +def force_mingw(env): + env.Tool('crossmingw', toolpath=['.']); + +env = Environment(); +force_mingw(env); + +def CheckPKGConfig(context, version): + context.Message( 'Checking for pkg-config... ' ) + ret = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --atleast-pkgconfig-version=%s' % version)[0] + context.Result( ret ) + return ret + +def CheckPKG(context, name): + context.Message( 'Checking for %s... ' % name ) + ret = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, + 'CheckPKG' : CheckPKG }) + +if not conf.CheckPKGConfig('0.15.0'): + print 'pkg-config >= 0.15.0 not found.' +# Exit(1) + +if not conf.CheckPKG('glib-2.0 >= 2.10'): + print 'glib-2.0 >= 2.10 not found.' +# Exit(1) + +if not conf.CheckPKG('gthread-2.0'): + print 'gthread-2.0 not found.' +# Exit(1) + +env = conf.Finish(); + +#----------------------------------------------------------------------------- +# Platform specifics + +env = Environment( + variables = vars, + ENV = os.environ, + CCFLAGS = [ '-pipe', + '-Wall', + '-Wextra', + '-Wfloat-equal', + '-Wshadow', + '-Wunsafe-loop-optimizations', + '-Wpointer-arith', + '-Wbad-function-cast', + '-Wcast-qual', + '-Wcast-align', + '-Wwrite-strings', + '-Waggregate-return', + '-Wstrict-prototypes', + '-Wold-style-definition', + '-Wmissing-prototypes', + '-Wmissing-declarations', + '-Wmissing-noreturn', + '-Wmissing-format-attribute', + '-Wredundant-decls', + '-Wnested-externs', + '-Winline', + '-pedantic', +# C99 + '-std=gnu99', + '-D_GNU_SOURCE', + '-D_WIN32_WINNT=0x0501', +# re-entrant libc + '-D_REENTRANT', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R', +# '-DCONFIG_HAVE_GETPROTOBYNAME_R2', +# variadic macros + '-DCONFIG_HAVE_ISO_VARARGS', +# '-DCONFIG_HAVE_GNUC_VARARGS', +# stack memory api header +# '-DCONFIG_HAVE_ALLOCA_H', +# optimium checksum implementation +# '-DCONFIG_8BIT_CHECKSUM', + '-DCONFIG_16BIT_CHECKSUM', +# '-DCONFIG_32BIT_CHECKSUM', +# '-DCONFIG_64BIT_CHECKSUM', +# '-DCONFIG_VECTOR_CHECKSUM', +# useful /proc system +# '-DCONFIG_HAVE_PROC', +# example: crash handling +# '-DCONFIG_HAVE_BACKTRACE', +# timing +# '-DCONFIG_HAVE_PSELECT', +# '-DCONFIG_HAVE_RTC', + '-DCONFIG_HAVE_TSC', +# '-DCONFIG_HAVE_HPET', +# event handling +# '-DCONFIG_HAVE_POLL', +# '-DCONFIG_HAVE_EPOLL', +# interface enumeration +# '-DCONFIG_HAVE_GETIFADDRS', +# '-DCONFIG_HAVE_IFR_NETMASK', +# win32 cmsg +# '-DCONFIG_HAVE_WSACMSGHDR', +# multicast +# '-DCONFIG_HAVE_MCAST_JOIN', +# '-DCONFIG_HAVE_IP_MREQN', +# sprintf +# '-DCONFIG_HAVE_SPRINTF_GROUPING', +# '-DCONFIG_HAVE_VASPRINTF', +# symbol linking scope + '-DCONFIG_HAVE_DSO_VISIBILITY', +# socket binding + '-DCONFIG_BIND_INADDR_ANY', +# IP header order as per IP(4) on FreeBSD +# '-DCONFIG_HOST_ORDER_IP_LEN', +# '-DCONFIG_HOST_ORDER_IP_OFF', +# optimum galois field multiplication + '-DCONFIG_GALOIS_MUL_LUT', +# Wine limited API support + '-DCONFIG_TARGET_WINE', +# GNU getopt +# '-DCONFIG_HAVE_GETOPT' + ], + LINKFLAGS = [ '-pipe' + ], + LIBS = [ + 'iphlpapi.lib', + 'ws2_32.lib' + ] +) +force_mingw(env); + +# Branch prediction +if env['BRANCH'] == 'profile': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-fprofile-arcs') +elif env['BRANCH'] == 'seed': + env.Append(CCFLAGS = '-fbranch-probabilities') + +# Coverage analysis +if env['COVERAGE'] == 'full': + env.Append(CCFLAGS = '-fprofile-arcs') + env.Append(CCFLAGS = '-ftest-coverage') + env.Append(LINKFLAGS = '-fprofile-arcs') + env.Append(LINKFLAGS = '-lgcov') + +# Define separate build environments +release = env.Clone(BUILD = 'release') +release.Append(CCFLAGS = '-O2') + +debug = env.Clone(BUILD = 'debug') +debug.Append(CCFLAGS = ['-DPGM_DEBUG','-ggdb'], LINKFLAGS = ['-gdb']) + +profile = env.Clone(BUILD = 'profile') +profile.Append(CCFLAGS = ['-O2','-pg'], LINKFLAGS = '-pg') + +thirtytwo = release.Clone(BUILD = 'thirtytwo') +thirtytwo.Append(CCFLAGS = '-m32', LINKFLAGS = '-m32') + +# choose and environment to build +if env['BUILD'] == 'release': + Export({'env':release}) +elif env['BUILD'] == 'profile': + Export({'env':profile}) +elif env['BUILD'] == 'thirtytwo': + Export({'env':thirtytwo}) +else: + Export({'env':debug}) + +#----------------------------------------------------------------------------- +# Re-analyse dependencies + +Import('env') + +# vanilla environment +if env['WITH_GLIB'] == 'true': + env['GLIB_FLAGS'] = env.ParseFlags('!PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --cflags --libs glib-2.0 gthread-2.0'); + env.MergeFlags('-Iwin/include -Lwin/lib'); +else: + env['GLIB_FLAGS'] = ''; + +# l10n +if env['WITH_GETTEXT'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HAVE_GETTEXT'); + +# instrumentation +if env['WITH_HTTP'] == 'true' and env['WITH_HISTOGRAMS'] == 'true': + env.Append(CCFLAGS = '-DCONFIG_HISTOGRAMS'); + +# managed environment for libpgmsnmp, libpgmhttp +env['SNMP_FLAGS'] = { + 'CCFLAGS' : [], + 'LIBS' : [ 'netsnmpagent', 'netsnmpmibs', 'netsnmphelpers', 'netsnmp' ], +}; + +def CheckSNMP(context): + context.Message('Checking Net-SNMP...'); + lastLIBS = context.env['LIBS']; + lastCCFLAGS= context.env['CCFLAGS']; + context.env.MergeFlags(env['SNMP_FLAGS']); + result = context.TryLink(""" +int main(int argc, char**argv) +{ + init_agent("PGM"); + return 0; +} +""", '.c'); + context.env.Replace(LIBS = lastLIBS, CCFLAGS=lastCCFLAGS); + context.Result(not result); + return result; + +def CheckCheck(context): + context.Message('Checking Check unit test framework...'); + result = context.TryAction('PKG_CONFIG_PATH=win/lib/pkgconfig pkg-config --cflags --libs check')[0]; + context.Result(result); + return result; + +def CheckEventFD(context): + context.Message('Checking eventfd...'); + result = context.TryLink(""" +#include +int main(int argc, char**argv) +{ + eventfd(0,0); + return 0; +} +""", '.c') + context.Result(result); + return result; + +tests = { + 'CheckCheck': CheckCheck, + 'CheckEventFD': CheckEventFD +} +if env['WITH_SNMP'] == 'true': + tests['CheckSNMP'] = CheckSNMP; +conf = Configure(env, custom_tests = tests); + +if env['WITH_SNMP'] == 'true' and not conf.CheckSNMP(): + print 'Enabling extra Red Hat dependencies for Net-SNMP.'; + conf.env['SNMP_FLAGS']['LIBS'].append(['librpm', 'libsensors', 'libdl', 'libwrap']); + lastLIBS = conf.env['LIBS']; + conf.env.ParseConfig('perl -MExtUtils::Embed -e ldopts'); + conf.env['SNMP_FLAGS']['LIBS'].append(conf.env['LIBS']); + conf.env.Replace(LIBS = lastLIBS); + if not conf.CheckSNMP(): + print 'Net-SNMP libraries not compatible.'; + Exit(1); + +if env['WITH_CHECK'] == 'true' and conf.CheckCheck(): + print 'Enabling Check unit tests.'; + conf.env['CHECK'] = 'true'; +else: + print 'Disabling Check unit tests.'; + conf.env['CHECK'] = 'false'; + +if conf.CheckEventFD(): + print 'Enabling kernel eventfd notification mechanism.'; + conf.env.Append(CCFLAGS = '-DCONFIG_EVENTFD'); + +env = conf.Finish(); + +# add builder to create PIC static libraries for including in shared libraries +action_list = [ Action("$ARCOM", "$ARCOMSTR") ]; +if env.Detect('ranlib'): + ranlib_action = Action("$RANLIBCOM", "$RANLIBCOMSTR"); + action_list.append(ranlib_action); +pic_lib = Builder( action = action_list, + emitter = '$LIBEMITTER', + prefix = '$LIBPREFIX', + suffix = '$LIBSUFFIX', + src_suffix = '$OBJSUFFIX', + src_builder = 'SharedObject') +env.Append(BUILDERS = {'StaticSharedLibrary': pic_lib}); + + +#----------------------------------------------------------------------------- + +ref_node = 'ref/' + env['BUILD'] + '-Wine-' + platform.machine() + '/'; +BuildDir(ref_node, '.', duplicate=0) + +env.Append(CPPPATH = os.getcwd() + '/include'); +env.Append(LIBPATH = os.getcwd() + '/' + ref_node); + +if env['WITH_GLIB'] == 'true': + SConscript(ref_node + 'SConscript.libpgmex'); +SConscript(ref_node + 'SConscript.libpgm'); +if env['WITH_HTTP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmhttp'); +if env['WITH_SNMP'] == 'true': + SConscript(ref_node + 'SConscript.libpgmsnmp'); +if env['WITH_TEST'] == 'true': + SConscript(ref_node + 'test/SConscript'); +if env['WITH_EXAMPLES'] == 'true': + SConscript(ref_node + 'examples/SConscript'); + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/atomic_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/atomic_unittest.c new file mode 100644 index 0000000..a301c28 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/atomic_unittest.c @@ -0,0 +1,166 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for atomic operations. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include + + +/* mock state */ + + +/* mock functions for external references */ + +#define PGM_COMPILATION +#include "pgm/atomic.h" + + +/* target: + * uint32_t + * pgm_atomic_exchange_and_add32 ( + * volatile uint32_t* atomic, + * const uint32_t val + * ) + */ + +START_TEST (test_int32_exchange_and_add_pass_001) +{ + volatile uint32_t atomic = 0; + fail_unless (0 == pgm_atomic_exchange_and_add32 (&atomic, 5)); + fail_unless (5 == atomic); + fail_unless (5 == pgm_atomic_exchange_and_add32 (&atomic, (uint32_t)-10)); + fail_unless ((uint32_t)-5 == atomic); +} +END_TEST + +/* target: + * void + * pgm_atomic_add32 ( + * volatile uint32_t* atomic, + * const uint32_t val + * ) + */ + +START_TEST (test_int32_add_pass_001) +{ + volatile uint32_t atomic = (uint32_t)-5; + pgm_atomic_add32 (&atomic, 20); + fail_unless (15 == atomic); + pgm_atomic_add32 (&atomic, (uint32_t)-35); + fail_unless ((uint32_t)-20 == atomic); +} +END_TEST + +/* ensure wrap around when casting uint32 */ +START_TEST (test_int32_add_pass_002) +{ + volatile uint32_t atomic = 0; + pgm_atomic_add32 (&atomic, UINT32_MAX/2); + fail_unless ((UINT32_MAX/2) == atomic); + pgm_atomic_add32 (&atomic, UINT32_MAX - (UINT32_MAX/2)); + fail_unless (UINT32_MAX == atomic); + pgm_atomic_add32 (&atomic, 1); + fail_unless (0 == atomic); +} +END_TEST + +/* target: + * uint32_t + * pgm_atomic_read32 ( + * volatile uint32_t* atomic + * ) + */ + +START_TEST (test_int32_get_pass_001) +{ + volatile uint32_t atomic = (uint32_t)-20; + fail_unless ((uint32_t)-20 == pgm_atomic_read32 (&atomic)); +} +END_TEST + +/* target: + * void + * pgm_atomic_int32_set ( + * volatile int32_t* atomic, + * const int32_t val + * ) + */ + +START_TEST (test_int32_set_pass_001) +{ + volatile uint32_t atomic = (uint32_t)-20; + pgm_atomic_write32 (&atomic, 5); + fail_unless (5 == atomic); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_exchange_and_add = tcase_create ("exchange-and-add"); + suite_add_tcase (s, tc_exchange_and_add); + tcase_add_test (tc_exchange_and_add, test_int32_exchange_and_add_pass_001); + + TCase* tc_add = tcase_create ("add"); + suite_add_tcase (s, tc_add); + tcase_add_test (tc_add, test_int32_add_pass_001); + tcase_add_test (tc_add, test_int32_add_pass_002); + + TCase* tc_get = tcase_create ("get"); + suite_add_tcase (s, tc_get); + tcase_add_test (tc_get, test_int32_get_pass_001); + + TCase* tc_set = tcase_create ("set"); + suite_add_tcase (s, tc_set); + tcase_add_test (tc_set, test_int32_set_pass_001); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/backtrace.c b/3rdparty/openpgm-svn-r1135/pgm/backtrace.c new file mode 100644 index 0000000..86a3cd0 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/backtrace.c @@ -0,0 +1,69 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Dump back trace to stderr and try gdb. + * + * Copyright (c) 2006-2007 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef CONFIG_HAVE_BACKTRACE +# include +# include +# include +# include +#endif +#include +#include +#include + + +void +on_sigsegv ( + G_GNUC_UNUSED int signum + ) +{ +#ifdef CONFIG_HAVE_BACKTRACE + void* array[256]; + char** names; + char cmd[1024]; + int i, size; + gchar *out, *err; + gint exit_status; + + fprintf (stderr, "\n======= Backtrace: =========\n"); + + size = backtrace (array, G_N_ELEMENTS(array)); + names = backtrace_symbols (array, size); + + for (i = 0; i < size; i++) + fprintf (stderr, "%s\n", names[i]); + + free (names); + fflush (stderr); + + sprintf (cmd, "gdb --ex 'attach %ld' --ex 'info threads' --ex 'thread apply all bt' --batch", (long)getpid ()); + if ( g_spawn_command_line_sync (cmd, &out, &err, &exit_status, NULL) ) + { + fprintf (stderr, "======= GDB Backtrace: =========\n"); + fprintf (stderr, "%s\n", out); + } +#endif /* CONFIG_HAVE_BACKTRACE */ + + abort (); +} + +/* eof */ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/checksum.c b/3rdparty/openpgm-svn-r1135/pgm/checksum.c new file mode 100644 index 0000000..5e367ea --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/checksum.c @@ -0,0 +1,941 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM checksum routines + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + + +/* locals */ + +static inline uint16_t do_csum (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; +static uint16_t do_csum_8bit (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; +static uint16_t do_csum_16bit (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; +static uint16_t do_csum_32bit (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; +static uint16_t do_csum_64bit (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; +#if defined(__amd64) || defined(__x86_64__) +static uint16_t do_csum_vector (const void*, uint16_t, uint32_t) PGM_GNUC_PURE; +#endif + + +/* endian independent checksum routine + */ + +static +uint16_t +do_csum_8bit ( + const void* addr, + uint16_t len, + uint32_t csum + ) +{ + uint_fast32_t acc; + uint16_t src; + const uint8_t* buf; + + acc = csum; + buf = (const uint8_t*)addr; + while (len > 1) { +/* first byte as most significant */ + src = (*buf++) << 8; +/* second byte as least significant */ + src |= (*buf++); + acc += src; + len -= 2; + } +/* trailing odd byte */ + if (len > 0) { + src = (*buf) << 8; + acc += src; + } + acc = (acc >> 16) + (acc & 0xffff); + acc += (acc >> 16); + return htons ((uint16_t)acc); +} + +static +uint16_t +do_csumcpy_8bit ( + const void* restrict srcaddr, + void* restrict dstaddr, + uint16_t len, + uint32_t csum + ) +{ + uint_fast32_t acc; + const uint8_t*restrict srcbuf; + uint8_t*restrict dstbuf; + uint_fast16_t val16; + + acc = csum; + srcbuf = (const uint8_t*restrict)srcaddr; + dstbuf = (uint8_t*restrict)dstaddr; + while (len > 1) { +/* first byte as most significant */ + val16 = (*dstbuf++ = *srcbuf++) << 8; +/* second byte as least significant */ + val16 |= (*dstbuf++ = *srcbuf++); + acc += val16; + len -= 2; + } +/* trailing odd byte */ + if (len > 0) { + val16 = (*dstbuf = *srcbuf) << 8; + acc += val16; + } + acc = (acc >> 16) + (acc & 0xffff); + acc += (acc >> 16); + return htons ((uint16_t)acc); +} + +static +uint16_t +do_csum_16bit ( + const void* addr, + uint16_t len, + uint32_t csum + ) +{ + uint_fast32_t acc; + const uint8_t* buf; + uint16_t remainder; + uint_fast16_t count8; + bool is_odd; + + acc = csum; + buf = (const uint8_t*)addr; + remainder = 0; + + if (PGM_UNLIKELY(len == 0)) + return (uint16_t)acc; + is_odd = ((uintptr_t)buf & 1); +/* align first byte */ + if (PGM_UNLIKELY(is_odd)) { + ((uint8_t*)&remainder)[1] = *buf++; + len--; + } +/* 8-byte unrolls */ + count8 = len >> 3; + while (count8--) { + acc += ((const uint16_t*)buf)[ 0 ]; + acc += ((const uint16_t*)buf)[ 1 ]; + acc += ((const uint16_t*)buf)[ 2 ]; + acc += ((const uint16_t*)buf)[ 3 ]; + buf = &buf[ 8 ]; + } + len %= 8; +/* final 7 bytes */ + while (len > 1) { + acc += ((const uint16_t*)buf)[ 0 ]; + buf = &buf[ 2 ]; + len -= 2; + } +/* trailing odd byte */ + if (len > 0) { + ((uint8_t*)&remainder)[0] = *buf; + } + acc += remainder; + acc = (acc >> 16) + (acc & 0xffff); + acc += (acc >> 16); + if (PGM_UNLIKELY(is_odd)) + acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); + return (uint16_t)acc; +} + +static +uint16_t +do_csumcpy_16bit ( + const void* restrict srcaddr, + void* restrict dstaddr, + uint16_t len, + uint32_t csum + ) +{ + uint_fast32_t acc; + const uint8_t*restrict srcbuf; + uint8_t*restrict dstbuf; + uint16_t remainder; + uint_fast16_t count8; + bool is_odd; + + acc = csum; + srcbuf = (const uint8_t*restrict)srcaddr; + dstbuf = (uint8_t*restrict)dstaddr; + remainder = 0; + + if (PGM_UNLIKELY(len == 0)) + return (uint16_t)acc; + is_odd = ((uintptr_t)srcbuf & 1); +/* align first byte */ + if (PGM_UNLIKELY(is_odd)) { + ((uint8_t*restrict)&remainder)[1] = *dstbuf++ = *srcbuf++; + len--; + } +/* 8-byte unrolls, anything larger than 16-byte or less than 8 loses performance */ + count8 = len >> 3; + while (count8--) { + acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; + acc += ((uint16_t*restrict)dstbuf)[ 1 ] = ((const uint16_t*restrict)srcbuf)[ 1 ]; + acc += ((uint16_t*restrict)dstbuf)[ 2 ] = ((const uint16_t*restrict)srcbuf)[ 2 ]; + acc += ((uint16_t*restrict)dstbuf)[ 3 ] = ((const uint16_t*restrict)srcbuf)[ 3 ]; + srcbuf = &srcbuf[ 8 ]; + dstbuf = &dstbuf[ 8 ]; + } + len %= 8; +/* final 7 bytes */ + while (len > 1) { + acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; + srcbuf = &srcbuf[ 2 ]; + dstbuf = &dstbuf[ 2 ]; + len -= 2; + } +/* trailing odd byte */ + if (len > 0) { + ((uint8_t*restrict)&remainder)[0] = *dstbuf = *srcbuf; + } + acc += remainder; + acc = (acc >> 16) + (acc & 0xffff); + acc += (acc >> 16); + if (PGM_UNLIKELY(is_odd)) + acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); + return (uint16_t)acc; +} + +static +uint16_t +do_csum_32bit ( + const void* addr, + uint16_t len, + uint32_t csum + ) +{ + uint_fast32_t acc; + const uint8_t* buf; + uint16_t remainder; + uint_fast16_t count; + bool is_odd; + + acc = csum; + buf = (const uint8_t*)addr; + remainder = 0; + + if (PGM_UNLIKELY(len == 0)) + return (uint16_t)acc; + is_odd = ((uintptr_t)buf & 1); +/* align first byte */ + if (PGM_UNLIKELY(is_odd)) { + ((uint8_t*)&remainder)[1] = *buf++; + len--; + } +/* 16-bit words */ + count = len >> 1; + if (count) + { + if ((uintptr_t)buf & 2) { + acc += ((const uint16_t*)buf)[ 0 ]; + buf = &buf[ 2 ]; + count--; + len -= 2; + } +/* 32-bit words */ + count >>= 1; + if (count) + { + uint32_t carry = 0; + while (count) { + acc += carry; + acc += ((const uint32_t*)buf)[ 0 ]; + carry = ((const uint32_t*)buf)[ 0 ] > acc; + buf = &buf[ 4 ]; + count--; + } + acc += carry; + acc = (acc >> 16) + (acc & 0xffff); + } + if (len & 2) { + acc += ((const uint16_t*)buf)[ 0 ]; + buf = &buf[ 2 ]; + } + } +/* trailing odd byte */ + if (len & 1) { + ((uint8_t*)&remainder)[0] = *buf; + } + acc += remainder; + acc = (acc >> 16) + (acc & 0xffff); + acc += (acc >> 16); + if (PGM_UNLIKELY(is_odd)) + acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); + return (uint16_t)acc; +} + +static +uint16_t +do_csumcpy_32bit ( + const void* restrict srcaddr, + void* restrict dstaddr, + uint16_t len, + uint32_t csum + ) +{ + uint_fast32_t acc; + const uint8_t*restrict srcbuf; + uint8_t*restrict dstbuf; + uint16_t remainder; + uint_fast16_t count; + bool is_odd; + + acc = csum; + srcbuf = (const uint8_t*restrict)srcaddr; + dstbuf = (uint8_t*restrict)dstaddr; + remainder = 0; + + if (PGM_UNLIKELY(len == 0)) + return (uint16_t)acc; + is_odd = ((uintptr_t)srcbuf & 1); +/* align first byte */ + if (PGM_UNLIKELY(is_odd)) { + ((uint8_t*restrict)&remainder)[1] = *dstbuf++ = *srcbuf++; + len--; + } +/* 16-bit words */ + count = len >> 1; + if (count) + { + if ((uintptr_t)srcbuf & 2) { + acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; + srcbuf = &srcbuf[ 2 ]; + dstbuf = &dstbuf[ 2 ]; + count--; + len -= 2; + } +/* 32-bit words */ + count >>= 1; + if (count) + { + uint32_t carry = 0; + while (count) { + acc += carry; + acc += ((uint32_t*restrict)dstbuf)[ 0 ] = ((const uint32_t*restrict)srcbuf)[ 0 ]; + carry = ((const uint32_t*restrict)dstbuf)[ 0 ] > acc; + srcbuf = &srcbuf[ 4 ]; + dstbuf = &dstbuf[ 4 ]; + count--; + } + acc += carry; + acc = (acc >> 16) + (acc & 0xffff); + } + if (len & 2) { + acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; + srcbuf = &srcbuf[ 2 ]; + dstbuf = &dstbuf[ 2 ]; + } + } +/* trailing odd byte */ + if (len & 1) { + ((uint8_t*restrict)&remainder)[0] = *dstbuf = *srcbuf; + } + acc += remainder; + acc = (acc >> 16) + (acc & 0xffff); + acc += (acc >> 16); + if (PGM_UNLIKELY(is_odd)) + acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); + return (uint16_t)acc; +} + +/* best if architecture has native 64-bit words + */ + +static +uint16_t +do_csum_64bit ( + const void* addr, + uint16_t len, + uint32_t csum + ) +{ + uint_fast64_t acc; + const uint8_t* buf; + uint16_t remainder; + uint_fast16_t count; + bool is_odd; + + acc = csum; + buf = (const uint8_t*)addr; + remainder = 0; + + if (PGM_UNLIKELY(len == 0)) + return (uint16_t)acc; + is_odd = ((uintptr_t)buf & 1); +/* align first byte */ + if (PGM_UNLIKELY(is_odd)) { + ((uint8_t*)&remainder)[1] = *buf++; + len--; + } +/* 16-bit words */ + count = len >> 1; + if (count) + { + if ((uintptr_t)buf & 2) { + acc += ((const uint16_t*)buf)[ 0 ]; + buf = &buf[ 2 ]; + count--; + len -= 2; + } +/* 32-bit words */ + count >>= 1; + if (count) + { + if ((uintptr_t)buf & 4) { + acc += ((const uint32_t*)buf)[ 0 ]; + buf = &buf[ 4 ]; + count--; + len -= 4; + } +/* 64-bit words */ + count >>= 1; + if (count) + { + uint_fast64_t carry = 0; + while (count) { + acc += carry; + acc += ((const uint64_t*)buf)[ 0 ]; + carry = ((const uint64_t*)buf)[ 0 ] > acc; + buf = &buf[ 8 ]; + count--; + } + acc += carry; + acc = (acc >> 32) + (acc & 0xffffffff); + } + if (len & 4) { + acc += ((const uint32_t*)buf)[ 0 ]; + buf = &buf[ 4 ]; + } + } + if (len & 2) { + acc += ((const uint16_t*)buf)[ 0 ]; + buf = &buf[ 2 ]; + } + } +/* trailing odd byte */ + if (len & 1) { + ((uint8_t*)&remainder)[0] = *buf; + } + acc += remainder; + acc = (acc >> 32) + (acc & 0xffffffff); + acc = (acc >> 16) + (acc & 0xffff); + acc = (acc >> 16) + (acc & 0xffff); + acc += (acc >> 16); + if (PGM_UNLIKELY(is_odd)) + acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); + return (uint16_t)acc; +} + +static +uint16_t +do_csumcpy_64bit ( + const void* restrict srcaddr, + void* restrict dstaddr, + uint16_t len, + uint32_t csum + ) +{ + uint_fast64_t acc; + const uint8_t* restrict srcbuf; + uint8_t* restrict dstbuf; + uint16_t remainder; + uint_fast16_t count; + bool is_odd; + + acc = csum; + srcbuf = (const uint8_t*restrict)srcaddr; + dstbuf = (uint8_t*restrict)dstaddr; + remainder = 0; + + if (PGM_UNLIKELY(len == 0)) + return (uint16_t)acc; + is_odd = ((uintptr_t)srcbuf & 1); +/* align first byte */ + if (PGM_UNLIKELY(is_odd)) { + ((uint8_t*restrict)&remainder)[1] = *dstbuf++ = *srcbuf++; + len--; + } +/* 16-bit words */ + count = len >> 1; + if (count) + { + if ((uintptr_t)srcbuf & 2) { + acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; + srcbuf = &srcbuf[ 2 ]; + dstbuf = &dstbuf[ 2 ]; + count--; + len -= 2; + } +/* 32-bit words */ + count >>= 1; + if (count) + { + if ((uintptr_t)srcbuf & 4) { + acc += ((uint32_t*restrict)dstbuf)[ 0 ] = ((const uint32_t*restrict)srcbuf)[ 0 ]; + srcbuf = &srcbuf[ 4 ]; + dstbuf = &dstbuf[ 4 ]; + count--; + len -= 4; + } +/* 64-bit words */ + count >>= 1; + if (count) + { +/* 64-byte blocks */ + uint_fast64_t carry = 0; + uint_fast16_t count64 = count >> 3; + if (count64) + { + carry = 0; + while (count64) { + acc += carry; + acc += ((uint64_t*restrict)dstbuf)[ 0 ] = ((const uint64_t*restrict)srcbuf)[ 0 ]; + carry = ((const uint64_t*restrict)dstbuf)[ 0 ] > acc; + acc += carry; + acc += ((uint64_t*restrict)dstbuf)[ 1 ] = ((const uint64_t*restrict)srcbuf)[ 1 ]; + carry = ((const uint64_t*restrict)dstbuf)[ 1 ] > acc; + acc += carry; + acc += ((uint64_t*restrict)dstbuf)[ 2 ] = ((const uint64_t*restrict)srcbuf)[ 2 ]; + carry = ((const uint64_t*restrict)dstbuf)[ 2 ] > acc; + acc += carry; + acc += ((uint64_t*restrict)dstbuf)[ 3 ] = ((const uint64_t*restrict)srcbuf)[ 3 ]; + carry = ((const uint64_t*restrict)dstbuf)[ 3 ] > acc; + acc += carry; + acc += ((uint64_t*restrict)dstbuf)[ 4 ] = ((const uint64_t*restrict)srcbuf)[ 4 ]; + carry = ((const uint64_t*restrict)dstbuf)[ 4 ] > acc; + acc += carry; + acc += ((uint64_t*restrict)dstbuf)[ 5 ] = ((const uint64_t*restrict)srcbuf)[ 5 ]; + carry = ((const uint64_t*restrict)dstbuf)[ 5 ] > acc; + acc += carry; + acc += ((uint64_t*restrict)dstbuf)[ 6 ] = ((const uint64_t*restrict)srcbuf)[ 6 ]; + carry = ((const uint64_t*restrict)dstbuf)[ 6 ] > acc; + acc += carry; + acc += ((uint64_t*restrict)dstbuf)[ 7 ] = ((const uint64_t*restrict)srcbuf)[ 7 ]; + carry = ((const uint64_t*restrict)dstbuf)[ 7 ] > acc; + srcbuf = &srcbuf[ 64 ]; + dstbuf = &dstbuf[ 64 ]; + count64--; + } + acc += carry; + acc = (acc >> 32) + (acc & 0xffffffff); + count %= 8; + } + +/* last 56 bytes */ + carry = 0; + while (count) { + acc += carry; + acc += ((uint64_t*restrict)dstbuf)[ 0 ] = ((const uint64_t*restrict)srcbuf)[ 0 ]; + carry = ((const uint64_t*restrict)dstbuf)[ 0 ] > acc; + srcbuf = &srcbuf[ 8 ]; + dstbuf = &dstbuf[ 8 ]; + count--; + } + acc += carry; + acc = (acc >> 32) + (acc & 0xffffffff); + } + if (len & 4) { + acc += ((uint32_t*restrict)dstbuf)[ 0 ] = ((const uint32_t*restrict)srcbuf)[ 0 ]; + srcbuf = &srcbuf[ 4 ]; + dstbuf = &dstbuf[ 4 ]; + } + } + if (len & 2) { + acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; + srcbuf = &srcbuf[ 2 ]; + dstbuf = &dstbuf[ 2 ]; + } + } +/* trailing odd byte */ + if (len & 1) { + ((uint8_t*restrict)&remainder)[0] = *dstbuf = *srcbuf; + } + acc += remainder; + acc = (acc >> 32) + (acc & 0xffffffff); + acc = (acc >> 16) + (acc & 0xffff); + acc = (acc >> 16) + (acc & 0xffff); + acc += (acc >> 16); + if (PGM_UNLIKELY(is_odd)) + acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); + return (uint16_t)acc; +} + +#if defined(__amd64) || defined(__x86_64__) +/* simd instructions unique to AMD/Intel 64-bit, so always little endian. + */ + +static +uint16_t +do_csum_vector ( + const void* addr, + uint16_t len, + uint32_t csum + ) +{ + uint64_t acc; /* fixed size for asm */ + const uint8_t* buf; + uint16_t remainder; /* fixed size for endian swap */ + uint_fast16_t count; + bool is_odd; + + acc = csum; + buf = (const uint8_t*)addr; + remainder = 0; + + if (PGM_UNLIKELY(len == 0)) + return (uint16_t)acc; +/* align first byte */ + is_odd = ((uintptr_t)buf & 1); + if (PGM_UNLIKELY(is_odd)) { + ((uint8_t*)&remainder)[1] = *buf++; + len--; + } +/* 16-bit words */ + count = len >> 1; + if (count) + { + if ((uintptr_t)buf & 2) { + acc += ((const uint16_t*)buf)[ 0 ]; + buf = &buf[ 2 ]; + count--; + len -= 2; + } +/* 32-bit words */ + count >>= 1; + if (count) + { + if ((uintptr_t)buf & 4) { + acc += ((const uint32_t*)buf)[ 0 ]; + buf = &buf[ 4 ]; + count--; + len -= 4; + } +/* 64-bit words */ + count >>= 1; + if (count) + { + uint64_t carry = 0; + while (count) { + asm volatile ( "addq %1, %0\n\t" + "adcq %2, %0" + : "=r" (acc) + : "m" (*(const uint64_t*)buf), "r" (carry), "0" (acc) + : "cc" ); + buf = &buf[ 8 ]; + count--; + } + acc += carry; + acc = (acc >> 32) + (acc & 0xffffffff); + } + if (len & 4) { + acc += ((const uint32_t*)buf)[ 0 ]; + buf = &buf[ 4 ]; + } + } + if (len & 2) { + acc += ((const uint16_t*)buf)[ 0 ]; + buf = &buf[ 2 ]; + } + } +/* trailing odd byte */ + if (len & 1) { + ((uint8_t*)&remainder)[0] = *buf; + } + acc += remainder; + acc = (acc >> 32) + (acc & 0xffffffff); + acc = (acc >> 16) + (acc & 0xffff); + acc = (acc >> 16) + (acc & 0xffff); + acc += (acc >> 16); + if (PGM_UNLIKELY(is_odd)) + acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); + return (uint16_t)acc; +} + +static +uint16_t +do_csumcpy_vector ( + const void* restrict srcaddr, + void* restrict dstaddr, + uint16_t len, + uint32_t csum + ) +{ + uint64_t acc; /* fixed size for asm */ + const uint8_t*restrict srcbuf; + uint8_t*restrict dstbuf; + uint16_t remainder; /* fixed size for endian swap */ + uint_fast16_t count; + bool is_odd; + + acc = csum; + srcbuf = (const uint8_t*restrict)srcaddr; + dstbuf = (uint8_t*restrict)dstaddr; + remainder = 0; + + if (PGM_UNLIKELY(len == 0)) + return (uint16_t)acc; +/* fill cache line with source buffer, invalidate destination buffer, + * perversly for testing high temporal locality is better than no locality, + * whilst in production no locality may be preferred depending on skb re-use. + */ + pgm_prefetch (srcbuf); + pgm_prefetchw (dstbuf); +/* align first byte */ + is_odd = ((uintptr_t)srcbuf & 1); + if (PGM_UNLIKELY(is_odd)) { + ((uint8_t*restrict)&remainder)[1] = *dstbuf++ = *srcbuf++; + len--; + } +/* 16-bit words */ + count = len >> 1; + if (count) + { + if ((uintptr_t)srcbuf & 2) { + acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; + srcbuf = &srcbuf[ 2 ]; + dstbuf = &dstbuf[ 2 ]; + count--; + len -= 2; + } +/* 32-bit words */ + count >>= 1; + if (count) + { + if ((uintptr_t)srcbuf & 4) { + acc += ((uint32_t*restrict)dstbuf)[ 0 ] = ((const uint32_t*restrict)srcbuf)[ 0 ]; + srcbuf = &srcbuf[ 4 ]; + dstbuf = &dstbuf[ 4 ]; + count--; + len -= 4; + } +/* 64-bit words */ + count >>= 1; + if (count) + { +/* 64-byte blocks */ + uint64_t carry = 0; + uint_fast16_t count64 = count >> 3; + + while (count64) + { + pgm_prefetch (&srcbuf[ 64 ]); + pgm_prefetchw (&dstbuf[ 64 ]); + asm volatile ( "movq 0*8(%1), %%r8\n\t" /* load */ + "movq 1*8(%1), %%r9\n\t" + "movq 2*8(%1), %%r10\n\t" + "movq 3*8(%1), %%r11\n\t" + "movq 4*8(%1), %%r12\n\t" + "movq 5*8(%1), %%r13\n\t" + "movq 6*8(%1), %%r14\n\t" + "movq 7*8(%1), %%r15\n\t" + "adcq %%r8, %0\n\t" /* checksum */ + "adcq %%r9, %0\n\t" + "adcq %%r10, %0\n\t" + "adcq %%r11, %0\n\t" + "adcq %%r12, %0\n\t" + "adcq %%r13, %0\n\t" + "adcq %%r14, %0\n\t" + "adcq %%r15, %0\n\t" + "adcq %3, %0\n\t" + "movq %%r8, 0*8(%2)\n\t" /* save */ + "movq %%r9, 1*8(%2)\n\t" + "movq %%r10, 2*8(%2)\n\t" + "movq %%r11, 3*8(%2)\n\t" + "movq %%r12, 4*8(%2)\n\t" + "movq %%r13, 5*8(%2)\n\t" + "movq %%r14, 6*8(%2)\n\t" + "movq %%r15, 7*8(%2)" + : "=r" (acc) + : "r" (srcbuf), "r" (dstbuf), "r" (carry), "0" (acc) + : "cc", "memory", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" ); + srcbuf = &srcbuf[ 64 ]; + dstbuf = &dstbuf[ 64 ]; + count64--; + } + count %= 8; +/* last 56 bytes */ + while (count) { + asm volatile ( "addq %1, %0\n\t" + "adcq %2, %0" + : "=r" (acc) + : "m" (*(const uint64_t*restrict)srcbuf), "r" (carry), "0" (acc) + : "cc" ); + srcbuf = &srcbuf[ 8 ]; + count--; + } + acc += carry; + acc = (acc >> 32) + (acc & 0xffffffff); + } + if (len & 4) { + acc += ((uint32_t*restrict)dstbuf)[ 0 ] = ((const uint32_t*restrict)srcbuf)[ 0 ]; + srcbuf = &srcbuf[ 4 ]; + dstbuf = &dstbuf[ 4 ]; + } + } + if (len & 2) { + acc += ((uint16_t*restrict)dstbuf)[ 0 ] = ((const uint16_t*restrict)srcbuf)[ 0 ]; + srcbuf = &srcbuf[ 2 ]; + dstbuf = &dstbuf[ 2 ]; + } + } +/* trailing odd byte */ + if (len & 1) { + ((uint8_t*restrict)&remainder)[0] = *dstbuf = *srcbuf; + } + acc += remainder; + acc = (acc >> 32) + (acc & 0xffffffff); + acc = (acc >> 16) + (acc & 0xffff); + acc = (acc >> 16) + (acc & 0xffff); + acc += (acc >> 16); + if (PGM_UNLIKELY(is_odd)) + acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); + return (uint16_t)acc; +} + +#endif + +static inline +uint16_t +do_csum ( + const void* addr, + uint16_t len, + uint32_t csum + ) +{ +#if defined(CONFIG_8BIT_CHECKSUM) + return do_csum_8bit (addr, len, csum); +#elif defined(CONFIG_16BIT_CHECKSUM) + return do_csum_16bit (addr, len, csum); +#elif defined(CONFIG_32BIT_CHECKSUM) + return do_csum_32bit (addr, len, csum); +#elif defined(CONFIG_64BIT_CHECKSUM) + return do_csum_64bit (addr, len, csum); +#elif defined(CONFIG_VECTOR_CHECKSUM) + return do_csum_vector (addr, len, csum); +#else +# error "checksum routine undefined" +#endif +} + +/* Calculate an IP header style checksum + */ + +uint16_t +pgm_inet_checksum ( + const void* addr, + uint16_t len, + uint16_t csum + ) +{ +/* pre-conditions */ + pgm_assert (NULL != addr); + + return ~do_csum (addr, len, csum); +} + +/* Calculate a partial (unfolded) checksum + */ + +uint32_t +pgm_compat_csum_partial ( + const void* addr, + uint16_t len, + uint32_t csum + ) +{ +/* pre-conditions */ + pgm_assert (NULL != addr); + + csum = (csum >> 16) + (csum & 0xffff); + csum += do_csum (addr, len, 0); + csum = (csum >> 16) + (csum & 0xffff); + + return csum; +} + +/* Calculate & copy a partial PGM checksum + */ + +uint32_t +pgm_compat_csum_partial_copy ( + const void* restrict src, + void* restrict dst, + uint16_t len, + uint32_t csum + ) +{ +/* pre-conditions */ + pgm_assert (NULL != src); + pgm_assert (NULL != dst); + +#if defined(CONFIG_8BIT_CHECKSUM) + return do_csumcpy_8bit (src, dst, len, csum); +#elif defined(CONFIG_16BIT_CHECKSUM) + return do_csumcpy_16bit (src, dst, len, csum); +#elif defined(CONFIG_32BIT_CHECKSUM) + return do_csumcpy_32bit (src, dst, len, csum); +#elif defined(CONFIG_64BIT_CHECKSUM) + return do_csumcpy_64bit (src, dst, len, csum); +#elif defined(CONFIG_VECTOR_CHECKSUM) + return do_csumcpy_vector (src, dst, len, csum); +#else + memcpy (dst, src, len); + return pgm_csum_partial (dst, len, csum); +#endif +} + +/* Fold 32 bit checksum accumulator into 16 bit final value. + */ + +uint16_t +pgm_csum_fold ( + uint32_t csum + ) +{ + csum = (csum >> 16) + (csum & 0xffff); + csum += (csum >> 16); + +/* handle special case of no checksum */ + return (uint16_t)(csum == 0xffff ? csum : ~csum); +} + +/* Add together two unfolded checksum accumulators + */ + +uint32_t +pgm_csum_block_add ( + uint32_t csum, + uint32_t csum2, + const uint16_t offset + ) +{ + if (offset & 1) /* byte magic on odd offset */ + csum2 = ((csum2 & 0xff00ff) << 8) + + ((csum2 >> 8) & 0xff00ff); + + csum += csum2; + return csum + (csum < csum2); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/checksum_perftest.c b/3rdparty/openpgm-svn-r1135/pgm/checksum_perftest.c new file mode 100644 index 0000000..678a066 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/checksum_perftest.c @@ -0,0 +1,807 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * performance tests for PGM checksum routines + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include + + +/* mock state */ + +static unsigned perf_testsize = 0; +static unsigned perf_answer = 0; + + +static +void +mock_setup_100b (void) +{ + perf_testsize = 100; + perf_answer = 0x6ea8; +} + +static +void +mock_setup_200b (void) +{ + perf_testsize = 200; + perf_answer = 0x86e1; +} + +static +void +mock_setup_1500b (void) +{ + perf_testsize = 1500; + perf_answer = 0xec69; +} + +static +void +mock_setup_9kb (void) +{ + perf_testsize = 9000; + perf_answer = 0x576e; +} + +static +void +mock_setup_64kb (void) +{ + perf_testsize = 65535; + perf_answer = 0x3fc0; +} + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + +#define CHECKSUM_DEBUG +#include "checksum.c" + + +static +void +mock_setup (void) +{ + g_assert (pgm_time_init (NULL)); +} + +static +void +mock_teardown (void) +{ + g_assert (pgm_time_shutdown ()); +} + + +/* target: + * guint16 + * pgm_inet_checksum ( + * const void* src, + * guint len, + * int csum + * ) + */ + +START_TEST (test_8bit) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + csum = ~do_csum_8bit (source, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("8-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +/* checksum + memcpy */ +START_TEST (test_8bit_memcpy) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + char* target = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + memcpy (target, source, perf_testsize); + csum = ~do_csum_8bit (target, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("8-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +/* checksum & copy */ +START_TEST (test_8bit_csumcpy) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + char* target = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + csum = ~do_csumcpy_8bit (source, target, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("8-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +START_TEST (test_16bit) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + csum = ~do_csum_16bit (source, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("16-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +START_TEST (test_16bit_memcpy) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + char* target = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + memcpy (target, source, perf_testsize); + csum = ~do_csum_16bit (target, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("16-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +START_TEST (test_16bit_csumcpy) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + char* target = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + csum = ~do_csumcpy_16bit (source, target, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("16-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +START_TEST (test_32bit) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + csum = ~do_csum_32bit (source, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("32-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +START_TEST (test_32bit_memcpy) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + char* target = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + memcpy (target, source, perf_testsize); + csum = ~do_csum_32bit (target, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("32-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +START_TEST (test_32bit_csumcpy) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + char* target = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + csum = ~do_csumcpy_32bit (source, target, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("32-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +START_TEST (test_64bit) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + csum = ~do_csum_64bit (source, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("64-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +START_TEST (test_64bit_memcpy) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + char* target = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + memcpy (target, source, perf_testsize); + csum = ~do_csum_64bit (target, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("64-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +START_TEST (test_64bit_csumcpy) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + char* target = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + csum = ~do_csumcpy_64bit (source, target, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("64-bit/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +#if defined(__amd64) || defined(__x86_64__) +START_TEST (test_vector) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + csum = ~do_csum_vector (source, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("vector/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +START_TEST (test_vector_memcpy) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + char* target = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + memcpy (target, source, perf_testsize); + csum = ~do_csum_vector (target, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("vector/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST + +START_TEST (test_vector_csumcpy) +{ + const unsigned iterations = 1000; + char* source = alloca (perf_testsize); + char* target = alloca (perf_testsize); + for (unsigned i = 0, j = 0; i < perf_testsize; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = perf_answer; /* network order */ + + guint16 csum; + pgm_time_t start, check; + + start = pgm_time_update_now(); + for (unsigned i = iterations; i; i--) { + csum = ~do_csumcpy_vector (source, target, perf_testsize, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + fail_unless (answer == csum, "checksum mismatch 0x%04x (0x%04x)", csum, answer); + } + + check = pgm_time_update_now(); + g_message ("vector/%u: elapsed time %" PGM_TIME_FORMAT " us, unit time %" PGM_TIME_FORMAT " us", + perf_testsize, + (guint64)(check - start), + (guint64)((check - start) / iterations)); +} +END_TEST +#endif /* defined(__amd64) || defined(__x86_64__) */ + + + +static +Suite* +make_csum_performance_suite (void) +{ + Suite* s; + + s = suite_create ("Raw checksum performance"); + + TCase* tc_100b = tcase_create ("100b"); + suite_add_tcase (s, tc_100b); + tcase_add_checked_fixture (tc_100b, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_100b, mock_setup_100b, NULL); + tcase_add_test (tc_100b, test_8bit); + tcase_add_test (tc_100b, test_16bit); + tcase_add_test (tc_100b, test_32bit); + tcase_add_test (tc_100b, test_64bit); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_100b, test_vector); +#endif + + TCase* tc_200b = tcase_create ("200b"); + suite_add_tcase (s, tc_200b); + tcase_add_checked_fixture (tc_200b, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_200b, mock_setup_200b, NULL); + tcase_add_test (tc_200b, test_8bit); + tcase_add_test (tc_200b, test_16bit); + tcase_add_test (tc_200b, test_32bit); + tcase_add_test (tc_200b, test_64bit); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_200b, test_vector); +#endif + + TCase* tc_1500b = tcase_create ("1500b"); + suite_add_tcase (s, tc_1500b); + tcase_add_checked_fixture (tc_1500b, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_1500b, mock_setup_1500b, NULL); + tcase_add_test (tc_1500b, test_8bit); + tcase_add_test (tc_1500b, test_16bit); + tcase_add_test (tc_1500b, test_32bit); + tcase_add_test (tc_1500b, test_64bit); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_1500b, test_vector); +#endif + + TCase* tc_9kb = tcase_create ("9KB"); + suite_add_tcase (s, tc_9kb); + tcase_add_checked_fixture (tc_9kb, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_9kb, mock_setup_9kb, NULL); + tcase_add_test (tc_9kb, test_8bit); + tcase_add_test (tc_9kb, test_16bit); + tcase_add_test (tc_9kb, test_32bit); + tcase_add_test (tc_9kb, test_64bit); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_9kb, test_vector); +#endif + + TCase* tc_64kb = tcase_create ("64KB"); + suite_add_tcase (s, tc_64kb); + tcase_add_checked_fixture (tc_64kb, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_64kb, mock_setup_64kb, NULL); + tcase_add_test (tc_64kb, test_8bit); + tcase_add_test (tc_64kb, test_16bit); + tcase_add_test (tc_64kb, test_32bit); + tcase_add_test (tc_64kb, test_64bit); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_64kb, test_vector); +#endif + + return s; +} + +static +Suite* +make_csum_memcpy_performance_suite (void) +{ + Suite* s; + + s = suite_create ("Checksum and memcpy performance"); + + TCase* tc_100b = tcase_create ("100b"); + suite_add_tcase (s, tc_100b); + tcase_add_checked_fixture (tc_100b, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_100b, mock_setup_100b, NULL); + tcase_add_test (tc_100b, test_8bit_memcpy); + tcase_add_test (tc_100b, test_16bit_memcpy); + tcase_add_test (tc_100b, test_32bit_memcpy); + tcase_add_test (tc_100b, test_64bit_memcpy); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_100b, test_vector_memcpy); +#endif + + TCase* tc_200b = tcase_create ("200b"); + suite_add_tcase (s, tc_200b); + tcase_add_checked_fixture (tc_200b, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_200b, mock_setup_200b, NULL); + tcase_add_test (tc_200b, test_8bit_memcpy); + tcase_add_test (tc_200b, test_16bit_memcpy); + tcase_add_test (tc_200b, test_32bit_memcpy); + tcase_add_test (tc_200b, test_64bit_memcpy); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_200b, test_vector_memcpy); +#endif + + TCase* tc_1500b = tcase_create ("1500b"); + suite_add_tcase (s, tc_1500b); + tcase_add_checked_fixture (tc_1500b, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_1500b, mock_setup_1500b, NULL); + tcase_add_test (tc_1500b, test_8bit_memcpy); + tcase_add_test (tc_1500b, test_16bit_memcpy); + tcase_add_test (tc_1500b, test_32bit_memcpy); + tcase_add_test (tc_1500b, test_64bit_memcpy); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_1500b, test_vector_memcpy); +#endif + + TCase* tc_9kb = tcase_create ("9KB"); + suite_add_tcase (s, tc_9kb); + tcase_add_checked_fixture (tc_9kb, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_9kb, mock_setup_9kb, NULL); + tcase_add_test (tc_9kb, test_8bit_memcpy); + tcase_add_test (tc_9kb, test_16bit_memcpy); + tcase_add_test (tc_9kb, test_32bit_memcpy); + tcase_add_test (tc_9kb, test_64bit_memcpy); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_9kb, test_vector_memcpy); +#endif + + TCase* tc_64kb = tcase_create ("64KB"); + suite_add_tcase (s, tc_64kb); + tcase_add_checked_fixture (tc_64kb, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_64kb, mock_setup_64kb, NULL); + tcase_add_test (tc_64kb, test_8bit_memcpy); + tcase_add_test (tc_64kb, test_16bit_memcpy); + tcase_add_test (tc_64kb, test_32bit_memcpy); + tcase_add_test (tc_64kb, test_64bit_memcpy); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_64kb, test_vector_memcpy); +#endif + + return s; +} + +static +Suite* +make_csumcpy_performance_suite (void) +{ + Suite* s; + + s = suite_create ("Checksum copy performance"); + + TCase* tc_100b = tcase_create ("100b"); + suite_add_tcase (s, tc_100b); + tcase_add_checked_fixture (tc_100b, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_100b, mock_setup_100b, NULL); + tcase_add_test (tc_100b, test_8bit_csumcpy); + tcase_add_test (tc_100b, test_16bit_csumcpy); + tcase_add_test (tc_100b, test_32bit_csumcpy); + tcase_add_test (tc_100b, test_64bit_csumcpy); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_100b, test_vector_csumcpy); +#endif + + TCase* tc_200b = tcase_create ("200b"); + suite_add_tcase (s, tc_200b); + tcase_add_checked_fixture (tc_200b, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_200b, mock_setup_200b, NULL); + tcase_add_test (tc_200b, test_8bit_csumcpy); + tcase_add_test (tc_200b, test_16bit_csumcpy); + tcase_add_test (tc_200b, test_32bit_csumcpy); + tcase_add_test (tc_200b, test_64bit_csumcpy); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_200b, test_vector_csumcpy); +#endif + + TCase* tc_1500b = tcase_create ("1500b"); + suite_add_tcase (s, tc_1500b); + tcase_add_checked_fixture (tc_1500b, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_1500b, mock_setup_1500b, NULL); + tcase_add_test (tc_1500b, test_8bit_csumcpy); + tcase_add_test (tc_1500b, test_16bit_csumcpy); + tcase_add_test (tc_1500b, test_32bit_csumcpy); + tcase_add_test (tc_1500b, test_64bit_csumcpy); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_1500b, test_vector_csumcpy); +#endif + + TCase* tc_9kb = tcase_create ("9KB"); + suite_add_tcase (s, tc_9kb); + tcase_add_checked_fixture (tc_9kb, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_9kb, mock_setup_9kb, NULL); + tcase_add_test (tc_9kb, test_8bit_csumcpy); + tcase_add_test (tc_9kb, test_16bit_csumcpy); + tcase_add_test (tc_9kb, test_32bit_csumcpy); + tcase_add_test (tc_9kb, test_64bit_csumcpy); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_9kb, test_vector_csumcpy); +#endif + + TCase* tc_64kb = tcase_create ("64KB"); + suite_add_tcase (s, tc_64kb); + tcase_add_checked_fixture (tc_64kb, mock_setup, mock_teardown); + tcase_add_checked_fixture (tc_64kb, mock_setup_64kb, NULL); + tcase_add_test (tc_64kb, test_8bit_csumcpy); + tcase_add_test (tc_64kb, test_16bit_csumcpy); + tcase_add_test (tc_64kb, test_32bit_csumcpy); + tcase_add_test (tc_64kb, test_64bit_csumcpy); +#if defined(__amd64) || defined(__x86_64__) + tcase_add_test (tc_64kb, test_vector_csumcpy); +#endif + + return s; +} + + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_csum_performance_suite ()); + srunner_add_suite (sr, make_csum_memcpy_performance_suite ()); + srunner_add_suite (sr, make_csumcpy_performance_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/checksum_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/checksum_unittest.c new file mode 100644 index 0000000..a25d36a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/checksum_unittest.c @@ -0,0 +1,278 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for PGM checksum routines + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include + + +/* mock state */ + + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + + +#define CHECKSUM_DEBUG +#include "checksum.c" + + +/* target: + * uint16_t + * pgm_inet_checksum ( + * const void* src, + * uint16_t len, + * uint16_t csum + * ) + */ + +START_TEST (test_inet_pass_001) +{ + const char source[] = "i am not a string"; + const guint16 answer = 0x1fda; /* network order */ + + guint16 csum = pgm_inet_checksum (source, sizeof(source), 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + g_message ("IP checksum of \"%s\" (%d) is %u (%u)", + source, sizeof(source), csum, answer); + + fail_unless (answer == csum, "checksum mismatch"); +} +END_TEST + +START_TEST (test_inet_pass_002) +{ + char* source = alloca (65535); + for (unsigned i = 0, j = 0; i < 65535; i++) { + j = j * 1103515245 + 12345; + source[i] = j; + } + const guint16 answer = 0x3fc0; /* network order */ + + guint16 csum = pgm_inet_checksum (source, 65535, 0); +/* function calculates answer in host order */ + csum = g_htons (csum); + g_message ("IP checksum of 64KB is %u (%u)", + csum, answer); + + fail_unless (answer == csum, "checksum mismatch"); +} +END_TEST + +START_TEST (test_inet_fail_001) +{ + pgm_inet_checksum (NULL, 0, 0); + fail ("reached"); +} +END_TEST + +/* target: + * guint16 + * pgm_csum_fold ( + * guint32 csum + * ) + */ + +START_TEST (test_fold_pass_001) +{ + const guint32 csum = 0xdd250300; /* network order */ + const guint16 answer = 0x1fda; + + guint16 folded_csum = pgm_csum_fold (g_ntohl (csum)); + folded_csum = g_htons (folded_csum); + g_message ("32-bit checksum %u folds into %u (%u)", csum, folded_csum, answer); + + fail_unless (answer == folded_csum, "folded checksum mismatch"); +} +END_TEST + + +/* target: + * guint32 + * pgm_csum_partial ( + * const void* src, + * guint len, + * guint32 sum + * ) + */ + +START_TEST (test_partial_pass_001) +{ + const char source[] = "i am not a string"; +#if __BYTE_ORDER == __BIG_ENDIAN + const guint32 answer = 0x0000e025; /* network order */ +#elif __BYTE_ORDER == __LITTLE_ENDIAN + const guint32 answer = 0xe0250000; /* network order */ +#else +# error "__BYTE_ORDER not supported." +#endif + + guint32 csum = pgm_csum_partial (source, sizeof(source), 0); + csum = g_htonl (csum); + g_message ("Partial checksum of \"%s\" is %u (%u)", source, csum, answer); + + fail_unless (answer == csum, "checksum mismatch"); +} +END_TEST + +START_TEST (test_partial_fail_001) +{ + pgm_csum_partial (NULL, 0, 0); + fail ("reached"); +} +END_TEST + +/* target: + * guint32 + * pgm_csum_partial_copy ( + * const void* src, + * void* dst, + * guint len, + * guint32 sum + * ) + */ + +START_TEST (test_partial_copy_pass_001) +{ + const char source[] = "i am not a string"; +#if __BYTE_ORDER == __BIG_ENDIAN + const guint32 answer = 0x0000e025; /* network order */ +#elif __BYTE_ORDER == __LITTLE_ENDIAN + const guint32 answer = 0xe0250000; /* network order */ +#else +# error "__BYTE_ORDER not supported." +#endif + + char dest[1024]; + guint32 csum_source = pgm_csum_partial_copy (source, dest, sizeof(source), 0); + csum_source = g_htonl (csum_source); + guint32 csum_dest = pgm_csum_partial (dest, sizeof(source), 0); + csum_dest = g_htonl (csum_dest); + g_message ("Partial copy checksum of \"%s\" is %u, partial checksum is %u (%u)", + source, csum_source, csum_dest, answer); + fail_unless (answer == csum_source, "checksum mismatch in partial-copy"); + fail_unless (answer == csum_dest, "checksum mismatch in partial"); +} +END_TEST + +START_TEST (test_partial_copy_fail_001) +{ + pgm_csum_partial_copy (NULL, NULL, 0, 0); + fail ("reached"); +} +END_TEST + +/* target: + * guint32 + * pgm_csum_block_add ( + * guint32 csum, + * guint32 csum2, + * guint offset + * ) + */ + +START_TEST (test_block_add_pass_001) +{ + const char source[] = "i am not a string"; + const guint16 answer = 0x1fda; /* network order */ + + guint32 csum_a = pgm_csum_partial (source, sizeof(source) / 2, 0); + guint32 csum_b = pgm_csum_partial (source + (sizeof(source) / 2), sizeof(source) - (sizeof(source) / 2), 0); + guint32 csum = pgm_csum_block_add (csum_a, csum_b, sizeof(source) / 2); + guint16 fold = pgm_csum_fold (csum); +/* convert to display in network order */ + csum_a = g_htonl (csum_a); + csum_b = g_htonl (csum_b); + csum = g_htonl (csum); + fold = g_htons (fold); + g_message ("Checksum A:%u + B:%u = %u -> %u (%u)", + csum_a, csum_b, csum, fold, answer); + fail_unless (answer == fold, "checksum mismatch"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_inet = tcase_create ("inet"); + suite_add_tcase (s, tc_inet); + tcase_add_test (tc_inet, test_inet_pass_001); + tcase_add_test (tc_inet, test_inet_pass_002); + tcase_add_test_raise_signal (tc_inet, test_inet_fail_001, SIGABRT); + + TCase* tc_fold = tcase_create ("fold"); + suite_add_tcase (s, tc_fold); + tcase_add_test (tc_fold, test_fold_pass_001); + + TCase* tc_block_add = tcase_create ("block-add"); + suite_add_tcase (s, tc_block_add); + tcase_add_test (tc_block_add, test_block_add_pass_001); + + TCase* tc_partial = tcase_create ("partial"); + suite_add_tcase (s, tc_partial); + tcase_add_test (tc_partial, test_partial_pass_001); + tcase_add_test_raise_signal (tc_partial, test_partial_fail_001, SIGABRT); + + TCase* tc_partial_copy = tcase_create ("partial-copy"); + suite_add_tcase (s, tc_partial_copy); + tcase_add_test (tc_partial_copy, test_partial_copy_pass_001); + tcase_add_test_raise_signal (tc_partial_copy, test_partial_copy_fail_001, SIGABRT); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/crossmingw.py b/3rdparty/openpgm-svn-r1135/pgm/crossmingw.py new file mode 100644 index 0000000..2981506 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/crossmingw.py @@ -0,0 +1,144 @@ +import os +import os.path +import string + +import SCons.Action +import SCons.Builder +import SCons.Tool +import SCons.Util + +# This is what we search for to find mingw: +prefixes = SCons.Util.Split(""" + mingw32- + i386-mingw32msvc- + i486-mingw32msvc- + i586-mingw32msvc- + i686-mingw32msvc- +""") + +def find(env): + for prefix in prefixes: + # First search in the SCons path and then the OS path: + if env.WhereIs(prefix + 'gcc') or SCons.Util.WhereIs(prefix + 'gcc'): + return prefix + + return '' + +def shlib_generator(target, source, env, for_signature): + cmd = SCons.Util.CLVar(['$SHLINK', '$SHLINKFLAGS']) + + dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') + if dll: cmd.extend(['-o', dll]) + + cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) + + implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX') + if implib: cmd.append('-Wl,--out-implib,'+implib.get_string(for_signature)) + + def_target = env.FindIxes(target, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') + if def_target: cmd.append('-Wl,--output-def,'+def_target.get_string(for_signature)) + + return [cmd] + +def shlib_emitter(target, source, env): + dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') + no_import_lib = env.get('no_import_lib', 0) + + if not dll: + raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX") + + if not no_import_lib and \ + not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'): + + # Append an import library to the list of targets. + target.append(env.ReplaceIxes(dll, + 'SHLIBPREFIX', 'SHLIBSUFFIX', + 'LIBPREFIX', 'LIBSUFFIX')) + + # Append a def file target if there isn't already a def file target + # or a def file source. There is no option to disable def file + # target emitting, because I can't figure out why someone would ever + # want to turn it off. + def_source = env.FindIxes(source, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') + def_target = env.FindIxes(target, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') + if not def_source and not def_target: + target.append(env.ReplaceIxes(dll, + 'SHLIBPREFIX', 'SHLIBSUFFIX', + 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX')) + + return (target, source) + +# TODO: Backported to old scons version +#shlib_action = SCons.Action.CommandGenerator(shlib_generator) +shlib_action = SCons.Action.Action(shlib_generator,generator=1) + +res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR') + +res_builder = SCons.Builder.Builder(action=res_action, suffix='.o', + source_scanner=SCons.Tool.SourceFileScanner) +SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan) + +def generate(env): + mingw_prefix = find(env) + + if mingw_prefix: + dir = os.path.dirname(env.WhereIs(mingw_prefix + 'gcc') or SCons.Util.WhereIs(mingw_prefix + 'gcc')) + + # The mingw bin directory must be added to the path: + path = env['ENV'].get('PATH', []) + if not path: + path = [] + if SCons.Util.is_String(path): + path = string.split(path, os.pathsep) + + env['ENV']['PATH'] = string.join([dir] + path, os.pathsep) + + # Most of mingw is the same as gcc and friends... + gnu_tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas'] + for tool in gnu_tools: + SCons.Tool.Tool(tool)(env) + + #... but a few things differ: + env['CC'] = mingw_prefix + 'gcc' + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') + env['CXX'] = mingw_prefix + 'g++' + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') + env['SHLINKCOM'] = shlib_action + env.Append(SHLIBEMITTER = [shlib_emitter]) + # This line isn't required and breaks C++ linking + #env['LINK'] = mingw_prefix + 'g++' + env['AS'] = mingw_prefix + 'as' + env['AR'] = mingw_prefix + 'ar' + env['RANLIB'] = mingw_prefix + 'ranlib' + env['WIN32DEFPREFIX'] = '' + env['WIN32DEFSUFFIX'] = '.def' + env['SHOBJSUFFIX'] = '.o' + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + + env['RC'] = mingw_prefix + 'windres' + env['RCFLAGS'] = SCons.Util.CLVar('') + env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET)} $)' + env['RCINCPREFIX'] = '--include-dir ' + env['RCINCSUFFIX'] = '' + env['RCCOM'] = '$RC $RCINCFLAGS $RCINCPREFIX $SOURCE.dir $RCFLAGS -i $SOURCE -o $TARGET' + env['BUILDERS']['RES'] = res_builder + + # Some setting from the platform also have to be overridden: + env['OBJPREFIX'] = '' + env['OBJSUFFIX'] = '.o' + env['LIBPREFIX'] = 'lib' + env['LIBSUFFIX'] = '.a' + env['SHOBJPREFIX'] = '$OBJPREFIX' + env['SHOBJSUFFIX'] = '$OBJSUFFIX' + env['PROGPREFIX'] = '' + env['PROGSUFFIX'] = '.exe' + env['LIBPREFIX'] = '' + env['LIBSUFFIX'] = '.lib' + env['SHLIBPREFIX'] = '' + env['SHLIBSUFFIX'] = '.dll' + env['LIBPREFIXES'] = [ '$LIBPREFIX' ] + env['LIBSUFFIXES'] = [ '$LIBSUFFIX' ] + +def exists(env): + return find(env) diff --git a/3rdparty/openpgm-svn-r1135/pgm/crossmingw64.py b/3rdparty/openpgm-svn-r1135/pgm/crossmingw64.py new file mode 100644 index 0000000..111e0ed --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/crossmingw64.py @@ -0,0 +1,140 @@ +import os +import os.path +import string + +import SCons.Action +import SCons.Builder +import SCons.Tool +import SCons.Util + +# This is what we search for to find mingw: +prefixes = SCons.Util.Split(""" + x86_64-w64-mingw32- +""") + +def find(env): + for prefix in prefixes: + # First search in the SCons path and then the OS path: + if env.WhereIs(prefix + 'gcc') or SCons.Util.WhereIs(prefix + 'gcc'): + return prefix + + return '' + +def shlib_generator(target, source, env, for_signature): + cmd = SCons.Util.CLVar(['$SHLINK', '$SHLINKFLAGS']) + + dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') + if dll: cmd.extend(['-o', dll]) + + cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS']) + + implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX') + if implib: cmd.append('-Wl,--out-implib,'+implib.get_string(for_signature)) + + def_target = env.FindIxes(target, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') + if def_target: cmd.append('-Wl,--output-def,'+def_target.get_string(for_signature)) + + return [cmd] + +def shlib_emitter(target, source, env): + dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX') + no_import_lib = env.get('no_import_lib', 0) + + if not dll: + raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX") + + if not no_import_lib and \ + not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'): + + # Append an import library to the list of targets. + target.append(env.ReplaceIxes(dll, + 'SHLIBPREFIX', 'SHLIBSUFFIX', + 'LIBPREFIX', 'LIBSUFFIX')) + + # Append a def file target if there isn't already a def file target + # or a def file source. There is no option to disable def file + # target emitting, because I can't figure out why someone would ever + # want to turn it off. + def_source = env.FindIxes(source, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') + def_target = env.FindIxes(target, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX') + if not def_source and not def_target: + target.append(env.ReplaceIxes(dll, + 'SHLIBPREFIX', 'SHLIBSUFFIX', + 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX')) + + return (target, source) + +# TODO: Backported to old scons version +#shlib_action = SCons.Action.CommandGenerator(shlib_generator) +shlib_action = SCons.Action.Action(shlib_generator,generator=1) + +res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR') + +res_builder = SCons.Builder.Builder(action=res_action, suffix='.o', + source_scanner=SCons.Tool.SourceFileScanner) +SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan) + +def generate(env): + mingw_prefix = find(env) + + if mingw_prefix: + dir = os.path.dirname(env.WhereIs(mingw_prefix + 'gcc') or SCons.Util.WhereIs(mingw_prefix + 'gcc')) + + # The mingw bin directory must be added to the path: + path = env['ENV'].get('PATH', []) + if not path: + path = [] + if SCons.Util.is_String(path): + path = string.split(path, os.pathsep) + + env['ENV']['PATH'] = string.join([dir] + path, os.pathsep) + + # Most of mingw is the same as gcc and friends... + gnu_tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas'] + for tool in gnu_tools: + SCons.Tool.Tool(tool)(env) + + #... but a few things differ: + env['CC'] = mingw_prefix + 'gcc' + env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') + env['CXX'] = mingw_prefix + 'g++' + env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') + env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared') + env['SHLINKCOM'] = shlib_action + env.Append(SHLIBEMITTER = [shlib_emitter]) + # This line isn't required and breaks C++ linking + #env['LINK'] = mingw_prefix + 'g++' + env['AS'] = mingw_prefix + 'as' + env['AR'] = mingw_prefix + 'ar' + env['RANLIB'] = mingw_prefix + 'ranlib' + env['WIN32DEFPREFIX'] = '' + env['WIN32DEFSUFFIX'] = '.def' + env['SHOBJSUFFIX'] = '.o' + env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + + env['RC'] = mingw_prefix + 'windres' + env['RCFLAGS'] = SCons.Util.CLVar('') + env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET)} $)' + env['RCINCPREFIX'] = '--include-dir ' + env['RCINCSUFFIX'] = '' + env['RCCOM'] = '$RC $RCINCFLAGS $RCINCPREFIX $SOURCE.dir $RCFLAGS -i $SOURCE -o $TARGET' + env['BUILDERS']['RES'] = res_builder + + # Some setting from the platform also have to be overridden: + env['OBJPREFIX'] = '' + env['OBJSUFFIX'] = '.o' + env['LIBPREFIX'] = 'lib' + env['LIBSUFFIX'] = '.a' + env['SHOBJPREFIX'] = '$OBJPREFIX' + env['SHOBJSUFFIX'] = '$OBJSUFFIX' + env['PROGPREFIX'] = '' + env['PROGSUFFIX'] = '.exe' + env['LIBPREFIX'] = '' + env['LIBSUFFIX'] = '.lib' + env['SHLIBPREFIX'] = '' + env['SHLIBSUFFIX'] = '.dll' + env['LIBPREFIXES'] = [ '$LIBPREFIX' ] + env['LIBSUFFIXES'] = [ '$LIBSUFFIX' ] + +def exists(env): + return find(env) diff --git a/3rdparty/openpgm-svn-r1135/pgm/engine.c b/3rdparty/openpgm-svn-r1135/pgm/engine.c new file mode 100644 index 0000000..dbe50b4 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/engine.c @@ -0,0 +1,282 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM engine. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* getprotobyname_r */ +#ifndef _BSD_SOURCE +# define _BSD_SOURCE 1 +#endif + +#ifndef _WIN32 +# include +#endif +#include +#include +#include +#include +#include +#include +#include + + +//#define ENGINE_DEBUG + + +/* globals */ +int pgm_ipproto_pgm PGM_GNUC_READ_MOSTLY = IPPROTO_PGM; + +#ifdef _WIN32 +LPFN_WSARECVMSG pgm_WSARecvMsg PGM_GNUC_READ_MOSTLY = NULL; +#endif + +#ifdef PGM_DEBUG +unsigned pgm_loss_rate PGM_GNUC_READ_MOSTLY = 0; +#endif + +/* locals */ +static bool pgm_is_supported = FALSE; +static volatile uint32_t pgm_ref_count = 0; + +#ifdef _WIN32 +# ifndef WSAID_WSARECVMSG +/* http://cvs.winehq.org/cvsweb/wine/include/mswsock.h */ +# define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} +# endif +#endif + + +/* startup PGM engine, mainly finding PGM protocol definition, if any from NSS + * + * returns TRUE on success, returns FALSE if an error occurred, implying some form of + * system re-configuration is required to resolve before trying again. + * + * NB: Valgrind loves generating errors in getprotobyname(). + */ +bool +pgm_init ( + pgm_error_t** error + ) +{ + if (pgm_atomic_exchange_and_add32 (&pgm_ref_count, 1) > 0) + return TRUE; + +/* initialise dependent modules */ + pgm_messages_init(); + + pgm_minor ("OpenPGM %d.%d.%d%s%s%s %s %s %s %s", + pgm_major_version, pgm_minor_version, pgm_micro_version, + pgm_build_revision ? " (" : "", pgm_build_revision ? pgm_build_revision : "", pgm_build_revision ? ")" : "", + pgm_build_date, pgm_build_time, pgm_build_system, pgm_build_machine); + + pgm_thread_init(); + pgm_mem_init(); + pgm_rand_init(); + +#ifdef _WIN32 + WORD wVersionRequested = MAKEWORD (2, 2); + WSADATA wsaData; + if (WSAStartup (wVersionRequested, &wsaData) != 0) + { + const int save_errno = WSAGetLastError (); + pgm_set_error (error, + PGM_ERROR_DOMAIN_ENGINE, + pgm_error_from_wsa_errno (save_errno), + _("WSAStartup failure: %s"), + pgm_wsastrerror (save_errno)); + goto err_shutdown; + } + + if (LOBYTE (wsaData.wVersion) != 2 || HIBYTE (wsaData.wVersion) != 2) + { + WSACleanup(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_ENGINE, + PGM_ERROR_FAILED, + _("WSAStartup failed to provide requested version 2.2.")); + goto err_shutdown; + } + +# ifndef CONFIG_TARGET_WINE +/* find WSARecvMsg API */ + if (NULL == pgm_WSARecvMsg) { + GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; + DWORD cbBytesReturned; + const SOCKET sock = socket (AF_INET, SOCK_DGRAM, 0); + if (SOCKET_ERROR == sock) { + WSACleanup(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_ENGINE, + PGM_ERROR_FAILED, + _("Cannot open socket.")); + goto err_shutdown; + } + if (SOCKET_ERROR == WSAIoctl (sock, + SIO_GET_EXTENSION_FUNCTION_POINTER, + &WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID), + &pgm_WSARecvMsg, sizeof(pgm_WSARecvMsg), + &cbBytesReturned, + NULL, + NULL)) + { + closesocket (sock); + WSACleanup(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_ENGINE, + PGM_ERROR_FAILED, + _("WSARecvMsg function not found.")); + goto err_shutdown; + } + pgm_debug ("Retrieved address of WSARecvMsg."); + closesocket (sock); + } +# endif +#endif /* _WIN32 */ + +/* find PGM protocol id overriding default value, use first value from NIS */ +#ifdef CONFIG_HAVE_GETPROTOBYNAME_R + char b[1024]; + struct protoent protobuf; + const struct protoent* proto = getprotobyname_r ("pgm", &protobuf, b, sizeof(b)); + if (NULL != proto) { + if (proto->p_proto != pgm_ipproto_pgm) { + pgm_minor (_("Setting PGM protocol number to %i from /etc/protocols."), + proto->p_proto); + pgm_ipproto_pgm = proto->p_proto; + } + } +#elif defined(CONFIG_HAVE_GETPROTOBYNAME_R2) + char b[1024]; + struct protoent protobuf, *proto; + const int e = getprotobyname_r ("pgm", &protobuf, b, sizeof(b), &proto); + if (e != -1 && proto != NULL) { + if (proto->p_proto != pgm_ipproto_pgm) { + pgm_minor (_("Setting PGM protocol number to %i from /etc/protocols."), + proto->p_proto); + pgm_ipproto_pgm = proto->p_proto; + } + } +#else + const struct protoent *proto = getprotobyname ("pgm"); + if (proto != NULL) { + if (proto->p_proto != pgm_ipproto_pgm) { +#ifndef _WIN32 + pgm_minor (_("Setting PGM protocol number to %i from /etc/protocols."), + proto->p_proto); +#else + pgm_minor (_("Setting PGM protocol number to %i from %%SYSTEMROOT%%\\system32\\drivers\\etc\\protocols."), + proto->p_proto); +#endif + pgm_ipproto_pgm = proto->p_proto; + } + } +#endif + +/* ensure timing enabled */ + pgm_error_t* sub_error = NULL; + if (!pgm_time_init (&sub_error)) { + if (sub_error) + pgm_propagate_error (error, sub_error); +#ifdef _WIN32 + WSACleanup(); +#endif + goto err_shutdown; + } + +/* receiver simulated loss rate */ +#ifdef PGM_DEBUG + const char *loss_rate = getenv ("PGM_LOSS_RATE"); + if (NULL != loss_rate) { + int value = atoi (loss_rate); + if (value > 0 && value <= 100) { + pgm_loss_rate = value; + pgm_minor (_("Setting PGM packet loss rate to %i%%."), pgm_loss_rate); + } + } +#endif + +/* create global sock list lock */ + pgm_rwlock_init (&pgm_sock_list_lock); + + pgm_is_supported = TRUE; + return TRUE; + +err_shutdown: + pgm_rand_shutdown(); + pgm_mem_shutdown(); + pgm_thread_shutdown(); + pgm_messages_shutdown(); + pgm_atomic_dec32 (&pgm_ref_count); + return FALSE; +} + +/* returns TRUE if PGM engine has been initialized + */ + +bool +pgm_supported (void) +{ + return ( pgm_is_supported == TRUE ); +} + +/* returns TRUE on success, returns FALSE if an error occurred. + */ + +bool +pgm_shutdown (void) +{ + pgm_return_val_if_fail (pgm_atomic_read32 (&pgm_ref_count) > 0, FALSE); + + if (pgm_atomic_exchange_and_add32 (&pgm_ref_count, (uint32_t)-1) != 1) + return TRUE; + + pgm_is_supported = FALSE; + +/* destroy all open socks */ + while (pgm_sock_list) { + pgm_close ((pgm_sock_t*)pgm_sock_list->data, FALSE); + } + + pgm_time_shutdown(); + +#ifdef _WIN32 + WSACleanup(); +#endif + + pgm_rand_shutdown(); + pgm_mem_shutdown(); + pgm_thread_shutdown(); + pgm_messages_shutdown(); + return TRUE; +} + +/* helper to drop out of setuid 0 after creating PGM sockets + */ +void +pgm_drop_superuser (void) +{ +#ifndef _WIN32 + if (0 == getuid()) { + setuid((gid_t)65534); + setgid((uid_t)65534); + } +#endif +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/engine.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/engine.c.c89.patch new file mode 100644 index 0000000..30021c2 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/engine.c.c89.patch @@ -0,0 +1,58 @@ +--- engine.c 2010-05-23 15:43:35.000000000 +0800 ++++ engine.c89 2010-08-04 10:30:53.000000000 +0800 +@@ -85,6 +85,7 @@ + pgm_rand_init(); + + #ifdef _WIN32 ++ { + WORD wVersionRequested = MAKEWORD (2, 2); + WSADATA wsaData; + if (WSAStartup (wVersionRequested, &wsaData) != 0) +@@ -142,6 +143,7 @@ + closesocket (sock); + } + # endif ++ } + #endif /* _WIN32 */ + + /* find PGM protocol id overriding default value, use first value from NIS */ +@@ -168,6 +170,7 @@ + } + } + #else ++ { + const struct protoent *proto = getprotobyname ("pgm"); + if (proto != NULL) { + if (proto->p_proto != pgm_ipproto_pgm) { +@@ -181,9 +184,11 @@ + pgm_ipproto_pgm = proto->p_proto; + } + } ++ } + #endif + + /* ensure timing enabled */ ++ { + pgm_error_t* sub_error = NULL; + if (!pgm_time_init (&sub_error)) { + if (sub_error) +@@ -193,9 +198,11 @@ + #endif + goto err_shutdown; + } ++ } + + /* receiver simulated loss rate */ + #ifdef PGM_DEBUG ++ { + const char *loss_rate = getenv ("PGM_LOSS_RATE"); + if (NULL != loss_rate) { + int value = atoi (loss_rate); +@@ -204,6 +211,7 @@ + pgm_minor (_("Setting PGM packet loss rate to %i%%."), pgm_loss_rate); + } + } ++ } + #endif + + /* create global sock list lock */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/engine_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/engine_unittest.c new file mode 100644 index 0000000..13b448c --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/engine_unittest.c @@ -0,0 +1,234 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for PGM engine. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* getprotobyname_r */ +#define _BSD_SOURCE 1 + +#include +#include +#include +#include +#include + + +/* mock state */ + +struct pgm_rwlock_t; +struct pgm_slist_t; + +static gint mock_time_init = 0; +static struct pgm_rwlock_t mock_pgm_sock_list_lock; +static struct pgm_slist_t* mock_pgm_sock_list = NULL; + +#define pgm_time_init mock_pgm_time_init +#define pgm_time_shutdown mock_pgm_time_shutdown +#define pgm_close mock_pgm_close +#define pgm_sock_list_lock mock_pgm_sock_list_lock +#define pgm_sock_list mock_pgm_sock_list + +#define ENGINE_DEBUG +#include "engine.c" + + +static +void +mock_setup (void) +{ + mock_time_init = FALSE; +} + +static +void +mock_teardown (void) +{ +// null +} + + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_time_init ( + pgm_error_t** error + ) +{ + mock_time_init++; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_time_shutdown (void) +{ + if (!mock_time_init) + return FALSE; + mock_time_init--; + return TRUE; +} + +bool +mock_pgm_close ( + pgm_sock_t* sock, + bool flush + ) +{ + return TRUE; +} + + +/* target: + * bool + * pgm_init (pgm_error_t** error) + */ + +/* reference counting on init */ +START_TEST (test_init_pass_001) +{ + fail_unless (TRUE == pgm_init (NULL), "init failed"); + fail_unless (TRUE == pgm_init (NULL), "init failed"); +} +END_TEST + +/* timing module already init */ +START_TEST (test_init_pass_003) +{ + pgm_error_t* err = NULL; + fail_unless (TRUE == pgm_time_init (&err), "time-init failed: %s", (err && err->message) ? err->message : "(null)"); + fail_unless (TRUE == pgm_init (&err), "init failed: %s", (err && err->message) ? err->message : "(null)"); + fail_unless (TRUE == pgm_init (&err), "init failed: %s", (err && err->message) ? err->message : "(null)"); +} +END_TEST + +/* target: + * bool + * pgm_shutdown (void) + */ + +START_TEST (test_shutdown_pass_001) +{ + fail_unless (TRUE == pgm_init (NULL), "init failed"); + fail_unless (TRUE == pgm_shutdown (), "shutdown failed"); +} +END_TEST + +/* no init */ +START_TEST (test_shutdown_pass_002) +{ + fail_unless (FALSE == pgm_shutdown (), "shutdown failed"); +} +END_TEST + +/* double call */ +START_TEST (test_shutdown_pass_003) +{ + fail_unless (TRUE == pgm_init (NULL), "init failed"); + fail_unless (TRUE == pgm_shutdown (), "shutdown failed"); + fail_unless (FALSE == pgm_shutdown (), "shutdown failed"); +} +END_TEST + +/* check reference counting */ +START_TEST (test_shutdown_pass_004) +{ + fail_unless (TRUE == pgm_init (NULL), "init failed"); + fail_unless (TRUE == pgm_init (NULL), "init failed"); + fail_unless (TRUE == pgm_shutdown (), "shutdown failed"); + fail_unless (TRUE == pgm_shutdown (), "shutdown failed"); + fail_unless (FALSE == pgm_shutdown (), "shutdown failed"); +} +END_TEST + +/* target: + * bool + * pgm_supported (void) + */ + +START_TEST (test_supported_pass_001) +{ + fail_unless (FALSE == pgm_supported(), "supported failed"); + fail_unless (TRUE == pgm_init (NULL), "init failed"); + fail_unless (TRUE == pgm_supported(), "supported failed"); + fail_unless (TRUE == pgm_shutdown (), "shutdown failed"); + fail_unless (FALSE == pgm_supported(), "supported failed"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_init = tcase_create ("init"); + tcase_add_checked_fixture (tc_init, mock_setup, mock_teardown); + suite_add_tcase (s, tc_init); + tcase_add_test (tc_init, test_init_pass_001); + tcase_add_test (tc_init, test_init_pass_003); + + TCase* tc_shutdown = tcase_create ("shutdown"); + tcase_add_checked_fixture (tc_shutdown, mock_setup, mock_teardown); + suite_add_tcase (s, tc_shutdown); + tcase_add_test (tc_shutdown, test_shutdown_pass_001); + tcase_add_test (tc_shutdown, test_shutdown_pass_002); + tcase_add_test (tc_shutdown, test_shutdown_pass_003); + tcase_add_test (tc_shutdown, test_shutdown_pass_004); + + TCase* tc_supported = tcase_create ("supported"); + tcase_add_checked_fixture (tc_supported, mock_setup, mock_teardown); + suite_add_tcase (s, tc_supported); + tcase_add_test (tc_supported, test_supported_pass_001); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/error.c b/3rdparty/openpgm-svn-r1135/pgm/error.c new file mode 100644 index 0000000..3f3fe30 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/error.c @@ -0,0 +1,518 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable error reporting. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _WIN32 +# include +#endif +#include +#include + + +//#define ERROR_DEBUG + + +#define ERROR_OVERWRITTEN_WARNING "pgm_error_t set over the top of a previous pgm_error_t or uninitialized memory.\n" \ + "This indicates a bug. You must ensure an error is NULL before it's set.\n" \ + "The overwriting error message was: %s" + +static pgm_error_t* pgm_error_new_valist (const int, const int, const char*, va_list) PGM_GNUC_PRINTF(3, 0); +static void pgm_error_add_prefix (char**restrict, const char*restrict, va_list) PGM_GNUC_PRINTF(2, 0); + + +static +pgm_error_t* +pgm_error_new_valist ( + const int error_domain, + const int error_code, + const char* format, + va_list args + ) +{ + pgm_error_t *error = pgm_new (pgm_error_t, 1); + error->domain = error_domain; + error->code = error_code; + error->message = pgm_strdup_vprintf (format, args); + return error; +} + +void +pgm_error_free ( + pgm_error_t* error + ) +{ + pgm_return_if_fail (error != NULL); + pgm_free (error->message); + pgm_free (error); +} + +void +pgm_set_error ( + pgm_error_t** restrict err, + const int error_domain, + const int error_code, + const char* restrict format, + ... + ) +{ + pgm_error_t *new; + va_list args; + + if (NULL == err) + return; + + va_start (args, format); + new = pgm_error_new_valist (error_domain, error_code, format, args); + va_end (args); + + if (NULL == *err) + *err = new; + else + pgm_warn (_(ERROR_OVERWRITTEN_WARNING), new->message); +} + +void +pgm_propagate_error ( + pgm_error_t** restrict dest, + pgm_error_t* restrict src + ) +{ + pgm_return_if_fail (src != NULL); + + if (NULL == dest) { + if (src) + pgm_error_free (src); + return; + } else { + if (NULL != *dest) { + pgm_warn (_(ERROR_OVERWRITTEN_WARNING), src->message); + } else { + *dest = src; + } + } +} + +void +pgm_clear_error ( + pgm_error_t** err + ) +{ + if (err && *err) { + pgm_error_free (*err); + *err = NULL; + } +} + +static +void +pgm_error_add_prefix ( + char** restrict string, + const char* restrict format, + va_list ap + ) +{ + char* prefix = pgm_strdup_vprintf (format, ap); + char* oldstring = *string; + *string = pgm_strconcat (prefix, oldstring, NULL); + pgm_free (oldstring); + pgm_free (prefix); +} + +void +pgm_prefix_error ( + pgm_error_t** restrict err, + const char* restrict format, + ... + ) +{ + if (err && *err) { + va_list ap; + va_start (ap, format); + pgm_error_add_prefix (&(*err)->message, format, ap); + va_end (ap); + } +} + +/* error from libc. + */ + +int +pgm_error_from_errno ( + const int from_errno + ) +{ + switch (from_errno) { +#ifdef EAFNOSUPPORT + case EAFNOSUPPORT: + return PGM_ERROR_AFNOSUPPORT; + break; +#endif + +#ifdef EAGAIN + case EAGAIN: + return PGM_ERROR_AGAIN; + break; +#endif + +#ifdef EBADF + case EBADF: + return PGM_ERROR_BADF; + break; +#endif + +#ifdef ECONNRESET + case ECONNRESET: + return PGM_ERROR_CONNRESET; + break; +#endif + +#ifdef EFAULT + case EFAULT: + return PGM_ERROR_FAULT; + break; +#endif + +#ifdef EINTR + case EINTR: + return PGM_ERROR_INTR; + break; +#endif + +#ifdef EINVAL + case EINVAL: + return PGM_ERROR_INVAL; + break; +#endif + +#ifdef EMFILE + case EMFILE: + return PGM_ERROR_MFILE; + break; +#endif + +#ifdef ENFILE + case ENFILE: + return PGM_ERROR_NFILE; + break; +#endif + +#ifdef ENODEV + case ENODEV: + return PGM_ERROR_NODEV; + break; +#endif + +#ifdef ENOENT + case ENOENT: + return PGM_ERROR_NOENT; + break; +#endif + +#ifdef ENOMEM + case ENOMEM: + return PGM_ERROR_NOMEM; + break; +#endif + +#ifdef ENONET + case ENONET: + return PGM_ERROR_NONET; + break; +#endif + +#ifdef ENOPROTOOPT + case ENOPROTOOPT: + return PGM_ERROR_NOPROTOOPT; + break; +#endif + +#ifdef ENOTUNIQ + case ENOTUNIQ: + return PGM_ERROR_NOTUNIQ; + break; +#endif + +#ifdef ENXIO + case ENXIO: + return PGM_ERROR_NXIO; + break; +#endif + +#ifdef EPERM + case EPERM: + return PGM_ERROR_PERM; + break; +#endif + +#ifdef EPROTO + case EPROTO: + return PGM_ERROR_PROTO; + break; +#endif + +#ifdef ERANGE + case ERANGE: + return PGM_ERROR_RANGE; + break; +#endif + +#ifdef EXDEV + case EXDEV: + return PGM_ERROR_XDEV; + break; +#endif + + default : + return PGM_ERROR_FAILED; + break; + } +} + +/* h_errno from gethostbyname. + */ + +int +pgm_error_from_h_errno ( + const int from_h_errno + ) +{ + switch (from_h_errno) { +#ifdef HOST_NOT_FOUND + case HOST_NOT_FOUND: + return PGM_ERROR_NONAME; + break; +#endif + +#ifdef TRY_AGAIN + case TRY_AGAIN: + return PGM_ERROR_AGAIN; + break; +#endif + +#ifdef NO_RECOVERY + case NO_RECOVERY: + return PGM_ERROR_FAIL; + break; +#endif + +#ifdef NO_DATA + case NO_DATA: + return PGM_ERROR_NODATA; + break; +#endif + + default: + return PGM_ERROR_FAILED; + break; + } +} + +/* errno must be preserved before calling to catch correct error + * status with EAI_SYSTEM. + */ + +int +pgm_error_from_eai_errno ( + const int from_eai_errno, +#ifdef EAI_SYSTEM + const int from_errno +#else + PGM_GNUC_UNUSED const int from_errno +#endif + ) +{ + switch (from_eai_errno) { +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY: + return PGM_ERROR_ADDRFAMILY; + break; +#endif + +#ifdef EAI_AGAIN + case EAI_AGAIN: + return PGM_ERROR_AGAIN; + break; +#endif + +#ifdef EAI_BADFLAGS + case EAI_BADFLAGS: + return PGM_ERROR_INVAL; + break; +#endif + +#ifdef EAI_FAIL + case EAI_FAIL: + return PGM_ERROR_FAIL; + break; +#endif + +#ifdef EAI_FAMILY + case EAI_FAMILY: + return PGM_ERROR_AFNOSUPPORT; + break; +#endif + +#ifdef EAI_MEMORY + case EAI_MEMORY: + return PGM_ERROR_NOMEM; + break; +#endif + +#ifdef EAI_NODATA + case EAI_NODATA: + return PGM_ERROR_NODATA; + break; +#endif + +#if defined(EAI_NONAME) && EAI_NONAME != EAI_NODATA + case EAI_NONAME: + return PGM_ERROR_NONAME; + break; +#endif + +#ifdef EAI_SERVICE + case EAI_SERVICE: + return PGM_ERROR_SERVICE; + break; +#endif + +#ifdef EAI_SOCKTYPE + case EAI_SOCKTYPE: + return PGM_ERROR_SOCKTNOSUPPORT; + break; +#endif + +#ifdef EAI_SYSTEM + case EAI_SYSTEM: + return pgm_error_from_errno (from_errno); + break; +#endif + + default : + return PGM_ERROR_FAILED; + break; + } +} + +/* from WSAGetLastError() + */ + +int +pgm_error_from_wsa_errno ( + const int from_wsa_errno + ) +{ + switch (from_wsa_errno) { +#ifdef WSAEINVAL + case WSAEINVAL: + return PGM_ERROR_INVAL; + break; +#endif +#ifdef WSAEMFILE + case WSAEMFILE: + return PGM_ERROR_MFILE; + break; +#endif +#ifdef WSA_NOT_ENOUGH_MEMORY + case WSA_NOT_ENOUGH_MEMORY: + return PGM_ERROR_NOMEM; + break; +#endif +#ifdef WSAENOPROTOOPT + case WSAENOPROTOOPT: + return PGM_ERROR_NOPROTOOPT; + break; +#endif +#ifdef WSAECONNRESET + case WSAECONNRESET: + return PGM_ERROR_CONNRESET; + break; +#endif + + default : + return PGM_ERROR_FAILED; + break; + } +} + +/* from Last-Error codes, i.e. Windows non-WinSock and non-DOS errors. + */ + +int +pgm_error_from_win_errno ( + const int from_win_errno + ) +{ + switch (from_win_errno) { +#ifdef ERROR_ADDRESS_NOT_ASSOCIATED + case ERROR_ADDRESS_NOT_ASSOCIATED: + return PGM_ERROR_NODATA; + break; +#endif + +#ifdef ERROR_BUFFER_OVERFLOW + case ERROR_BUFFER_OVERFLOW: + return PGM_ERROR_NOBUFS; + break; +#endif + +#ifdef ERROR_INVALID_DATA + case ERROR_INVALID_DATA: + return PGM_ERROR_BADE; + break; +#endif + +#ifdef ERROR_INSUFFICIENT_BUFFER + case ERROR_INSUFFICIENT_BUFFER: + return PGM_ERROR_NOMEM; + break; +#endif + +#ifdef ERROR_INVALID_PARAMETER + case ERROR_INVALID_PARAMETER: + return PGM_ERROR_INVAL; + break; +#endif + +#ifdef ERROR_NOT_ENOUGH_MEMORY + case ERROR_NOT_ENOUGH_MEMORY: + return PGM_ERROR_NOMEM; + break; +#endif + +#ifdef ERROR_NO_DATA + case ERROR_NO_DATA: + return PGM_ERROR_NODATA; + break; +#endif + +#ifdef ERROR_NOT_SUPPORTED + case ERROR_NOT_SUPPORTED: + return PGM_ERROR_NOSYS; + break; +#endif + + default : + return PGM_ERROR_FAILED; + break; + } +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/error_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/error_unittest.c new file mode 100644 index 0000000..035c0f3 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/error_unittest.c @@ -0,0 +1,292 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for error reporting. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include + + +/* mock state */ + + + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + + +#define ERROR_DEBUG +#include "error.c" + + +/* target: + * void + * pgm_set_error ( + * pgm_error_t** err, + * int err_domain, + * int err_code, + * const char* format, + * ... + * ) + */ + +START_TEST (test_set_error_pass_001) +{ + pgm_error_t* err = NULL; + const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; + const gint err_code = 100; + pgm_set_error (&err, err_domain, err_code, "an error occurred."); + fail_unless (NULL != err); +} +END_TEST + +START_TEST (test_set_error_pass_002) +{ + pgm_error_t* err = NULL; + const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; + const gint err_code = 100; + pgm_set_error (&err, err_domain, err_code, "an error occurred: value=%d.", 123); + fail_unless (NULL != err); +} +END_TEST + +/* ignore NULL error */ +START_TEST (test_set_error_pass_003) +{ + pgm_error_t* err = NULL; + const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; + const gint err_code = 100; + pgm_set_error (NULL, err_domain, err_code, "an error occurred."); +} +END_TEST + +/* overwritten error */ +START_TEST (test_set_error_pass_004) +{ + pgm_error_t* err = NULL; + const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; + const gint err_code = 100; + pgm_set_error (&err, err_domain, err_code, "an error occurred."); + fail_unless (NULL != err); + pgm_set_error (&err, err_domain, err_code, "another error occurred."); +} +END_TEST + +/* target: + * void + * pgm_prefix_error ( + * pgm_error_t** err, + * const char* format, + * ... + * ) + */ + +START_TEST (test_prefix_error_pass_001) +{ + pgm_error_t* err = NULL; + const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; + const gint err_code = 100; + pgm_set_error (&err, err_domain, err_code, "an error occurred."); + fail_unless (NULL != err); + pgm_prefix_error (&err, "i am a prefix:"); + pgm_prefix_error (&err, "i am another prefix, value=%d:", 123); +} +END_TEST + +/* ignore null original error */ +START_TEST (test_prefix_error_pass_002) +{ + pgm_error_t* err = NULL; + pgm_prefix_error (&err, "i am a prefix:"); +} +END_TEST + +/* target: + * void + * pgm_propagate_error ( + * pgm_error_t** dest, + * pgm_error_t* src, + * ) + */ + +START_TEST (test_propagate_error_pass_001) +{ + pgm_error_t* dest = NULL; + pgm_error_t* err = NULL; + const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; + const gint err_code = 100; + pgm_set_error (&err, err_domain, err_code, "an error occurred."); + fail_unless (NULL != err); + pgm_propagate_error (&dest, err); + fail_unless (NULL != dest); +} +END_TEST + +/* ignore NULL destination */ +START_TEST (test_propagate_error_pass_002) +{ + pgm_error_t* err = NULL; + const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; + const gint err_code = 100; + pgm_set_error (&err, err_domain, err_code, "an error occurred."); + fail_unless (NULL != err); + pgm_propagate_error (NULL, err); +} +END_TEST + +/* src error SHOULD be valid */ +START_TEST (test_propagate_error_pass_003) +{ + pgm_error_t* dest = NULL; + pgm_error_t* err = NULL; + pgm_propagate_error (&dest, err); +} +END_TEST + +/* target: + * void + * pgm_clear_error ( + * pgm_error_t** err + * ) + */ + +START_TEST (test_clear_error_pass_001) +{ + pgm_error_t* err = NULL; + const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; + const gint err_code = 100; + pgm_set_error (&err, err_domain, err_code, "an error occurred."); + fail_unless (NULL != err); + pgm_clear_error (&err); + fail_unless (NULL == err); +} +END_TEST + +START_TEST (test_clear_error_pass_002) +{ + pgm_error_t* err = NULL; + pgm_clear_error (&err); + fail_unless (NULL == err); +} +END_TEST + +START_TEST (test_clear_error_pass_003) +{ + pgm_clear_error (NULL); +} +END_TEST + +/* target: + * void + * pgm_error_free ( + * pgm_error_t* err + * ) + */ + +START_TEST (test_error_free_pass_001) +{ + pgm_error_t* err = NULL; + const gint err_domain = PGM_ERROR_DOMAIN_ENGINE; + const gint err_code = 100; + pgm_set_error (&err, err_domain, err_code, "an error occurred."); + fail_unless (NULL != err); + pgm_error_free (err); +} +END_TEST + +START_TEST (test_error_free_pass_002) +{ + pgm_error_free (NULL); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_set_error = tcase_create ("set-error"); + suite_add_tcase (s, tc_set_error); + tcase_add_test (tc_set_error, test_set_error_pass_001); + tcase_add_test (tc_set_error, test_set_error_pass_002); + tcase_add_test (tc_set_error, test_set_error_pass_003); + tcase_add_test (tc_set_error, test_set_error_pass_004); + + TCase* tc_prefix_error = tcase_create ("prefix-error"); + suite_add_tcase (s, tc_prefix_error); + tcase_add_test (tc_prefix_error, test_prefix_error_pass_001); + tcase_add_test (tc_prefix_error, test_prefix_error_pass_002); + + TCase* tc_propagate_error = tcase_create ("propagate-error"); + suite_add_tcase (s, tc_propagate_error); + tcase_add_test (tc_propagate_error, test_propagate_error_pass_001); + tcase_add_test (tc_propagate_error, test_propagate_error_pass_002); + tcase_add_test (tc_propagate_error, test_propagate_error_pass_003); + + TCase* tc_clear_error = tcase_create ("clear-error"); + suite_add_tcase (s, tc_clear_error); + tcase_add_test (tc_clear_error, test_clear_error_pass_001); + tcase_add_test (tc_clear_error, test_clear_error_pass_002); + tcase_add_test (tc_clear_error, test_clear_error_pass_003); + + TCase* tc_error_free = tcase_create ("error-free"); + suite_add_tcase (s, tc_error_free); + tcase_add_test (tc_error_free, test_error_free_pass_001); + tcase_add_test (tc_error_free, test_error_free_pass_002); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/SConscript b/3rdparty/openpgm-svn-r1135/pgm/examples/SConscript new file mode 100644 index 0000000..46ebce3 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/SConscript @@ -0,0 +1,88 @@ +# -*- mode: python -*- +# OpenPGM build script +# $Id$ + +import os; + +Import('env'); +e = env.Clone(); +e.Prepend(LIBS = ['libpgm']); +p = e.Clone(); +if '-DCONFIG_HAVE_GETOPT' in env['CCFLAGS']: + getopt = [] +else: + getopt = ['getopt.c'] + +if e['WITH_GLIB'] == 'true': + e.Prepend(LIBS = ['libpgmex']); + e.MergeFlags(env['GLIB_FLAGS']); + e2 = e.Clone(); + if e2['WITH_SNMP'] == 'true': + e2.Append(CCFLAGS = ['-DCONFIG_WITH_SNMP']); + e2.Prepend(LIBS = ['libpgmsnmp']); + e2.MergeFlags(e['SNMP_FLAGS']); + if e2['WITH_HTTP'] == 'true': + e2.Append(CCFLAGS = ['-DCONFIG_WITH_HTTP']); + e2.Prepend(LIBS = ['libpgmhttp']); + +# core preferred examples + e.Program(['pgmdump.c']) + e2.Program(['pgmsend.c']) + e2.Program(['pgmrecv.c']) + +# sync examples + e.Program(['blocksyncrecv.c']) + e.Program(['snonblocksyncrecv.c']) + if '-DCONFIG_HAVE_POLL' in e['CCFLAGS']: + e.Program(['pnonblocksyncrecv.c']) + +# epoll based examples + if '-DCONFIG_HAVE_EPOLL' in e['CCFLAGS']: + e.Program(['enonblocksyncrecv.c']) + e.Program(['enonblocksyncrecvmsg.c']) + e.Program(['enonblocksyncrecvmsgv.c']) + +# ncurses examples + if e['WITH_NCURSES'] == 'true': + en = e.Clone() + en.Append(LIBS = ['panel', 'ncurses']); + en.Program(['pgmtop.c']) + +# Google Protocol Buffer example + if e['WITH_PROTOBUF'] == 'true': + ep = e2.Clone(); + newCCFLAGS = []; + for flag in ep['CCFLAGS']: + if ("-W" != flag[:2]) and ("-std=gnu99" != flag[:10]) and ("-pedantic" != flag[:9]) and ("-D_XOPEN_SOURCE=600" != flag[:19]) and ("-xc99=all" != flag[:9]): + newCCFLAGS.append(flag); + if ("-D_XOPEN_SOURCE=600" == flag[:19]): + newCCFLAGS.append("-D_XOPEN_SOURCE=500"); + ep['CCFLAGS'] = newCCFLAGS; + ep.Append(CPPPATH = '.'); + ep.Append(CCFLAGS = ep['PROTOBUF_CCFLAGS']); + ep.Depends('pgmping.cc', ['ping.pb.cc', 'ping.pb.h']); + protobuf = Builder(action = 'cd ${SOURCE.dir} && %s ${SOURCE.file} --cpp_out=../${TARGET.dir}' % ep['PROTOBUF_PROTOC']) + ep.Append(BUILDERS = {'Protobuf' : protobuf}) + ep.Protobuf('ping.pb.cc', 'ping.proto') + ep.Program(['pgmping.cc', 'ping.pb.cc', ep['PROTOBUF_LIBS']]) + +# Vanilla example +p.Program(['purinsend.c'] + getopt) +p.Program(['purinrecv.c'] + getopt) +p.Program(['daytime.c'] + getopt) +p.Program(['shortcakerecv.c', 'async.c'] + getopt) + +# Vanilla C++ example +if e['WITH_CC'] == 'true': + pcc = p.Clone(); + newCCFLAGS = []; + for flag in pcc['CCFLAGS']: + if ("-W" != flag[:2]) and ("-std=gnu99" != flag[:10]) and ("-pedantic" != flag[:9]) and ("-D_XOPEN_SOURCE=600" != flag[:19]) and ("-xc99=all" != flag[:9]): + newCCFLAGS.append(flag); + if ("-D_XOPEN_SOURCE=600" == flag[:19]): + newCCFLAGS.append("-D_XOPEN_SOURCE=500"); + pcc['CCFLAGS'] = newCCFLAGS; + pcc.Program('purinsendcc', ['purinsendcc.cc'] + p.Object(getopt)) + pcc.Program('purinrecvcc', ['purinrecvcc.cc'] + p.Object(getopt)) + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/SConscript89 b/3rdparty/openpgm-svn-r1135/pgm/examples/SConscript89 new file mode 100644 index 0000000..5595d3d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/SConscript89 @@ -0,0 +1,41 @@ +# -*- mode: python -*- +# OpenPGM build script +# $Id$ + +import os; + +Import('env'); +e = env.Clone(); +e.Prepend(LIBS = ['libpgm89']); +p = e.Clone(); +if '-DCONFIG_HAVE_GETOPT' in env['CCFLAGS']: + getopt = [] +else: + getopt = ['getopt.c'] + +c89source = Builder(action = 'perl -p -e "s/%z(u|d)/%l\\1/g" $SOURCE > $TARGET', + suffix = '.c89.c', + src_suffix = '.c', + single_source = 1); +p.Append(BUILDERS = {'C89Source' : c89source}) + +for c99file in ['purinsend.c', 'purinrecv.c']: + p.C89Source(c99file); + +p.Program('purinsend', ['purinsend.c89.c'] + getopt) +p.Program('purinrecv', ['purinrecv.c89.c'] + getopt) + +# Vanilla C++ example +if e['WITH_CC'] == 'true': + pcc = p.Clone(); + newCCFLAGS = []; + for flag in pcc['CCFLAGS']: + if ("-W" != flag[:2]) and ("-std=gnu99" != flag[:10]) and ("-pedantic" != flag[:9]) and ("-D_XOPEN_SOURCE=600" != flag[:19]) and ("-xc99=all" != flag[:9]): + newCCFLAGS.append(flag); + if ("-D_XOPEN_SOURCE=600" == flag[:19]): + newCCFLAGS.append("-D_XOPEN_SOURCE=500"); + pcc['CCFLAGS'] = newCCFLAGS; + pcc.Program('purinsendcc', ['purinsendcc.cc'] + p.Object(getopt)) + pcc.Program('purinrecvcc', ['purinrecvcc.cc'] + p.Object(getopt)) + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/async.c b/3rdparty/openpgm-svn-r1135/pgm/examples/async.c new file mode 100644 index 0000000..9ac15dd --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/async.c @@ -0,0 +1,441 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Asynchronous queue for receiving packets in a separate managed thread. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#ifndef _WIN32 +# include +# include +# include +#else +# include +#endif +#include + +#include "async.h" + + +/* locals */ + +struct async_event_t { + struct async_event_t *next, *prev; + size_t len; + struct pgm_sockaddr_t addr; +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) + char data[]; +#elif defined(__cplusplus) + char data[1]; +#else + char data[0]; +#endif +}; + + +static void on_data (async_t*const restrict, const void*restrict, const size_t, const struct pgm_sockaddr_t*restrict, const socklen_t); + + +/* queued data is stored as async_event_t objects + */ + +static inline +struct async_event_t* +async_event_alloc ( + size_t len + ) +{ + struct async_event_t* event; + event = (struct async_event_t*)calloc (1, len + sizeof(struct async_event_t)); + event->len = len; + return event; +} + +static inline +void +async_event_unref ( + struct async_event_t* const event + ) +{ + free (event); +} + +/* async_t implements a queue + */ + +static inline +void +async_push_event ( + async_t* restrict async, + struct async_event_t* restrict event + ) +{ + event->next = async->head; + if (async->head) + async->head->prev = event; + else + async->tail = event; + async->head = event; + async->length++; +} + +static inline +struct async_event_t* +async_pop_event ( + async_t* async + ) +{ + if (async->tail) + { + struct async_event_t *event = async->tail; + + async->tail = event->prev; + if (async->tail) + { + async->tail->next = NULL; + event->prev = NULL; + } + else + async->head = NULL; + async->length--; + + return event; + } + + return NULL; +} + +/* asynchronous receiver thread, sits in a loop processing incoming packets + */ + +static +#ifndef _WIN32 +void* +#else +unsigned +__stdcall +#endif +receiver_routine ( + void* arg + ) +{ + assert (NULL != arg); + async_t* async = (async_t*)arg; + assert (NULL != async->sock); +#ifndef _WIN32 + int fds; + fd_set readfds; +#else + int n_handles = 3, recv_sock, pending_sock; + HANDLE waitHandles[ 3 ]; + DWORD dwTimeout, dwEvents; + WSAEVENT recvEvent, pendingEvent; + socklen_t socklen = sizeof(int); + + recvEvent = WSACreateEvent (); + pgm_getsockopt (async->sock, IPPROTO_PGM, PGM_RECV_SOCK, &recv_sock, &socklen); + WSAEventSelect (recv_sock, recvEvent, FD_READ); + pendingEvent = WSACreateEvent (); + pgm_getsockopt (async->sock, IPPROTO_PGM, PGM_PENDING_SOCK, &pending_sock, &socklen); + WSAEventSelect (pending_sock, pendingEvent, FD_READ); + + waitHandles[0] = async->destroy_event; + waitHandles[1] = recvEvent; + waitHandles[2] = pendingEvent; +#endif /* !_WIN32 */ + +/* dispatch loop */ + do { + struct timeval tv; + char buffer[4096]; + size_t len; + struct pgm_sockaddr_t from; + socklen_t fromlen = sizeof (from); + const int status = pgm_recvfrom (async->sock, + buffer, + sizeof(buffer), + 0, + &len, + &from, + &fromlen, + NULL); + switch (status) { + case PGM_IO_STATUS_NORMAL: + on_data (async, buffer, len, &from, fromlen); + break; + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (async->sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (async->sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } + case PGM_IO_STATUS_WOULD_BLOCK: +/* select for next event */ +block: +#ifndef _WIN32 + fds = async->destroy_pipe[0] + 1; + FD_ZERO(&readfds); + FD_SET(async->destroy_pipe[0], &readfds); + pgm_select_info (async->sock, &readfds, NULL, &fds); + fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); +#else + dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv. +tv_usec / 1000)); + dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout); + switch (dwEvents) { + case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; + case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break; + default: break; + } +#endif /* !_WIN32 */ + break; + + default: + if (PGM_IO_STATUS_ERROR == status) + break; + } + } while (!async->is_destroyed); + +/* cleanup */ +#ifndef _WIN32 + return NULL; +#else + WSACloseEvent (recvEvent); + WSACloseEvent (pendingEvent); + _endthread(); + return 0; +#endif /* !_WIN32 */ +} + +/* enqueue a new data event. + */ + +static +void +on_data ( + async_t*const restrict async, + const void* restrict data, + const size_t len, + const struct pgm_sockaddr_t* restrict from, + const socklen_t fromlen + ) +{ + struct async_event_t* event = async_event_alloc (len); + memcpy (&event->addr, from, fromlen); + memcpy (&event->data, data, len); +#ifndef _WIN32 + pthread_mutex_lock (&async->pthread_mutex); + async_push_event (async, event); + if (1 == async->length) { + const char one = '1'; + const size_t writelen = write (async->notify_pipe[1], &one, sizeof(one)); + assert (sizeof(one) == writelen); + } + pthread_mutex_unlock (&async->pthread_mutex); +#else + WaitForSingleObject (async->win32_mutex, INFINITE); + async_push_event (async, event); + if (1 == async->length) { + SetEvent (async->notify_event); + } + ReleaseMutex (async->win32_mutex); +#endif /* _WIN32 */ +} + +/* create asynchronous thread handler from bound PGM sock. + * + * on success, 0 is returned. on error, -1 is returned, and errno set appropriately. + */ + +int +async_create ( + async_t** restrict async, + pgm_sock_t* const restrict sock + ) +{ + async_t* new_async; + + if (NULL == async || NULL == sock) { + errno = EINVAL; + return -1; + } + + new_async = (async_t*)calloc (1, sizeof(async_t)); + new_async->sock = sock; +#ifndef _WIN32 + int e; + e = pthread_mutex_init (&new_async->pthread_mutex, NULL); + if (0 != e) goto err_destroy; + e = pipe (new_async->notify_pipe); + const int flags = fcntl (new_async->notify_pipe[0], F_GETFL); + fcntl (new_async->notify_pipe[0], F_SETFL, flags | O_NONBLOCK); + if (0 != e) goto err_destroy; + e = pipe (new_async->destroy_pipe); + if (0 != e) goto err_destroy; + const int status = pthread_create (&new_async->thread, NULL, &receiver_routine, new_async); + if (0 != status) goto err_destroy; +#else + new_async->win32_mutex = CreateMutex (NULL, FALSE, NULL); + new_async->notify_event = CreateEvent (NULL, TRUE, FALSE, TEXT("AsyncNotify")); + new_async->destroy_event = CreateEvent (NULL, TRUE, FALSE, TEXT("AsyncDestroy")); + new_async->thread = (HANDLE)_beginthreadex (NULL, 0, &receiver_routine, new_async, 0, NULL); + if (0 == new_async->thread) goto err_destroy; +#endif /* _WIN32 */ + +/* return new object */ + *async = new_async; + return 0; + +err_destroy: +#ifndef _WIN32 + close (new_async->destroy_pipe[0]); + close (new_async->destroy_pipe[1]); + close (new_async->notify_pipe[0]); + close (new_async->notify_pipe[1]); + pthread_mutex_destroy (&new_async->pthread_mutex); +#else + CloseHandle (new_async->destroy_event); + CloseHandle (new_async->notify_event); + CloseHandle (new_async->win32_mutex); +#endif /* _WIN32 */ + if (new_async) + free (new_async); + return -1; +} + +/* Destroy asynchronous receiver, there must be no active queue consumer. + * + * on success, 0 is returned, on error -1 is returned and errno set appropriately. + */ + +int +async_destroy ( + async_t* const async + ) +{ + if (NULL == async || async->is_destroyed) { + errno = EINVAL; + return -1; + } + + async->is_destroyed = TRUE; +#ifndef _WIN32 + const char one = '1'; + const size_t writelen = write (async->destroy_pipe[1], &one, sizeof(one)); + assert (sizeof(one) == writelen); + pthread_join (async->thread, NULL); + close (async->destroy_pipe[0]); + close (async->destroy_pipe[1]); + close (async->notify_pipe[0]); + close (async->notify_pipe[1]); + pthread_mutex_destroy (&async->pthread_mutex); +#else + SetEvent (async->destroy_event); + WaitForSingleObject (async->thread, INFINITE); + CloseHandle (async->thread); + CloseHandle (async->destroy_event); + CloseHandle (async->notify_event); + CloseHandle (async->win32_mutex); +#endif /* !_WIN32 */ + while (async->head) { + struct async_event_t *next = async->head->next; + async_event_unref (async->head); + async->head = next; + async->length--; + } + free (async); + return 0; +} + +/* synchronous reading from the queue. + * + * returns GIOStatus with success, error, again, or eof. + */ + +ssize_t +async_recvfrom ( + async_t* const restrict async, + void* restrict buf, + size_t len, + struct pgm_sockaddr_t* restrict from, + socklen_t* restrict fromlen + ) +{ + struct async_event_t* event; + + if (NULL == async || NULL == buf || async->is_destroyed) { + errno = EINVAL; + return -1; + } + +#ifndef _WIN32 + pthread_mutex_lock (&async->pthread_mutex); + if (0 == async->length) { +/* flush event pipe */ + char tmp; + while (sizeof(tmp) == read (async->notify_pipe[0], &tmp, sizeof(tmp))); + pthread_mutex_unlock (&async->pthread_mutex); + errno = EAGAIN; + return -1; + } + event = async_pop_event (async); + pthread_mutex_unlock (&async->pthread_mutex); +#else + WaitForSingleObject (async->win32_mutex, INFINITE); + if (0 == async->length) { +/* clear event */ + ResetEvent (async->notify_event); + ReleaseMutex (async->win32_mutex); + errno = EAGAIN; + return -1; + } + event = async_pop_event (async); + ReleaseMutex (async->win32_mutex); +#endif /* _WIN32 */ + assert (NULL != event); + +/* pass data back to callee */ + const size_t event_len = MIN(event->len, len); + if (NULL != from && sizeof(struct pgm_sockaddr_t) == *fromlen) { + memcpy (from, &event->addr, *fromlen); + } + memcpy (buf, event->data, event_len); + async_event_unref (event); + return event_len; +} + +ssize_t +async_recv ( + async_t* const restrict async, + void* restrict buf, + size_t len + ) +{ + return async_recvfrom (async, buf, len, NULL, NULL); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/async.h b/3rdparty/openpgm-svn-r1135/pgm/examples/async.h new file mode 100644 index 0000000..788a777 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/async.h @@ -0,0 +1,82 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Asynchronous receive thread helper + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_ASYNC_H__ +#define __PGM_ASYNC_H__ + +struct async_event_t; + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct async_t { + pgm_sock_t* sock; +#ifndef _WIN32 + pthread_t thread; + int notify_pipe[2]; + int destroy_pipe[2]; + pthread_mutex_t pthread_mutex; +#else + HANDLE thread; + HANDLE notify_event; + HANDLE destroy_event; + HANDLE win32_mutex; +#endif + struct async_event_t *head, *tail; + unsigned length; + bool is_destroyed; +}; +typedef struct async_t async_t; + +int async_create (async_t** restrict, pgm_sock_t*const restrict); +int async_destroy (async_t* const); +ssize_t async_recv (async_t*const restrict, void* restrict, size_t); +ssize_t async_recvfrom (async_t*const restrict, void*restrict, size_t, struct pgm_sockaddr_t*restrict, socklen_t*restrict); + +#ifndef _WIN32 +static inline int async_get_fd (async_t* async) +{ + if (NULL == async) { + errno = EINVAL; + return -1; + } + return async->notify_pipe[0]; +} +#else +static inline HANDLE async_get_event (async_t* async) +{ + if (NULL == async) { + errno = EINVAL; + return NULL; + } + return async->notify_event; +} +#endif /* _WIN32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* __PGM_ASYNC_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/blocksyncrecv.c b/3rdparty/openpgm-svn-r1135/pgm/examples/blocksyncrecv.c new file mode 100644 index 0000000..dec87be --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/blocksyncrecv.c @@ -0,0 +1,350 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Simple PGM receiver: blocking synchronous receiver + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#ifndef G_OS_WIN32 +# include +#else +# include "getopt.h" +#endif +#include + +/* example dependencies */ +#include +#include + + +/* typedefs */ + +/* globals */ + +static int g_port = 0; +static const char* g_network = ""; +static gboolean g_multicast_loop = FALSE; +static int g_udp_encap_port = 0; + +static int g_max_tpdu = 1500; +static int g_sqns = 100; + +static pgm_sock_t* g_sock = NULL; +static gboolean g_quit = FALSE; + +#ifdef G_OS_UNIX +static void on_signal (int); +#else +static BOOL on_console_ctrl (DWORD); +#endif +static gboolean on_startup (void); +static int on_data (gconstpointer, size_t, struct pgm_sockaddr_t*); + + +G_GNUC_NORETURN static +void +usage ( + const char* bin + ) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); + exit (1); +} + +int +main ( + int argc, + char* argv[] + ) +{ + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + + log_init (); + g_message ("blocksyncrecv"); + + if (!pgm_init (&pgm_err)) { + g_error ("Unable to start PGM engine: %s", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) + { + switch (c) { + case 'n': g_network = optarg; break; + case 's': g_port = atoi (optarg); break; + case 'p': g_udp_encap_port = atoi (optarg); break; + case 'l': g_multicast_loop = TRUE; break; + + case 'h': + case '?': usage (binary_name); + } + } + +/* setup signal handlers */ + signal(SIGSEGV, on_sigsegv); +#ifdef SIGHUP + signal(SIGHUP, SIG_IGN); +#endif +#ifdef G_OS_UNIX + signal(SIGINT, on_signal); + signal(SIGTERM, on_signal); +#else + SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); +#endif + + on_startup(); + +/* dispatch loop */ + g_message ("entering PGM message loop ... "); + do { + char buffer[4096]; + size_t len; + struct pgm_sockaddr_t from; + socklen_t fromlen = sizeof(from); + const int status = pgm_recvfrom (g_sock, + buffer, + sizeof(buffer), + 0, + &len, + &from, + &fromlen, + &pgm_err); + if (PGM_IO_STATUS_NORMAL == status) + on_data (buffer, len, &from); + else { + if (pgm_err) { + g_warning ("%s", pgm_err->message); + pgm_error_free (pgm_err); + pgm_err = NULL; + } + if (PGM_IO_STATUS_ERROR == status) + break; + } + } while (!g_quit); + + g_message ("message loop terminated, cleaning up."); + +/* cleanup */ + if (g_sock) { + g_message ("closing PGM socket."); + pgm_close (g_sock, TRUE); + g_sock = NULL; + } + + g_message ("PGM engine shutdown."); + pgm_shutdown (); + g_message ("finished."); + return EXIT_SUCCESS; +} + +#ifdef G_OS_UNIX +static +void +on_signal ( + int signum + ) +{ + g_message ("on_signal (signum:%d)", signum); + g_quit = TRUE; +} +#else +static +BOOL +on_console_ctrl ( + DWORD dwCtrlType + ) +{ + g_message ("on_console_ctrl (dwCtrlType:%lu)", (unsigned long)dwCtrlType); + g_quit = TRUE; + return TRUE; +} +#endif /* !G_OS_UNIX */ + +static +gboolean +on_startup (void) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + + g_message ("startup."); + +/* parse network parameter into transport address structure */ + if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { + g_error ("parsing network parameter: %s", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + if (g_udp_encap_port) { + g_message ("create PGM/UDP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + } else { + g_message ("create PGM/IP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int recv_only = 1, + passive = 0, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PASSIVE, &passive, sizeof(passive)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + g_error ("creating GSI: %s", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (g_sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + g_error ("binding PGM socket: %s", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int blocking = 0, + multicast_loop = g_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NOBLOCK, &blocking, sizeof(blocking)); + + if (!pgm_connect (g_sock, &pgm_err)) { + g_error ("connecting PGM socket: %s", pgm_err->message); + goto err_abort; + } + + g_message ("startup complete."); + return TRUE; + +err_abort: + if (NULL != g_sock) { + pgm_close (g_sock, FALSE); + g_sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +static +int +on_data ( + gconstpointer data, + size_t len, + struct pgm_sockaddr_t* from + ) +{ +/* protect against non-null terminated strings */ + char buf[1024], tsi[PGM_TSISTRLEN]; + const size_t buflen = MIN( sizeof(buf) - 1, len ); + strncpy (buf, data, buflen); + buf[buflen] = '\0'; + pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); + + g_message ("\"%s\" (%u bytes from %s)", + buf, + (unsigned)len, + tsi); + + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/daytime.c b/3rdparty/openpgm-svn-r1135/pgm/examples/daytime.c new file mode 100644 index 0000000..52779a9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/daytime.c @@ -0,0 +1,546 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Daytime broadcast service. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +# include +# include +# include +#else +# include +# include +# include "getopt.h" +# define snprintf _snprintf +#endif +#include + + +/* globals */ +#define TIME_FORMAT "%a, %d %b %Y %H:%M:%S %z" + +static int port = 0; +static const char* network = ""; +static bool use_multicast_loop = FALSE; +static int udp_encap_port = 0; + +static int max_tpdu = 1500; +static int max_rte = 400*1000; /* very conservative rate, 2.5mb/s */ +static int sqns = 100; + +static bool use_pgmcc = FALSE; +static bool use_fec = FALSE; +static bool use_ondemand_parity = FALSE; +static int proactive_packets = 0; +static int rs_k = 8; +static int rs_n = 255; + +static pgm_sock_t* sock = NULL; +static bool is_terminated = FALSE; + +#ifndef _WIN32 +static pthread_t nak_thread; +static int terminate_pipe[2]; +static void on_signal (int); +static void* nak_routine (void*); +#else +static HANDLE nak_thread; +static HANDLE terminate_event; +static BOOL on_console_ctrl (DWORD); +static unsigned __stdcall nak_routine (void*); +#endif +#ifndef _MSC_VER +static void usage (const char*) __attribute__((__noreturn__)); +#else +static void usage (const char*); +#endif + +static bool on_startup (void); +static bool create_sock (void); +static bool create_nak_thread (void); + + +static void +usage ( + const char* bin + ) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -r : Regulate to rate bytes per second\n"); + fprintf (stderr, " -c : Enable PGMCC\n"); + fprintf (stderr, " -f : Enable FEC: proactive, ondemand, or both\n"); + fprintf (stderr, " -N : Reed-Solomon block size (255)\n"); + fprintf (stderr, " -K : Reed-Solomon group size (8)\n"); + fprintf (stderr, " -P : Number of pro-active parity packets (h)\n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); + fprintf (stderr, " -i : List available interfaces\n"); + exit (EXIT_SUCCESS); +} + +int +main ( + int argc, + char *argv[] + ) +{ + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + + puts ("PGM daytime service"); + + if (!pgm_init (&pgm_err)) { + fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:p:r:cf:N:K:P:lih")) != -1) + { + switch (c) { + case 'n': network = optarg; break; + case 's': port = atoi (optarg); break; + case 'p': udp_encap_port = atoi (optarg); break; + case 'r': max_rte = atoi (optarg); break; + case 'c': use_pgmcc = TRUE; break; + case 'f': + use_fec = TRUE; + switch (optarg[0]) { + case 'p': + case 'P': + proactive_packets = 1; + break; + case 'b': + case 'B': + proactive_packets = 1; + case 'o': + case 'O': + use_ondemand_parity = TRUE; + break; + } + break; + case 'N': rs_n = atoi (optarg); break; + case 'K': rs_k = atoi (optarg); break; + case 'P': proactive_packets = atoi (optarg); break; + + case 'l': use_multicast_loop = TRUE; break; + + case 'i': + pgm_if_print_all(); + return EXIT_SUCCESS; + + case 'h': + case '?': + usage (binary_name); + } + } + + if (use_fec && ( !rs_n || !rs_k )) { + fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); + usage (binary_name); + } + +/* setup signal handlers */ +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif +#ifndef _WIN32 + int e = pipe (terminate_pipe); + assert (0 == e); + const int flags = fcntl (terminate_pipe[0], F_GETFL); + fcntl (terminate_pipe[0], F_SETFL, flags | O_NONBLOCK); + signal (SIGINT, on_signal); + signal (SIGTERM, on_signal); +#else + terminate_event = CreateEvent (NULL, TRUE, FALSE, TEXT("TerminateEvent")); + SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); +#endif /* !_WIN32 */ + + if (!on_startup()) { + fprintf (stderr, "Startup failed\n"); + return EXIT_FAILURE; + } + +/* service loop */ + do { + time_t now; + time (&now); + const struct tm* time_ptr = localtime(&now); +#ifndef _WIN32 + char s[1024]; + const size_t slen = strftime (s, sizeof(s), TIME_FORMAT, time_ptr); + const int status = pgm_send (sock, s, slen + 1, NULL); +#else + char s[1024]; + const size_t slen = strftime (s, sizeof(s), TIME_FORMAT, time_ptr); + wchar_t ws[1024]; + size_t wslen = MultiByteToWideChar (CP_ACP, 0, s, slen, ws, 1024); + char us[1024]; + size_t uslen = WideCharToMultiByte (CP_UTF8, 0, ws, wslen + 1, us, sizeof(us), NULL, NULL); + const int status = pgm_send (sock, us, uslen + 1, NULL); +#endif + if (PGM_IO_STATUS_NORMAL != status) { + fprintf (stderr, "pgm_send() failed.\n"); + } +#ifndef _WIN32 + sleep (1); +#else + Sleep (1 * 1000); +#endif + } while (!is_terminated); + +/* cleanup */ + puts ("Waiting for NAK thread."); +#ifndef _WIN32 + pthread_join (nak_thread, NULL); + close (terminate_pipe[0]); + close (terminate_pipe[1]); +#else + WaitForSingleObject (nak_thread, INFINITE); + CloseHandle (nak_thread); + CloseHandle (terminate_event); +#endif /* !_WIN32 */ + + if (sock) { + puts ("Closing PGM sock."); + pgm_close (sock, TRUE); + sock = NULL; + } + + puts ("PGM engine shutdown."); + pgm_shutdown(); + puts ("finished."); + return EXIT_SUCCESS; +} + +#ifndef _WIN32 +static +void +on_signal ( + int signum + ) +{ + printf ("on_signal (signum:%d)\n", signum); + is_terminated = TRUE; + const char one = '1'; + const size_t writelen = write (terminate_pipe[1], &one, sizeof(one)); + assert (sizeof(one) == writelen); +} +#else +static +BOOL +on_console_ctrl ( + DWORD dwCtrlType + ) +{ + printf ("on_console_ctrl (dwCtrlType:%lu)\n", (unsigned long)dwCtrlType); + is_terminated = TRUE; + SetEvent (terminate_event); + return TRUE; +} +#endif /* !_WIN32 */ + +static +bool +on_startup (void) +{ + bool status = (create_sock() && create_nak_thread()); + if (status) + puts ("Startup complete."); + return status; +} + +static +bool +create_sock (void) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + +/* parse network parameter into sock address structure */ + if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { + fprintf (stderr, "Parsing network parameter: %s\n", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + puts ("Create PGM socket."); + if (udp_encap_port) { + if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + fprintf (stderr, "Creating PGM/UDP socket: %s\n", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + } else { + if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + fprintf (stderr, "Creating PGM/IP socket: %s\n", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int send_only = 1, + ambient_spm = pgm_secs (30), + heartbeat_spm[] = { pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (1300), + pgm_secs (7), + pgm_secs (16), + pgm_secs (25), + pgm_secs (30) }; + + pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_ONLY, &send_only, sizeof(send_only)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MTU, &max_tpdu, sizeof(max_tpdu)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_SQNS, &sqns, sizeof(sqns)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_MAX_RTE, &max_rte, sizeof(max_rte)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm)); + +#ifdef I_UNDERSTAND_PGMCC_AND_FEC_ARE_NOT_SUPPORTED + if (use_pgmcc) { + struct pgm_pgmccinfo_t pgmccinfo; + pgmccinfo.ack_bo_ivl = pgm_msecs (50); + pgmccinfo.ack_c = 75; + pgmccinfo.ack_c_p = 500; + pgm_setsockopt (sock, IPPROTO_PGM, PGM_USE_PGMCC, &pgmccinfo, sizeof(pgmccinfo)); + } + if (use_fec) { + struct pgm_fecinfo_t fecinfo; + fecinfo.block_size = rs_n; + fecinfo.proactive_packets = proactive_packets; + fecinfo.group_size = rs_k; + fecinfo.ondemand_parity_enabled = use_ondemand_parity; + fecinfo.var_pktlen_enabled = TRUE; + pgm_setsockopt (sock, IPPROTO_PGM, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); + } +#endif + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = port ? port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + fprintf (stderr, "Creating GSI: %s\n", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + fprintf (stderr, "Binding PGM socket: %s\n", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int nonblocking = 1, + multicast_loop = use_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); + + if (!pgm_connect (sock, &pgm_err)) { + fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message); + goto err_abort; + } + + return TRUE; + +err_abort: + if (NULL != sock) { + pgm_close (sock, FALSE); + sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +static +bool +create_nak_thread (void) +{ +#ifndef _WIN32 + const int status = pthread_create (&nak_thread, NULL, &nak_routine, sock); + if (0 != status) { + fprintf (stderr, "Creating new thread: %s\n", strerror (status)); + return FALSE; + } +#else + nak_thread = (HANDLE)_beginthreadex (NULL, 0, &nak_routine, sock, 0, NULL); + const int save_errno = errno; + if (0 == nak_thread) { + fprintf (stderr, "Creating new thread: %s\n", strerror (save_errno)); + return FALSE; + } +#endif /* _WIN32 */ + return TRUE; +} + +static +#ifndef _WIN32 +void* +#else +unsigned +__stdcall +#endif +nak_routine ( + void* arg + ) +{ +/* dispatch loop */ + pgm_sock_t* nak_sock = (pgm_sock_t*)arg; +#ifndef _WIN32 + int fds; + fd_set readfds; +#else + int n_handles = 4, recv_sock, repair_sock, pending_sock; + HANDLE waitHandles[ 4 ]; + DWORD dwTimeout, dwEvents; + WSAEVENT recvEvent, repairEvent, pendingEvent; + socklen_t socklen = sizeof(int); + + recvEvent = WSACreateEvent (); + pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_RECV_SOCK, &recv_sock, &socklen); + WSAEventSelect (recv_sock, recvEvent, FD_READ); + repairEvent = WSACreateEvent (); + pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_REPAIR_SOCK, &repair_sock, &socklen); + WSAEventSelect (repair_sock, repairEvent, FD_READ); + pendingEvent = WSACreateEvent (); + pgm_getsockopt (nak_sock, IPPROTO_PGM, PGM_PENDING_SOCK, &pending_sock, &socklen); + WSAEventSelect (pending_sock, pendingEvent, FD_READ); + + waitHandles[0] = terminate_event; + waitHandles[1] = recvEvent; + waitHandles[2] = repairEvent; + waitHandles[3] = pendingEvent; +#endif /* !_WIN32 */ + do { + struct timeval tv; + char buf[4064]; + pgm_error_t* pgm_err = NULL; + const int status = pgm_recv (nak_sock, buf, sizeof(buf), 0, NULL, &pgm_err); + switch (status) { + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } + case PGM_IO_STATUS_WOULD_BLOCK: +block: +#ifndef _WIN32 + fds = terminate_pipe[0] + 1; + FD_ZERO(&readfds); + FD_SET(terminate_pipe[0], &readfds); + pgm_select_info (nak_sock, &readfds, NULL, &fds); + fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); +#else + dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout); + switch (dwEvents) { + case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; + case WAIT_OBJECT_0+2: WSAResetEvent (repairEvent); break; + case WAIT_OBJECT_0+3: WSAResetEvent (pendingEvent); break; + default: break; + } +#endif /* !_WIN32 */ + break; + + default: + if (pgm_err) { + fprintf (stderr, "%s\n", pgm_err->message ? pgm_err->message : "(null)"); + pgm_error_free (pgm_err); + pgm_err = NULL; + } + if (PGM_IO_STATUS_ERROR == status) + break; + } + } while (!is_terminated); +#ifndef _WIN32 + return NULL; +#else + WSACloseEvent (recvEvent); + WSACloseEvent (repairEvent); + WSACloseEvent (pendingEvent); + _endthread(); + return 0; +#endif +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecv.c b/3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecv.c new file mode 100644 index 0000000..3f24f76 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecv.c @@ -0,0 +1,382 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Simple PGM receiver: epoll based non-blocking synchronous receiver. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef G_OS_UNIX +# include +# include +# include +# include +#endif +#include + +/* example dependencies */ +#include +#include + + +/* typedefs */ + +/* globals */ + +static int g_port = 0; +static const char* g_network = ""; +static gboolean g_multicast_loop = FALSE; +static int g_udp_encap_port = 0; + +static int g_max_tpdu = 1500; +static int g_sqns = 100; + +static pgm_sock_t* g_sock = NULL; +static gboolean g_quit = FALSE; + +static void on_signal (int); +static gboolean on_startup (void); + +static int on_data (gconstpointer, size_t, struct pgm_sockaddr_t*); + + +G_GNUC_NORETURN static +void +usage ( + const char* bin + ) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); + exit (1); +} + +int +main ( + int argc, + char* argv[] + ) +{ + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + + log_init (); + g_message ("enonblocksyncrecv"); + + if (!pgm_init (&pgm_err)) { + g_error ("Unable to start PGM engine: %s", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) + { + switch (c) { + case 'n': g_network = optarg; break; + case 's': g_port = atoi (optarg); break; + case 'p': g_udp_encap_port = atoi (optarg); break; + case 'l': g_multicast_loop = TRUE; break; + + case 'h': + case '?': usage (binary_name); + } + } + + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); + signal (SIGINT, on_signal); + signal (SIGTERM, on_signal); +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif + + if (!on_startup ()) { + g_error ("startup failed"); + return EXIT_FAILURE; + } + +/* epoll file descriptor */ + int efd = epoll_create (IP_MAX_MEMBERSHIPS); + if (efd < 0) { + g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); + return EXIT_FAILURE; + } + + int retval = pgm_epoll_ctl (g_sock, efd, EPOLL_CTL_ADD, EPOLLIN); + if (retval < 0) { + g_error ("pgm_epoll_ctl failed."); + return EXIT_FAILURE; + } + + struct epoll_event events[1]; /* wait for maximum 1 event */ + +/* dispatch loop */ + g_message ("entering PGM message loop ... "); + do { + struct timeval tv; + int timeout; + char buffer[4096]; + size_t len; + struct pgm_sockaddr_t from; + socklen_t fromlen = sizeof(from); + const int status = pgm_recvfrom (g_sock, + buffer, + sizeof(buffer), + 0, + &len, + &from, + &fromlen, + &pgm_err); + switch (status) { + case PGM_IO_STATUS_NORMAL: + on_data (buffer, len, &from); + break; + + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } +/* fall through */ + case PGM_IO_STATUS_WOULD_BLOCK: +/* poll for next event */ +block: + timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); + break; + + default: + if (pgm_err) { + g_warning ("%s", pgm_err->message); + pgm_error_free (pgm_err); + pgm_err = NULL; + } + if (PGM_IO_STATUS_ERROR == status) + break; + } + } while (!g_quit); + + g_message ("message loop terminated, cleaning up."); + +/* cleanup */ + close (efd); + if (g_sock) { + g_message ("closing PGM socket."); + pgm_close (g_sock, TRUE); + g_sock = NULL; + } + + g_message ("PGM engine shutdown."); + pgm_shutdown (); + g_message ("finished."); + return EXIT_SUCCESS; +} + +static +void +on_signal ( + int signum + ) +{ + g_message ("on_signal (signum:%d)", signum); + g_quit = TRUE; +} + +static +gboolean +on_startup (void) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + + g_message ("startup."); + +/* parse network parameter into transport address structure */ + if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { + g_error ("parsing network parameter: %s", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + if (g_udp_encap_port) { + g_message ("create PGM/UDP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + } else { + g_message ("create PGM/IP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int recv_only = 1, + passive = 0, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PASSIVE, &passive, sizeof(passive)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + g_error ("creating GSI: %s", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (g_sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + g_error ("binding PGM socket: %s", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int nonblocking = 1, + multicast_loop = g_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); + + if (!pgm_connect (g_sock, &pgm_err)) { + g_error ("connecting PGM socket: %s", pgm_err->message); + goto err_abort; + } + + g_message ("startup complete."); + return TRUE; + +err_abort: + if (NULL != g_sock) { + pgm_close (g_sock, FALSE); + g_sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +static +int +on_data ( + gconstpointer data, + size_t len, + struct pgm_sockaddr_t* from + ) +{ +/* protect against non-null terminated strings */ + char buf[1024], tsi[PGM_TSISTRLEN]; + const size_t buflen = MIN(sizeof(buf) - 1, len); + strncpy (buf, (const char*)data, buflen); + buf[buflen] = '\0'; + pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); + + g_message ("\"%s\" (%u bytes from %s)", + buf, + (unsigned)len, + tsi); + + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecvmsg.c b/3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecvmsg.c new file mode 100644 index 0000000..43deb89 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecvmsg.c @@ -0,0 +1,382 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Simple PGM receiver: blocking synchronous receiver with scatter/gather io + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef G_OS_UNIX +# include +# include +# include +# include +#endif +#include + +/* example dependencies */ +#include +#include + + +/* typedefs */ + +/* globals */ + +static int g_port = 0; +static const char* g_network = ""; +static gboolean g_multicast_loop = FALSE; +static int g_udp_encap_port = 0; + +static int g_max_tpdu = 1500; +static int g_sqns = 100; + +static pgm_sock_t* g_sock = NULL; +static gboolean g_quit = FALSE; + +static void on_signal (int); +static gboolean on_startup (void); + +static int on_datav (struct pgm_msgv_t*, size_t); + + +G_GNUC_NORETURN static +void +usage ( + const char* bin + ) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); + exit (1); +} + +int +main ( + int argc, + char* argv[] + ) +{ + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + + log_init (); + g_message ("enonblocksyncrecvmsg"); + + if (!pgm_init (&pgm_err)) { + g_error ("Unable to start PGM engine: %s", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) + { + switch (c) { + case 'n': g_network = optarg; break; + case 's': g_port = atoi (optarg); break; + case 'p': g_udp_encap_port = atoi (optarg); break; + case 'l': g_multicast_loop = TRUE; break; + + case 'h': + case '?': usage (binary_name); + } + } + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); + signal (SIGINT, on_signal); + signal (SIGTERM, on_signal); +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif + + if (!on_startup ()) { + g_error ("startup failed"); + return EXIT_FAILURE; + } + +/* epoll file descriptor */ + int efd = epoll_create (IP_MAX_MEMBERSHIPS); + if (efd < 0) { + g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); + return EXIT_FAILURE; + } + + int retval = pgm_epoll_ctl (g_sock, efd, EPOLL_CTL_ADD, EPOLLIN); + if (retval < 0) { + g_error ("pgm_epoll_ctl failed."); + return EXIT_FAILURE; + } + +/* incoming message buffer */ + struct pgm_msgv_t msgv; + struct epoll_event events[1]; /* wait for maximum 1 event */ + +/* dispatch loop */ + g_message ("entering PGM message loop ... "); + do { + struct timeval tv; + int timeout; + size_t len; + const int status = pgm_recvmsg (g_sock, + &msgv, + 0, + &len, + &pgm_err); + switch (status) { + case PGM_IO_STATUS_NORMAL: + on_datav (&msgv, len); + break; + + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } +/* fall through */ + case PGM_IO_STATUS_WOULD_BLOCK: +/* poll for next event */ +block: + timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); + break; + + default: + if (pgm_err) { + g_warning ("%s", pgm_err->message); + pgm_error_free (pgm_err); + pgm_err = NULL; + } + if (PGM_IO_STATUS_ERROR == status) + break; + } + } while (!g_quit); + + g_message ("message loop terminated, cleaning up."); + +/* cleanup */ + close (efd); + if (g_sock) { + g_message ("closing PGM socket."); + pgm_close (g_sock, TRUE); + g_sock = NULL; + } + + g_message ("PGM engine shutdown."); + pgm_shutdown (); + g_message ("finished."); + return EXIT_SUCCESS; +} + +static +void +on_signal ( + int signum + ) +{ + g_message ("on_signal (signum:%d)", signum); + g_quit = TRUE; +} + +static +gboolean +on_startup (void) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + + g_message ("startup."); + +/* parse network parameter into transport address structure */ + if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { + g_error ("parsing network parameter: %s", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + if (g_udp_encap_port) { + g_message ("create PGM/UDP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + } else { + g_message ("create PGM/IP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int recv_only = 1, + passive = 0, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PASSIVE, &passive, sizeof(passive)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + g_error ("creating GSI: %s", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (g_sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + g_error ("binding PGM socket: %s", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int nonblocking = 1, + multicast_loop = g_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); + + if (!pgm_connect (g_sock, &pgm_err)) { + g_error ("connecting PGM socket: %s", pgm_err->message); + goto err_abort; + } + + g_message ("startup complete."); + return TRUE; + +err_abort: + if (NULL != g_sock) { + pgm_close (g_sock, FALSE); + g_sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +static +int +on_datav ( + struct pgm_msgv_t* datav, /* one msgv object */ + size_t len + ) +{ + char tsi[PGM_TSISTRLEN]; + pgm_tsi_print_r (&datav->msgv_skb[0]->tsi, tsi, sizeof(tsi)); + g_message ("(%u bytes from %s)", (unsigned)len, tsi); + +/* protect against non-null terminated strings */ + const struct pgm_sk_buff_t* skb = datav->msgv_skb[0]; + int i = 0; + while (len) + { + char buf[1024]; + const size_t buflen = MIN( sizeof(buf) - 1, skb->len ); + strncpy (buf, (const char*)skb->data, buflen); + buf[buflen] = '\0'; + g_message ("\t%i: %s (%" G_GUINT16_FORMAT " bytes)", ++i, buf, skb->len); + len -= skb->len; + skb++; + } + + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecvmsgv.c b/3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecvmsgv.c new file mode 100644 index 0000000..f41a002 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/enonblocksyncrecvmsgv.c @@ -0,0 +1,397 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Simple PGM receiver: epoll based non-blocking synchronous receiver with scatter/gather io + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef G_OS_UNIX +# include +# include +# include +# include +# include +#endif +#include + +/* example dependencies */ +#include +#include + + +/* typedefs */ + +/* globals */ + +static int g_port = 0; +static const char* g_network = ""; +static gboolean g_multicast_loop = FALSE; +static int g_udp_encap_port = 0; + +static int g_max_tpdu = 1500; +static int g_sqns = 100; + +static pgm_sock_t* g_sock = NULL; +static gboolean g_quit = FALSE; + +static void on_signal (int); +static gboolean on_startup (void); + +static int on_msgv (struct pgm_msgv_t*, size_t); + + +G_GNUC_NORETURN static +void +usage ( + const char* bin + ) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); + exit (1); +} + +int +main ( + int argc, + char* argv[] + ) +{ + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + + log_init (); + g_message ("enonblocksyncrecvmsgv"); + + if (!pgm_init (&pgm_err)) { + g_error ("Unable to start PGM engine: %s", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) + { + switch (c) { + case 'n': g_network = optarg; break; + case 's': g_port = atoi (optarg); break; + case 'p': g_udp_encap_port = atoi (optarg); break; + case 'l': g_multicast_loop = TRUE; break; + + case 'h': + case '?': usage (binary_name); + } + } + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); + signal (SIGINT, on_signal); + signal (SIGTERM, on_signal); +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif + + if (!on_startup ()) { + g_error ("startup failed"); + return EXIT_FAILURE; + } + +/* incoming message buffer, iov_len must be less than SC_IOV_MAX */ + const long iov_len = 8; + const long ev_len = 1; + g_message ("Using iov_len %li ev_len %li", iov_len, ev_len); + + struct pgm_msgv_t msgv[iov_len]; + struct epoll_event events[ev_len]; /* wait for maximum 1 event */ + +/* epoll file descriptor */ + const int efd = epoll_create (IP_MAX_MEMBERSHIPS); + if (efd < 0) { + g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); + return EXIT_FAILURE; + } + + const int retval = pgm_epoll_ctl (g_sock, efd, EPOLL_CTL_ADD, EPOLLIN); + if (retval < 0) { + g_error ("pgm_epoll_ctl failed."); + return EXIT_FAILURE; + } + +/* dispatch loop */ + g_message ("entering PGM message loop ... "); + do { + struct timeval tv; + int timeout; + size_t len; + const int status = pgm_recvmsgv (g_sock, + msgv, + iov_len, + 0, + &len, + &pgm_err); + switch (status) { + case PGM_IO_STATUS_NORMAL: + on_msgv (msgv, len); + break; + + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } +/* fall through */ + case PGM_IO_STATUS_WOULD_BLOCK: +/* poll for next event */ +block: + timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); + break; + + default: + if (pgm_err) { + g_warning ("%s", pgm_err->message); + pgm_error_free (pgm_err); + pgm_err = NULL; + } + if (PGM_IO_STATUS_ERROR == status) + break; + } + } while (!g_quit); + + g_message ("message loop terminated, cleaning up."); + +/* cleanup */ + close (efd); + if (g_sock) { + g_message ("closing PGM socket."); + pgm_close (g_sock, TRUE); + g_sock = NULL; + } + + g_message ("PGM engine shutdown."); + pgm_shutdown (); + g_message ("finished."); + return EXIT_SUCCESS; +} + +static +void +on_signal ( + int signum + ) +{ + g_message ("on_signal (signum:%d)", signum); + g_quit = TRUE; +} + +static +gboolean +on_startup (void) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + + g_message ("startup."); + +/* parse network parameter into transport address structure */ + if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { + g_error ("parsing network parameter: %s", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + if (g_udp_encap_port) { + g_message ("create PGM/UDP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + } else { + g_message ("create PGM/IP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int recv_only = 1, + passive = 0, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PASSIVE, &passive, sizeof(passive)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + g_error ("creating GSI: %s", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (g_sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + g_error ("binding PGM socket: %s", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int nonblocking = 1, + multicast_loop = g_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); + + if (!pgm_connect (g_sock, &pgm_err)) { + g_error ("connecting PGM socket: %s", pgm_err->message); + goto err_abort; + } + + g_message ("startup complete."); + return TRUE; + +err_abort: + if (NULL != g_sock) { + pgm_close (g_sock, FALSE); + g_sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +static +int +on_msgv ( + struct pgm_msgv_t* msgv, /* an array of msgv's */ + size_t len /* total size of all msgv's */ + ) +{ + g_message ("(%u bytes)", + (unsigned)len); + + guint i = 0; + +/* for each apdu display each fragment */ + do { + const struct pgm_sk_buff_t* pskb = msgv[i].msgv_skb[0]; + gsize apdu_len = 0; + for (unsigned j = 0; j < msgv[i].msgv_len; j++) + apdu_len += msgv[i].msgv_skb[j]->len; +/* truncate to first fragment to make GLib printing happy */ + char buf[1024], tsi[PGM_TSISTRLEN]; + const size_t buflen = MIN( sizeof(buf) - 1, pskb->len ); + strncpy (buf, (const char*)pskb->data, buflen); + buf[buflen] = '\0'; + pgm_tsi_print_r (&pskb->tsi, tsi, sizeof(tsi)); + if (msgv[i].msgv_len > 1) { + g_message ("\t%u: \"%s\" ... (%" G_GSIZE_FORMAT " bytes from %s)", i, buf, apdu_len, tsi); + } else { + g_message ("\t%u: \"%s\" (%" G_GSIZE_FORMAT " bytes from %s)", i, buf, apdu_len, tsi); + } + i++; + len -= apdu_len; + } while (len); + + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/getopt.c b/3rdparty/openpgm-svn-r1135/pgm/examples/getopt.c new file mode 100644 index 0000000..8c655b6 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/getopt.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include "getopt.h" + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(int nargc, char* const* nargv, const char* ostr) +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':' && optopt != BADCH) + (void)fprintf(stderr, "%s: illegal option -- %c\n", + "progname", optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + "progname", optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/getopt.h b/3rdparty/openpgm-svn-r1135/pgm/examples/getopt.h new file mode 100644 index 0000000..f04387b --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/getopt.h @@ -0,0 +1,62 @@ +/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ +/* $FreeBSD: src/include/getopt.h,v 1.1 2002/09/29 04:14:30 eric Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* These are global getopt variables */ +extern int opterr, /* if error message should be printed */ + optind, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +extern char* optarg; /* argument associated with option */ + +/* Original getopt */ +int getopt (int, char*const*, const char*); + +#ifdef __cplusplus +} +#endif + +#endif /* !_GETOPT_H_ */ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/pgmdump.c b/3rdparty/openpgm-svn-r1135/pgm/examples/pgmdump.c new file mode 100644 index 0000000..481b12e --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/pgmdump.c @@ -0,0 +1,279 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Dump PGM packets to the console. + * + * Copyright (c) 2006-2007 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef G_OS_UNIX +# include +# include +# include +# include +#endif + +#include + +/* PGM internals */ +#include + +/* example dependencies */ +#include +#include + + +/* globals */ + +static const char* g_network = "239.192.0.1"; + +static GIOChannel* g_io_channel = NULL; +static GMainLoop* g_loop = NULL; + + +static void on_signal (int); +static gboolean on_startup (gpointer); +static gboolean on_mark (gpointer); + +static gboolean on_io_data (GIOChannel*, GIOCondition, gpointer); + + +int +main ( + G_GNUC_UNUSED int argc, + G_GNUC_UNUSED char *argv[] + ) +{ + GError* err = NULL; + + setlocale (LC_ALL, ""); + + log_init (); + g_message ("pgmdump"); + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); + signal (SIGINT, on_signal); + signal (SIGTERM, on_signal); +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif + +/* delayed startup */ + g_message ("scheduling startup."); + g_timeout_add (0, (GSourceFunc)on_startup, NULL); + +/* dispatch loop */ + g_loop = g_main_loop_new (NULL, FALSE); + + g_message ("entering main event loop ... "); + g_main_loop_run (g_loop); + + g_message ("event loop terminated, cleaning up."); + +/* cleanup */ + g_main_loop_unref (g_loop); + g_loop = NULL; + + if (g_io_channel) { + g_message ("closing socket."); + g_io_channel_shutdown (g_io_channel, FALSE, &err); + g_io_channel = NULL; + } + + g_message ("finished."); + return EXIT_SUCCESS; +} + +static void +on_signal ( + G_GNUC_UNUSED int signum + ) +{ + puts ("on_signal"); + + g_main_loop_quit(g_loop); +} + +static +gboolean +on_startup ( + G_GNUC_UNUSED gpointer data + ) +{ + int e; + + g_message ("startup."); + +/* find PGM protocol id */ +// TODO: fix valgrind errors + int ipproto_pgm = IPPROTO_PGM; +#ifdef HAVE_GETPROTOBYNAME_R + char b[1024]; + struct protoent protobuf, *proto; + e = getprotobyname_r ("pgm", &protobuf, b, sizeof(b), &proto); + if (e != -1 && proto != NULL) { + if (proto->p_proto != ipproto_pgm) { + g_message ("Setting PGM protocol number to %i from /etc/protocols.\n"); + ipproto_pgm = proto->p_proto; + } + } +#else + struct protoent *proto = getprotobyname ("pgm"); + if (proto != NULL) { + if (proto->p_proto != ipproto_pgm) { + g_message ("Setting PGM protocol number to %i from /etc/protocols.\n", proto +->p_proto); + ipproto_pgm = proto->p_proto; + } + } +#endif + +/* open socket for snooping */ + g_message ("opening raw socket."); + int sock = socket (PF_INET, SOCK_RAW, ipproto_pgm); + if (sock < 0) { + perror("on_startup() failed"); +#ifdef G_OS_UNIX + if (EPERM == errno && 0 != getuid()) { + g_message ("PGM protocol requires this program to run as superuser."); + } +#endif + g_main_loop_quit (g_loop); + return FALSE; + } + +#ifdef G_OS_UNIX +/* drop out of setuid 0 */ + if (0 == getuid ()) { + g_message ("dropping superuser privileges."); + setuid ((gid_t)65534); + setgid ((uid_t)65534); + } +#endif + + char _t = 1; + e = setsockopt (sock, IPPROTO_IP, IP_HDRINCL, &_t, sizeof(_t)); + if (e < 0) { + perror ("on_startup() failed"); + close (sock); + g_main_loop_quit (g_loop); + return FALSE; + } + +/* buffers */ + int buffer_size = 0; + socklen_t len = 0; + e = getsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char*)&buffer_size, &len); + if (e == 0) { + g_message ("receive buffer set at %i bytes.\n", buffer_size); + } + e = getsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char*)&buffer_size, &len); + if (e == 0) { + g_message ("send buffer set at %i bytes.\n", buffer_size); + } + +/* bind */ + struct sockaddr_in addr; + memset (&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + e = bind (sock, (struct sockaddr*)&addr, sizeof(addr)); + if (e < 0) { + perror ("on_startup() failed"); + close (sock); + g_main_loop_quit (g_loop); + return FALSE; + } + +/* multicast */ + struct ip_mreq mreq; + memset (&mreq, 0, sizeof(mreq)); + mreq.imr_interface.s_addr = htonl (INADDR_ANY); + g_message ("listening on interface %s.\n", inet_ntoa (mreq.imr_interface)); + mreq.imr_multiaddr.s_addr = inet_addr (g_network); + g_message ("subscription on multicast address %s.\n", inet_ntoa (mreq.imr_multiaddr)); + e = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)); + if (e < 0) { + perror ("on_startup() failed"); + close (sock); + g_main_loop_quit (g_loop); + return FALSE; + } + +/* multicast loopback */ +/* multicast ttl */ + +/* add socket to event manager */ + g_io_channel = g_io_channel_unix_new (sock); + g_message ("socket opened with encoding %s.\n", g_io_channel_get_encoding (g_io_channel)); + + /* guint event = */ g_io_add_watch (g_io_channel, G_IO_IN | G_IO_PRI, on_io_data, NULL); + +/* period timer to indicate some form of life */ +// TODO: Gnome 2.14: replace with g_timeout_add_seconds() + g_timeout_add (10 * 1000, (GSourceFunc)on_mark, NULL); + + g_message ("startup complete."); + return FALSE; +} + +static gboolean +on_mark ( + G_GNUC_UNUSED gpointer data + ) +{ + g_message ("-- MARK --"); + return TRUE; +} + +static gboolean +on_io_data ( + GIOChannel* source, + G_GNUC_UNUSED GIOCondition condition, + G_GNUC_UNUSED gpointer data + ) +{ + char buffer[4096]; + + int fd = g_io_channel_unix_get_fd (source); + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + int len = recvfrom (fd, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len); + + g_message ("%i bytes received from %s.\n", len, inet_ntoa (addr.sin_addr)); + + if (!pgm_print_packet (buffer, len)) { + g_message ("invalid packet :("); + } + + fflush (stdout); + + return TRUE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/pgmping.cc b/3rdparty/openpgm-svn-r1135/pgm/examples/pgmping.cc new file mode 100644 index 0000000..0c7e702 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/pgmping.cc @@ -0,0 +1,1225 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Simple send/reply ping tool using the PGM transport. + * + * With no arguments, one message is sent per second. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* c99 compatibility for c++ */ +#define __STDC_LIMIT_MACROS + +/* Must be first for Sun */ +#include "ping.pb.h" + +/* c99 compatibility for c++ */ +#define __STDC_FORMAT_MACROS +#define restrict + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef CONFIG_HAVE_EPOLL +# include +#endif +#include +#ifndef _WIN32 +# include +# include +# include +# include +# include +#endif +#include +#include +#ifdef CONFIG_WITH_HTTP +# include +#endif +#ifdef CONFIG_WITH_SNMP +# include +#endif + +/* PGM internal time keeper */ +typedef pgm_time_t (*pgm_time_update_func)(void); +extern pgm_time_update_func pgm_time_update_now; +extern "C" { + size_t pgm_pkt_offset (bool, sa_family_t); +} + +/* example dependencies */ +#include +#include +#include + + +using namespace std; + + +/* globals */ + +static int g_port = 0; +static const char* g_network = ""; +static int g_udp_encap_port = 0; + +static int g_odata_rate = 0; +static int g_odata_interval = 0; +static guint32 g_payload = 0; +static int g_max_tpdu = 1500; +static int g_max_rte = 16*1000*1000; +static int g_sqns = 200; + +static gboolean g_use_pgmcc = FALSE; +static sa_family_t g_pgmcc_family = 0; /* 0 = disabled */ + +static gboolean g_use_fec = FALSE; +static int g_rs_k = 8; +static int g_rs_n = 255; + +static enum { + PGMPING_MODE_SOURCE, + PGMPING_MODE_RECEIVER, + PGMPING_MODE_INITIATOR, + PGMPING_MODE_REFLECTOR +} g_mode = PGMPING_MODE_INITIATOR; + +static pgm_sock_t* g_sock = NULL; + +/* stats */ +static guint64 g_msg_sent = 0; +static guint64 g_msg_received = 0; +static pgm_time_t g_interval_start = 0; +static pgm_time_t g_latency_current = 0; +static guint64 g_latency_seqno = 0; +static guint64 g_last_seqno = 0; +static double g_latency_total = 0.0; +static double g_latency_square_total = 0.0; +static guint64 g_latency_count = 0; +static double g_latency_max = 0.0; +#ifdef INFINITY +static double g_latency_min = INFINITY; +#else +static double g_latency_min = INT64_MAX; +#endif +static double g_latency_running_average = 0.0; +static guint64 g_out_total = 0; +static guint64 g_in_total = 0; + +static GMainLoop* g_loop = NULL; +static GThread* g_sender_thread = NULL; +static GThread* g_receiver_thread = NULL; +static gboolean g_quit; +#ifdef G_OS_UNIX +static int g_quit_pipe[2]; +static void on_signal (int, gpointer); +#else +static HANDLE g_quit_event; +static BOOL on_console_ctrl (DWORD); +#endif + +static gboolean on_startup (gpointer); +static gboolean on_shutdown (gpointer); +static gboolean on_mark (gpointer); + +static void send_odata (void); +static int on_msgv (struct pgm_msgv_t*, size_t); + +static gpointer sender_thread (gpointer); +static gpointer receiver_thread (gpointer); + + +G_GNUC_NORETURN static void +usage (const char* bin) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -d : Terminate transport after duration.\n"); + fprintf (stderr, " -m : Number of message to send per second\n"); + fprintf (stderr, " -o : Send-only mode (default send & receive mode)\n"); + fprintf (stderr, " -l : Listen-only mode\n"); + fprintf (stderr, " -e : Relect mode\n"); + fprintf (stderr, " -r : Regulate to rate bytes per second\n"); + fprintf (stderr, " -c : Enable PGMCC\n"); + fprintf (stderr, " -f : Enable FEC with either proactive or ondemand parity\n"); + fprintf (stderr, " -K : Configure Reed-Solomon code (n, k)\n"); + fprintf (stderr, " -N \n"); + fprintf (stderr, " -H : Enable HTTP administrative interface\n"); + fprintf (stderr, " -S : Enable SNMP interface\n"); + exit (1); +} + +int +main ( + int argc, + char *argv[] + ) +{ + GError* err = NULL; + pgm_error_t* pgm_err = NULL; + gboolean enable_http = FALSE; + gboolean enable_snmpx = FALSE; + int timeout = 0; + + GOOGLE_PROTOBUF_VERIFY_VERSION; + + setlocale (LC_ALL, ""); + setenv ("PGM_TIMER", "GTOD", 1); + setenv ("PGM_SLEEP", "USLEEP", 1); + + log_init (); + g_message ("pgmping"); + + g_thread_init (NULL); + + if (!pgm_init (&pgm_err)) { + g_error ("Unable to start PGM engine: %s", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = g_get_prgname(); + int c; + while ((c = getopt (argc, argv, "s:n:p:m:old:r:cfeK:N:HSh")) != -1) + { + switch (c) { + case 'n': g_network = optarg; break; + case 's': g_port = atoi (optarg); break; + case 'p': g_udp_encap_port = atoi (optarg); break; + case 'r': g_max_rte = atoi (optarg); break; + + case 'c': g_use_pgmcc = TRUE; break; + + case 'f': g_use_fec = TRUE; break; + case 'K': g_rs_k = atoi (optarg); break; + case 'N': g_rs_n = atoi (optarg); break; + + case 'H': enable_http = TRUE; break; + case 'S': enable_snmpx = TRUE; break; + + case 'm': g_odata_rate = atoi (optarg); + g_odata_interval = (1000 * 1000) / g_odata_rate; break; + case 'd': timeout = 1000 * atoi (optarg); break; + + case 'o': g_mode = PGMPING_MODE_SOURCE; break; + case 'l': g_mode = PGMPING_MODE_RECEIVER; break; + case 'e': g_mode = PGMPING_MODE_REFLECTOR; break; + + case 'h': + case '?': usage (binary_name); + } + } + + if (g_use_fec && ( !g_rs_k || !g_rs_n )) { + g_error ("Invalid Reed-Solomon parameters."); + usage (binary_name); + } + +#ifdef CONFIG_WITH_HTTP + if (enable_http) { + if (!pgm_http_init (PGM_HTTP_DEFAULT_SERVER_PORT, &pgm_err)) { + g_error ("Unable to start HTTP interface: %s", pgm_err->message); + pgm_error_free (pgm_err); + pgm_shutdown (); + return EXIT_FAILURE; + } + } +#endif +#ifdef CONFIG_WITH_SNMP + if (enable_snmpx) { + if (!pgm_snmp_init (&pgm_err)) { + g_error ("Unable to start SNMP interface: %s", pgm_err->message); + pgm_error_free (pgm_err); +#ifdef CONFIG_WITH_HTTP + if (enable_http) + pgm_http_shutdown (); +#endif + pgm_shutdown (); + return EXIT_FAILURE; + } + } +#endif + + g_loop = g_main_loop_new (NULL, FALSE); + + g_quit = FALSE; + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif +#ifdef G_OS_UNIX + pipe (g_quit_pipe); + pgm_signal_install (SIGINT, on_signal, g_loop); + pgm_signal_install (SIGTERM, on_signal, g_loop); +#else + g_quit_event = CreateEvent (NULL, TRUE, FALSE, TEXT("QuitEvent")); + SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); +#endif /* !G_OS_UNIX */ + +/* delayed startup */ + g_message ("scheduling startup."); + g_timeout_add (0, (GSourceFunc)on_startup, g_loop); + + if (timeout) { + g_message ("scheduling shutdown."); + g_timeout_add (timeout, (GSourceFunc)on_shutdown, g_loop); + } + +/* dispatch loop */ + g_message ("entering main event loop ... "); + g_main_loop_run (g_loop); + + g_message ("event loop terminated, cleaning up."); + +/* cleanup */ + g_quit = TRUE; +#ifdef G_OS_UNIX + const char one = '1'; + write (g_quit_pipe[1], &one, sizeof(one)); + if (PGMPING_MODE_SOURCE == g_mode || PGMPING_MODE_INITIATOR == g_mode) + g_thread_join (g_sender_thread); + g_thread_join (g_receiver_thread); + close (g_quit_pipe[0]); + close (g_quit_pipe[1]); +#else + SetEvent (g_quit_event); + if (PGMPING_MODE_SOURCE == g_mode || PGMPING_MODE_INITIATOR == g_mode) + g_thread_join (g_sender_thread); + g_thread_join (g_receiver_thread); + CloseHandle (g_quit_event); +#endif + + g_main_loop_unref (g_loop); + g_loop = NULL; + + if (g_sock) { + g_message ("closing PGM socket."); + pgm_close (g_sock, TRUE); + g_sock = NULL; + } + +#ifdef CONFIG_WITH_HTTP + if (enable_http) + pgm_http_shutdown(); +#endif +#ifdef CONFIG_WITH_SNMP + if (enable_snmpx) + pgm_snmp_shutdown(); +#endif + + google::protobuf::ShutdownProtobufLibrary(); + + g_message ("PGM engine shutdown."); + pgm_shutdown (); + g_message ("finished."); + return EXIT_SUCCESS; +} + +#ifdef G_OS_UNIX +static +void +on_signal ( + int signum, + gpointer user_data + ) +{ + GMainLoop* loop = (GMainLoop*)user_data; + g_message ("on_signal (signum:%d user-data:%p)", + signum, user_data); + g_main_loop_quit (loop); +} +#else +static +BOOL +on_console_ctrl ( + DWORD dwCtrlType + ) +{ + g_message ("on_console_ctrl (dwCtrlType:%lu)", (unsigned long)dwCtrlType); + g_main_loop_quit (g_loop); + return TRUE; +} +#endif /* !G_OS_UNIX */ + +static +gboolean +on_shutdown ( + gpointer user_data + ) +{ + GMainLoop* loop = (GMainLoop*)user_data; + g_message ("on_shutdown (user-data:%p)", user_data); + g_main_loop_quit (loop); + return FALSE; +} + +static +gboolean +on_startup ( + gpointer user_data + ) +{ + GMainLoop* loop = (GMainLoop*)user_data; + struct pgm_addrinfo_t* res = NULL; + GError* err = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + + g_message ("startup."); + +/* parse network parameter into transport address structure */ + if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { + g_error ("parsing network parameter: %s", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + if (g_use_pgmcc) + g_pgmcc_family = sa_family; + + if (g_udp_encap_port) { + g_message ("create PGM/UDP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port))) { + g_error ("setting PGM_UDP_ENCAP_UCAST_PORT = %d", g_udp_encap_port); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port))) { + g_error ("setting PGM_UDP_ENCAP_MCAST_PORT = %d", g_udp_encap_port); + goto err_abort; + } + } else { + g_message ("create PGM/IP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + { + const int no_router_assist = 0; + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist))) { + g_error ("setting PGM_IP_ROUTER_ALERT = %d", no_router_assist); + goto err_abort; + } + } + + pgm_drop_superuser(); + +/* set PGM parameters */ +/* common */ + { + const int bufsize = 1024 * 1024, + max_tpdu = g_max_tpdu; + + if (!pgm_setsockopt (g_sock, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize))) { + g_error ("setting SO_RCVBUF = %d", bufsize); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize))) { + g_error ("setting SO_SNDBUF = %d", bufsize); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MTU, &max_tpdu, sizeof(max_tpdu))) { + g_error ("setting PGM_MTU = %d", max_tpdu); + goto err_abort; + } + } + +/* send side */ + if (PGMPING_MODE_SOURCE == g_mode || + PGMPING_MODE_INITIATOR == g_mode || + PGMPING_MODE_REFLECTOR == g_mode ) + { + const int send_only = (PGMPING_MODE_SOURCE == g_mode) ? 1 : 0, + txw_sqns = g_sqns * 4, + txw_max_rte = g_max_rte, + ambient_spm = pgm_secs (30), + heartbeat_spm[] = { pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (1300), + pgm_secs (7), + pgm_secs (16), + pgm_secs (25), + pgm_secs (30) }; + + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_ONLY, &send_only, sizeof(send_only))) { + g_error ("setting PGM_SEND_ONLY = %d", send_only); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TXW_SQNS, &txw_sqns, sizeof(txw_sqns))) { + g_error ("setting PGM_TXW_SQNS = %d", txw_sqns); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TXW_MAX_RTE, &txw_max_rte, sizeof(txw_max_rte))) { + g_error ("setting PGM_TXW_MAX_RTE = %d", txw_max_rte); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm))) { + g_error ("setting PGM_AMBIENT_SPM = %d", ambient_spm); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm))) { + char buffer[1024]; + sprintf (buffer, "%d", heartbeat_spm[0]); + for (unsigned i = 1; i < G_N_ELEMENTS(heartbeat_spm); i++) { + char t[1024]; + sprintf (t, ", %d", heartbeat_spm[i]); + strcat (buffer, t); + } + g_error ("setting HEARTBEAT_SPM = { %s }", buffer); + goto err_abort; + } + + } + +/* receive side */ + if (PGMPING_MODE_RECEIVER == g_mode || + PGMPING_MODE_INITIATOR == g_mode || + PGMPING_MODE_REFLECTOR == g_mode ) + { + const int recv_only = (PGMPING_MODE_RECEIVER == g_mode) ? 1 : 0, + not_passive = 0, + rxw_sqns = g_sqns, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_msecs (200), //pgm_secs (2), + nak_rdata_ivl = pgm_msecs (200), //pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof(recv_only))) { + g_error ("setting PGM_RECV_ONLY = %d", recv_only); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PASSIVE, ¬_passive, sizeof(not_passive))) { + g_error ("setting PGM_PASSIVE = %d", not_passive); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RXW_SQNS, &rxw_sqns, sizeof(rxw_sqns))) { + g_error ("setting PGM_RXW_SQNS = %d", rxw_sqns); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry))) { + g_error ("setting PGM_PEER_EXPIRY = %d", peer_expiry); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry))) { + g_error ("setting PGM_SPMR_EXPIRY = %d", spmr_expiry); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl))) { + g_error ("setting PGM_NAK_BO_IVL = %d", nak_bo_ivl); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl))) { + g_error ("setting PGM_NAK_RPT_IVL = %d", nak_rpt_ivl); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl))) { + g_error ("setting PGM_NAK_RDATA_IVL = %d", nak_rdata_ivl); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries))) { + g_error ("setting PGM_NAK_DATA_RETRIES = %d", nak_data_retries); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries))) { + g_error ("setting PGM_NAK_NCF_RETRIES = %d", nak_ncf_retries); + goto err_abort; + } + } + +#ifdef I_UNDERSTAND_PGMCC_AND_FEC_ARE_NOT_SUPPORTED +/* PGMCC congestion control */ + if (g_use_pgmcc) { + struct pgm_pgmccinfo_t pgmccinfo; + pgmccinfo.ack_bo_ivl = pgm_msecs (50); + pgmccinfo.ack_c = 75; + pgmccinfo.ack_c_p = 500; + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_USE_PGMCC, &pgmccinfo, sizeof(pgmccinfo))) { + g_error ("setting PGM_USE_PGMCC = { ack_bo_ivl = %d ack_c = %d ack_c_p = %d }", + pgmccinfo.ack_bo_ivl, + pgmccinfo.ack_c, + pgmccinfo.ack_c_p); + goto err_abort; + } + } + +/* Reed Solomon forward error correction */ + if (g_use_fec) { + struct pgm_fecinfo_t fecinfo; + fecinfo.block_size = g_rs_n; + fecinfo.proactive_packets = 0; + fecinfo.group_size = g_rs_k; + fecinfo.ondemand_parity_enabled = TRUE; + fecinfo.var_pktlen_enabled = TRUE; + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_USE_FEC, &fecinfo, sizeof(fecinfo))) { + g_error ("setting PGM_USE_FEC = { block_size = %d proactive_packets = %d group_size = %d ondemand_parity_enabled = %s var_pktlen_enabled = %s }", + fecinfo.block_size, + fecinfo.proactive_packets, + fecinfo.group_size, + fecinfo.ondemand_parity_enabled ? "TRUE" : "FALSE", + fecinfo.var_pktlen_enabled ? "TRUE" : "FALSE"); + goto err_abort; + } + } +#endif + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = (0 != g_port) ? g_port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + g_error ("creating GSI: %s", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (g_sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + g_error ("binding PGM socket: %s", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + { + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req))) { + char group[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&res->ai_recv_addrs[i].gsr_group, sizeof(struct sockaddr_in), + group, sizeof(group), + NULL, 0, + NI_NUMERICHOST); + g_error ("setting PGM_JOIN_GROUP = { #%u %s }", + (unsigned)res->ai_recv_addrs[i].gsr_interface, + group); + goto err_abort; + } + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req))) { + char group[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, sizeof(struct sockaddr_in), + group, sizeof(group), + NULL, 0, + NI_NUMERICHOST); + g_error ("setting PGM_SEND_GROUP = { #%u %s }", + (unsigned)res->ai_send_addrs[0].gsr_interface, + group); + goto err_abort; + } + pgm_freeaddrinfo (res); + +/* set IP parameters */ + { + const int nonblocking = 1, + multicast_direct = 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_direct, sizeof(multicast_direct))) { + g_error ("setting PGM_MULTICAST_LOOP = %d", multicast_direct); + goto err_abort; + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops))) { + g_error ("setting PGM_MULTICAST_HOPS = %d", multicast_hops); + goto err_abort; + } + if (AF_INET6 != sa_family) { + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp))) { + g_error ("setting PGM_TOS = 0x%x", dscp); + goto err_abort; + } + } + if (!pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking))) { + g_error ("setting PGM_NOBLOCK = %d", nonblocking); + goto err_abort; + } + } + + if (!pgm_connect (g_sock, &pgm_err)) { + g_error ("connecting PGM socket: %s", pgm_err->message); + goto err_abort; + } + +/* period timer to indicate some form of life */ +// TODO: Gnome 2.14: replace with g_timeout_add_seconds() + g_timeout_add (2 * 1000, (GSourceFunc)on_mark, NULL); + + if (PGMPING_MODE_SOURCE == g_mode || PGMPING_MODE_INITIATOR == g_mode) + { + g_sender_thread = g_thread_create_full (sender_thread, + g_sock, + 0, + TRUE, + TRUE, + G_THREAD_PRIORITY_NORMAL, + &err); + if (!g_sender_thread) { + g_critical ("g_thread_create_full failed errno %i: \"%s\"", err->code, err->message); + goto err_abort; + } + } + + { + g_receiver_thread = g_thread_create_full (receiver_thread, + g_sock, + 0, + TRUE, + TRUE, + G_THREAD_PRIORITY_HIGH, + &err); + if (!g_receiver_thread) { + g_critical ("g_thread_create_full failed errno %i: \"%s\"", err->code, err->message); + goto err_abort; + } + } + + g_message ("startup complete."); + return FALSE; + +err_abort: + if (NULL != g_sock) { + pgm_close (g_sock, FALSE); + g_sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +static +gpointer +sender_thread ( + gpointer user_data + ) +{ + pgm_sock_t* tx_sock = (pgm_sock_t*)user_data; + example::Ping ping; + string subject("PING.PGM.TEST."); + char hostname[NI_MAXHOST + 1]; + const long payload_len = 1000; + char payload[payload_len]; + gpointer buffer = NULL; + guint64 latency, now, last; + +#ifdef CONFIG_HAVE_EPOLL + const long ev_len = 1; + struct epoll_event events[ev_len]; + + int efd_again = epoll_create (IP_MAX_MEMBERSHIPS); + if (efd_again < 0) { + g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); + g_main_loop_quit (g_loop); + return NULL; + } +/* Add write event to epoll domain in order to re-enable as required by return + * value. We use one-shot flag to disable ASAP, as we don't want such events + * until triggered. + */ + if (pgm_epoll_ctl (tx_sock, efd_again, EPOLL_CTL_ADD, EPOLLOUT | EPOLLONESHOT) < 0) { + g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); + g_main_loop_quit (g_loop); + return NULL; + } + struct epoll_event event; + memset (&event, 0, sizeof(event)); + event.events = EPOLLIN; + event.data.fd = g_quit_pipe[0]; + if (epoll_ctl (efd_again, EPOLL_CTL_ADD, g_quit_pipe[0], &event) < 0) { + g_error ("epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); + g_main_loop_quit (g_loop); + return NULL; + } +#elif defined(CONFIG_HAVE_POLL) + int n_fds = 2; + struct pollfd fds[ 2 + 1 ]; +#endif /* !CONFIG_HAVE_EPOLL */ + + gethostname (hostname, sizeof(hostname)); + subject.append(hostname); + memset (payload, 0, sizeof(payload)); + + ping.mutable_subscription_header()->set_subject (subject); + ping.mutable_market_data_header()->set_msg_type (example::MarketDataHeader::MSG_VERIFY); + ping.mutable_market_data_header()->set_rec_type (example::MarketDataHeader::PING); + ping.mutable_market_data_header()->set_rec_status (example::MarketDataHeader::STATUS_OK); + ping.set_time (last); + + last = now = pgm_time_update_now(); + do { + if (g_msg_sent && g_latency_seqno + 1 == g_msg_sent) + latency = g_latency_current; + else + latency = g_odata_interval; + + ping.set_seqno (g_msg_sent); + ping.set_latency (latency); + ping.set_payload (payload, sizeof(payload)); + + const size_t header_size = pgm_pkt_offset (FALSE, g_pgmcc_family); + const size_t apdu_size = ping.ByteSize(); + struct pgm_sk_buff_t* skb = pgm_alloc_skb (g_max_tpdu); + pgm_skb_reserve (skb, header_size); + pgm_skb_put (skb, apdu_size); + +/* wait on packet rate limit */ + if ((last + g_odata_interval) > now) { +#ifndef _WIN32 + const unsigned int usec = g_odata_interval - (now - last); + usleep (usec); +#else + const DWORD msec = usecs_to_msecs (g_odata_interval - (now - last)); + Sleep (msec); +#endif + now = pgm_time_update_now(); + } + last += g_odata_interval; + ping.set_time (now); + ping.SerializeToArray (skb->data, skb->len); + + struct timeval tv; + int timeout; + size_t bytes_written; + int status; +again: + status = pgm_send_skbv (tx_sock, &skb, 1, TRUE, &bytes_written); + switch (status) { +/* rate control */ + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + const gboolean status = pgm_getsockopt (tx_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + if (G_UNLIKELY(!status)) { + g_error ("getting PGM_RATE_REMAIN failed"); + break; + } + timeout = (tv.tv_sec * 1000) + ((tv.tv_usec + 500) / 1000); +/* busy wait under 2ms */ + if (timeout < 2) timeout = 0; +#ifdef CONFIG_HAVE_EPOLL + const int ready = epoll_wait (efd_again, events, G_N_ELEMENTS(events), timeout /* ms */); +#elif defined(CONFIG_HAVE_POLL) + memset (fds, 0, sizeof(fds)); + fds[0].fd = g_quit_pipe[0]; + fds[0].events = POLLIN; + pgm_poll_info (tx_sock, &fds[1], &n_fds, POLLIN); + poll (fds, 1 + n_fds, timeout /* ms */); +#endif /* !CONFIG_HAVE_EPOLL */ + if (G_UNLIKELY(g_quit)) + break; + goto again; + } +/* congestion control */ + case PGM_IO_STATUS_CONGESTION: +/* kernel feedback */ + case PGM_IO_STATUS_WOULD_BLOCK: + { +#ifdef CONFIG_HAVE_EPOLL +# if 1 +/* re-enable write event for one-shot */ + if (pgm_epoll_ctl (tx_sock, efd_again, EPOLL_CTL_MOD, EPOLLOUT | EPOLLONESHOT) < 0) + { + g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); + g_main_loop_quit (g_loop); + return NULL; + } + const int ready = epoll_wait (efd_again, events, G_N_ELEMENTS(events), -1 /* ms */); + if (G_UNLIKELY(g_quit)) + break; +# else + const int ready = epoll_wait (efd_again, events, G_N_ELEMENTS(events), -1 /* ms */); + if (G_UNLIKELY(g_quit)) + break; + if (ready > 0 && + pgm_epoll_ctl (tx_sock, efd_again, EPOLL_CTL_MOD, EPOLLOUT | EPOLLONESHOT) < 0) + { + g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); + g_main_loop_quit (g_loop); + return NULL; + } +# endif +#elif defined(CONFIG_HAVE_POLL) + memset (fds, 0, sizeof(fds)); + fds[0].fd = g_quit_pipe[0]; + fds[0].events = POLLIN; + pgm_poll_info (g_sock, &fds[1], &n_fds, POLLOUT); + poll (fds, 1 + n_fds, -1 /* ms */); +#endif /* !CONFIG_HAVE_EPOLL */ + goto again; + } +/* successful delivery */ + case PGM_IO_STATUS_NORMAL: +// g_message ("sent payload: %s", ping.DebugString().c_str()); +// g_message ("sent %u bytes", (unsigned)bytes_written); + break; + default: + g_warning ("pgm_send_skbv failed, status:%i", status); + g_main_loop_quit (g_loop); + return NULL; + } + g_out_total += bytes_written; + g_msg_sent++; + } while (!g_quit); + +#ifdef CONFIG_HAVE_EPOLL + close (efd_again); +#endif + return NULL; +} + +static +gpointer +receiver_thread ( + gpointer data + ) +{ + pgm_sock_t* rx_sock = (pgm_sock_t*)data; + const long iov_len = 20; + struct pgm_msgv_t msgv[iov_len]; + pgm_time_t lost_tstamp = 0; + pgm_tsi_t lost_tsi; + guint32 lost_count = 0; + +#ifdef CONFIG_HAVE_EPOLL + const long ev_len = 1; + struct epoll_event events[ev_len]; + + int efd = epoll_create (IP_MAX_MEMBERSHIPS); + if (efd < 0) { + g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); + g_main_loop_quit (g_loop); + return NULL; + } + if (pgm_epoll_ctl (rx_sock, efd, EPOLL_CTL_ADD, EPOLLIN) < 0) { + g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); + g_main_loop_quit (g_loop); + return NULL; + } + struct epoll_event event; + memset (&event, 0, sizeof(event)); + event.events = EPOLLIN; + event.data.fd = g_quit_pipe[0]; + if (epoll_ctl (efd, EPOLL_CTL_ADD, g_quit_pipe[0], &event) < 0) { + g_error ("epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); + g_main_loop_quit (g_loop); + return NULL; + } +#elif defined(CONFIG_HAVE_POLL) + int n_fds = 3; + struct pollfd fds[ 3 + 1 ]; +#endif /* !CONFIG_HAVE_EPOLL */ + + memset (&lost_tsi, 0, sizeof(lost_tsi)); + + do { + struct timeval tv; + int timeout; + size_t len; + pgm_error_t* pgm_err = NULL; + const int status = pgm_recvmsgv (rx_sock, + msgv, + G_N_ELEMENTS(msgv), + MSG_ERRQUEUE, + &len, + &pgm_err); + if (lost_count) { + pgm_time_t elapsed = pgm_time_update_now() - lost_tstamp; + if (elapsed >= pgm_secs(1)) { + g_warning ("pgm data lost %" G_GUINT32_FORMAT " packets detected from %s", + lost_count, pgm_tsi_print (&lost_tsi)); + lost_count = 0; + } + } + + switch (status) { + case PGM_IO_STATUS_NORMAL: +// g_message ("recv %u bytes", (unsigned)len); + on_msgv (msgv, len); + break; + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + const gboolean status = pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); +//g_message ("timer pending %d", ((tv.tv_sec * 1000) + (tv.tv_usec / 1000))); + if (G_UNLIKELY(!status)) { + g_error ("getting PGM_TIME_REMAIN failed"); + break; + } + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + const gboolean status = pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); +//g_message ("rate limited %d", ((tv.tv_sec * 1000) + (tv.tv_usec / 1000))); + if (G_UNLIKELY(!status)) { + g_error ("getting PGM_RATE_REMAIN failed"); + break; + } + } +/* fall through */ + case PGM_IO_STATUS_WOULD_BLOCK: +//g_message ("would block"); +block: + timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); +/* busy wait under 2ms */ + if (timeout > 0 && timeout < 2) timeout = 0; +#ifdef CONFIG_HAVE_EPOLL + epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); +#elif defined(CONFIG_HAVE_POLL) + memset (fds, 0, sizeof(fds)); + fds[0].fd = g_quit_pipe[0]; + fds[0].events = POLLIN; + pgm_poll_info (g_sock, &fds[1], &n_fds, POLLIN); + poll (fds, 1 + n_fds, timeout /* ms */); +#endif /* !CONFIG_HAVE_EPOLL */ + break; + case PGM_IO_STATUS_RESET: + { + struct pgm_sk_buff_t* skb = msgv[0].msgv_skb[0]; + lost_tstamp = skb->tstamp; + if (pgm_tsi_equal (&skb->tsi, &lost_tsi)) + lost_count += skb->sequence; + else { + lost_count = skb->sequence; + memcpy (&lost_tsi, &skb->tsi, sizeof(pgm_tsi_t)); + } + pgm_free_skb (skb); + break; + } + default: + if (pgm_err) { + g_warning ("%s", pgm_err->message); + pgm_error_free (pgm_err); + pgm_err = NULL; + } + break; + } + } while (!g_quit); + +#ifdef CONFIG_HAVE_EPOLL + close (efd); +#endif + return NULL; +} + +static +int +on_msgv ( + struct pgm_msgv_t* msgv, /* an array of msgvs */ + size_t len + ) +{ + example::Ping ping; + guint i = 0; + static pgm_time_t last_time = pgm_time_update_now(); + + while (len) + { + const struct pgm_sk_buff_t* pskb = msgv[i].msgv_skb[0]; + gsize apdu_len = 0; + for (unsigned j = 0; j < msgv[i].msgv_len; j++) + apdu_len += msgv[i].msgv_skb[j]->len; + + if (PGMPING_MODE_REFLECTOR == g_mode) + { + int status; +again: + status = pgm_send (g_sock, pskb->data, pskb->len, NULL); + switch (status) { + case PGM_IO_STATUS_RATE_LIMITED: +g_message ("ratelimit"); goto again; + case PGM_IO_STATUS_CONGESTION: +g_message ("congestion"); goto again; + case PGM_IO_STATUS_WOULD_BLOCK: +g_message ("would block"); +/* busy wait always as reflector */ + goto again; + + case PGM_IO_STATUS_NORMAL: + break; + + default: + g_warning ("pgm_send_skbv failed"); + g_main_loop_quit (g_loop); + return 0; + } + goto next_msg; + } + +/* only parse first fragment of each apdu */ + if (!ping.ParseFromArray (pskb->data, pskb->len)) + goto next_msg; +// g_message ("payload: %s", ping.DebugString().c_str()); + + { + const pgm_time_t send_time = ping.time(); + const pgm_time_t recv_time = pskb->tstamp; + const guint64 seqno = ping.seqno(); + const guint64 latency = ping.latency(); + + if (seqno < g_latency_seqno) { + g_message ("seqno replay?"); + goto next_msg; + } + + g_in_total += pskb->len; + g_msg_received++; + +/* handle ping */ + const pgm_time_t now = pgm_time_update_now(); + if (send_time > now) + g_warning ("send time %" PGM_TIME_FORMAT " newer than now %" PGM_TIME_FORMAT, + send_time, now); + if (recv_time > now) + g_warning ("recv time %" PGM_TIME_FORMAT " newer than now %" PGM_TIME_FORMAT, + recv_time, now); + if (send_time >= recv_time){ + g_message ("timer mismatch, send time = recv time + %.3f ms (last time + %.3f ms)", + pgm_to_msecsf(send_time - recv_time), + pgm_to_msecsf(last_time - send_time)); + goto next_msg; + } + g_latency_current = pgm_to_secs(recv_time - send_time); + g_latency_seqno = seqno; + + const double elapsed = pgm_to_usecsf (recv_time - send_time); + g_latency_total += elapsed; + g_latency_square_total += elapsed * elapsed; + + if (elapsed > g_latency_max) + g_latency_max = elapsed; + if (elapsed < g_latency_min) + g_latency_min = elapsed; + + g_latency_running_average += elapsed; + g_latency_count++; + last_time = recv_time; + } + +/* move onto next apdu */ +next_msg: + i++; + len -= apdu_len; + } + + return 0; +} + +/* idle log notification + */ + +static +gboolean +on_mark ( + G_GNUC_UNUSED gpointer data + ) +{ + const pgm_time_t now = pgm_time_update_now (); + const double interval = pgm_to_secsf(now - g_interval_start); + g_interval_start = now; + +/* receiving a ping */ + if (g_latency_count) + { + const double average = g_latency_total / g_latency_count; + const double variance = g_latency_square_total / g_latency_count + - average * average; + const double standard_deviation = sqrt (variance); + + if (g_latency_count < 10) + { + if (average < 1000.0) + g_message ("seqno=%" G_GUINT64_FORMAT " time=%.01f us", + g_latency_seqno, average); + else + g_message ("seqno=%" G_GUINT64_FORMAT " time=%.01f ms", + g_latency_seqno, average / 1000); + } + else + { + double seq_rate = (g_latency_seqno - g_last_seqno) / interval; + double out_rate = g_out_total * 8.0 / 1000000.0 / interval; + double in_rate = g_in_total * 8.0 / 1000000.0 / interval; + if (g_latency_min < 1000.0) + g_message ("s=%.01f avg=%.01f min=%.01f max=%.01f stddev=%0.1f us o=%.2f i=%.2f mbit", + seq_rate, average, g_latency_min, g_latency_max, standard_deviation, out_rate, in_rate); + else + g_message ("s=%.01f avg=%.01f min=%.01f max=%.01f stddev=%0.1f ms o=%.2f i=%.2f mbit", + seq_rate, average / 1000, g_latency_min / 1000, g_latency_max / 1000, standard_deviation / 1000, out_rate, in_rate); + } + +/* reset interval counters */ + g_latency_total = 0.0; + g_latency_square_total = 0.0; + g_latency_count = 0; + g_last_seqno = g_latency_seqno; +#ifdef INFINITY + g_latency_min = INFINITY; +#else + g_latency_min = INT64_MAX; +#endif + g_latency_max = 0.0; + g_out_total = 0; + g_in_total = 0; + } + + return TRUE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/pgmrecv.c b/3rdparty/openpgm-svn-r1135/pgm/examples/pgmrecv.c new file mode 100644 index 0000000..eddbbc7 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/pgmrecv.c @@ -0,0 +1,649 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Simple receiver using the PGM transport, based on enonblocksyncrecvmsgv :/ + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAVE_EPOLL +# include +#endif +#include +#include +#ifdef G_OS_UNIX +# include +# include +# include +# include +# include +# include +# include +#else +# include "getopt.h" +#endif +#include +#ifdef CONFIG_WITH_HTTP +# include +#endif +#ifdef CONFIG_WITH_SNMP +# include +#endif + +/* example dependencies */ +#include +#include +#include + + +/* globals */ + +static int g_port = 0; +static const char* g_network = ""; +static const char* g_source = ""; +static gboolean g_multicast_loop = FALSE; +static int g_udp_encap_port = 0; + +static int g_max_tpdu = 1500; +static int g_sqns = 100; + +static pgm_sock_t* g_sock = NULL; +static GThread* g_thread = NULL; +static GMainLoop* g_loop = NULL; +static gboolean g_quit; +#ifdef G_OS_UNIX +static int g_quit_pipe[2]; +static void on_signal (int, gpointer); +#else +static HANDLE g_quit_event; +static BOOL on_console_ctrl (DWORD); +#endif + +static gboolean on_startup (gpointer); +static gboolean on_mark (gpointer); + +static gpointer receiver_thread (gpointer); +static int on_msgv (struct pgm_msgv_t*, size_t); + + +G_GNUC_NORETURN static void +usage ( + const char* bin + ) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -a : Source unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); +#ifdef CONFIG_WITH_HTTP + fprintf (stderr, " -H : Enable HTTP administrative interface\n"); +#endif +#ifdef CONFIG_WITH_SNMP + fprintf (stderr, " -S : Enable SNMP interface\n"); +#endif + fprintf (stderr, " -i : List available interfaces\n"); + exit (1); +} + +int +main ( + int argc, + char* argv[] + ) +{ + int e; + pgm_error_t* pgm_err = NULL; +#ifdef CONFIG_WITH_HTTP + gboolean enable_http = FALSE; +#endif +#ifdef CONFIG_WITH_SNMP + gboolean enable_snmpx = FALSE; +#endif + + setlocale (LC_ALL, ""); + +/* pre-initialise PGM messages module to add hook for GLib logging */ + pgm_messages_init(); + log_init (); + g_message ("pgmrecv"); + + if (!pgm_init (&pgm_err)) { + g_error ("Unable to start PGM engine: %s", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + pgm_error_free (pgm_err); + pgm_messages_shutdown(); + return EXIT_FAILURE; + } + + g_thread_init (NULL); + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "a:s:n:p:lih" +#ifdef CONFIG_WITH_HTTP + "H" +#endif +#ifdef CONFIG_WITH_SNMP + "S" +#endif + )) != -1) + { + switch (c) { + case 'n': g_network = optarg; break; + case 'a': g_source = optarg; break; + case 's': g_port = atoi (optarg); break; + case 'p': g_udp_encap_port = atoi (optarg); break; + + case 'l': g_multicast_loop = TRUE; break; +#ifdef CONFIG_WITH_HTTP + case 'H': enable_http = TRUE; break; +#endif +#ifdef CONFIG_WITH_SNMP + case 'S': enable_snmpx = TRUE; break; +#endif + + case 'i': + pgm_if_print_all(); + pgm_messages_shutdown(); + return EXIT_SUCCESS; + + case 'h': + case '?': + pgm_messages_shutdown(); + usage (binary_name); + } + } + +#ifdef CONFIG_WITH_HTTP + if (enable_http) { + if (!pgm_http_init (PGM_HTTP_DEFAULT_SERVER_PORT, &pgm_err)) { + g_error ("Unable to start HTTP interface: %s", pgm_err->message); + pgm_error_free (pgm_err); + pgm_shutdown(); + pgm_messages_shutdown(); + return EXIT_FAILURE; + } + } +#endif +#ifdef CONFIG_WITH_SNMP + if (enable_snmpx) { + if (!pgm_snmp_init (&pgm_err)) { + g_error ("Unable to start SNMP interface: %s", pgm_err->message); + pgm_error_free (pgm_err); +#ifdef CONFIG_WITH_HTTP + if (enable_http) + pgm_http_shutdown (); +#endif + pgm_shutdown (); + pgm_messages_shutdown(); + return EXIT_FAILURE; + } + } +#endif + + g_loop = g_main_loop_new (NULL, FALSE); + + g_quit = FALSE; + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif +#ifdef G_OS_UNIX + e = pipe (g_quit_pipe); + g_assert (0 == e); + pgm_signal_install (SIGINT, on_signal, g_loop); + pgm_signal_install (SIGTERM, on_signal, g_loop); +#else + g_quit_event = CreateEvent (NULL, TRUE, FALSE, TEXT("QuitEvent")); + SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); +#endif + +/* delayed startup */ + g_message ("scheduling startup."); + g_timeout_add (0, (GSourceFunc)on_startup, NULL); + +/* dispatch loop */ + g_message ("entering main event loop ... "); + g_main_loop_run (g_loop); + + g_message ("event loop terminated, cleaning up."); + +/* cleanup */ + g_quit = TRUE; +#ifdef G_OS_UNIX + const char one = '1'; + const size_t writelen = write (g_quit_pipe[1], &one, sizeof(one)); + g_assert (sizeof(one) == writelen); + g_thread_join (g_thread); + close (g_quit_pipe[0]); + close (g_quit_pipe[1]); +#else + SetEvent (g_quit_event); + g_thread_join (g_thread); + CloseHandle (g_quit_event); +#endif + + g_main_loop_unref (g_loop); + g_loop = NULL; + + if (g_sock) { + g_message ("closing PGM socket."); + + pgm_close (g_sock, TRUE); + g_sock = NULL; + } + +#ifdef CONFIG_WITH_HTTP + if (enable_http) + pgm_http_shutdown(); +#endif +#ifdef CONFIG_WITH_SNMP + if (enable_snmpx) + pgm_snmp_shutdown(); +#endif + + g_message ("PGM engine shutdown."); + pgm_shutdown(); + g_message ("finished."); + pgm_messages_shutdown(); + return EXIT_SUCCESS; +} + +#ifdef G_OS_UNIX +static +void +on_signal ( + int signum, + gpointer user_data + ) +{ + GMainLoop* loop = (GMainLoop*)user_data; + g_message ("on_signal (signum:%d user_data:%p)", + signum, user_data); + g_main_loop_quit (loop); +} +#else +static +BOOL +on_console_ctrl ( + DWORD dwCtrlType + ) +{ + g_message ("on_console_ctrl (dwCtrlType:%lu)", (unsigned long)dwCtrlType); + g_main_loop_quit (g_loop); + return TRUE; +} +#endif /* !G_OS_UNIX */ + +static +gboolean +on_startup ( + G_GNUC_UNUSED gpointer data + ) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + + g_message ("startup."); + +/* parse network parameter into transport address structure */ + if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { + g_error ("parsing network parameter: %s", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + if (g_udp_encap_port) { + g_message ("create PGM/UDP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + } else { + g_message ("create PGM/IP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int recv_only = 1, + passive = 0, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PASSIVE, &passive, sizeof(passive)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + g_error ("creating GSI: %s", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (g_sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + g_error ("binding PGM socket: %s", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int nonblocking = 1, + multicast_loop = g_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); + + if (!pgm_connect (g_sock, &pgm_err)) { + g_error ("connecting PGM socket: %s", pgm_err->message); + goto err_abort; + } + +/* create receiver thread */ + GError* glib_err = NULL; + g_thread = g_thread_create_full (receiver_thread, + g_sock, + 0, + TRUE, + TRUE, + G_THREAD_PRIORITY_HIGH, + &glib_err); + if (!g_thread) { + g_error ("g_thread_create_full failed errno %i: \"%s\"", glib_err->code, glib_err->message); + g_error_free (glib_err); + goto err_abort; + } + +/* period timer to indicate some form of life */ +// TODO: Gnome 2.14: replace with g_timeout_add_seconds() + g_timeout_add(10 * 1000, (GSourceFunc)on_mark, NULL); + + g_message ("startup complete."); + return FALSE; + +err_abort: + if (NULL != g_sock) { + pgm_close (g_sock, FALSE); + g_sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + g_main_loop_quit (g_loop); + return FALSE; +} + +/* idle log notification + */ + +static +gboolean +on_mark ( + G_GNUC_UNUSED gpointer data + ) +{ + g_message ("-- MARK --"); + return TRUE; +} + +static +gpointer +receiver_thread ( + gpointer data + ) +{ + pgm_sock_t* rx_sock = (pgm_sock_t*)data; + const long iov_len = 20; + const long ev_len = 1; + struct pgm_msgv_t msgv[iov_len]; + +#ifdef CONFIG_HAVE_EPOLL + struct epoll_event events[ev_len]; /* wait for maximum 1 event */ + int timeout; + const int efd = epoll_create (IP_MAX_MEMBERSHIPS); + if (efd < 0) { + g_error ("epoll_create failed errno %i: \"%s\"", errno, strerror(errno)); + g_main_loop_quit (g_loop); + return NULL; + } + + if (pgm_epoll_ctl (rx_sock, efd, EPOLL_CTL_ADD, EPOLLIN) < 0) + { + g_error ("pgm_epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); + g_main_loop_quit (g_loop); + return NULL; + } + struct epoll_event event; + event.events = EPOLLIN; + event.data.fd = g_quit_pipe[0]; + if (epoll_ctl (efd, EPOLL_CTL_ADD, g_quit_pipe[0], &event) < 0) + { + g_error ("epoll_ctl failed errno %i: \"%s\"", errno, strerror(errno)); + g_main_loop_quit (g_loop); + return NULL; + } +#elif defined(CONFIG_HAVE_POLL) + int timeout; + int n_fds = 2; + struct pollfd fds[ 1 + n_fds ]; +#elif defined(G_OS_UNIX) /* HAVE_SELECT */ + int n_fds; + fd_set readfds; +#else /* G_OS_WIN32 */ + int n_handles = 3; +# if (__STDC_VERSION__ >= 199901L) + HANDLE waitHandles[n_handles]; +# else + HANDLE* waitHandles = (HANDLE*)g_malloc (n_handles * sizeof(HANDLE));; +# endif + DWORD timeout, dwEvents; + WSAEVENT recvEvent, pendingEvent; + + recvEvent = WSACreateEvent (); + WSAEventSelect (pgm_transport_get_recv_fd (g_transport), recvEvent, FD_READ); + pendingEvent = WSACreateEvent (); + WSAEventSelect (pgm_transport_get_pending_fd (g_transport), pendingEvent, FD_READ); + + waitHandles[0] = g_quit_event; + waitHandles[1] = recvEvent; + waitHandles[2] = pendingEvent; +#endif /* !CONFIG_HAVE_EPOLL */ + + do { + struct timeval tv; + size_t len; + pgm_error_t* pgm_err = NULL; + const int status = pgm_recvmsgv (rx_sock, + msgv, + G_N_ELEMENTS(msgv), + 0, + &len, + &pgm_err); + switch (status) { + case PGM_IO_STATUS_NORMAL: + on_msgv (msgv, len); + break; + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } +/* fall through */ + case PGM_IO_STATUS_WOULD_BLOCK: +block: +#ifdef CONFIG_HAVE_EPOLL + timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + epoll_wait (efd, events, G_N_ELEMENTS(events), timeout /* ms */); +#elif defined(CONFIG_HAVE_POLL) + timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + memset (fds, 0, sizeof(fds)); + fds[0].fd = g_quit_pipe[0]; + fds[0].events = POLLIN; + pgm_poll_info (rx_sock, &fds[1], &n_fds, POLLIN); + poll (fds, 1 + n_fds, timeout /* ms */); +#elif defined(G_OS_UNIX) /* HAVE_SELECT */ + FD_ZERO(&readfds); + FD_SET(g_quit_pipe[0], &readfds); + n_fds = g_quit_pipe[0] + 1; + pgm_select_info (rx_sock, &readfds, NULL, &n_fds); + select (n_fds, &readfds, NULL, NULL, PGM_IO_STATUS_RATE_LIMITED == status ? &tv : NULL); +#else /* G_OS_WIN32 */ + timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, timeout); + switch (dwEvents) { + case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; + case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break; + default: break; + } +#endif /* !CONFIG_HAVE_EPOLL */ + break; + + default: + if (pgm_err) { + g_warning ("%s", pgm_err->message); + pgm_error_free (pgm_err); + pgm_err = NULL; + } + if (PGM_IO_STATUS_ERROR == status) + break; + } + } while (!g_quit); + +#ifdef CONFIG_HAVE_EPOLL + close (efd); +#elif defined(G_OS_WIN32) + WSACloseEvent (recvEvent); + WSACloseEvent (pendingEvent); +# if (__STDC_VERSION__ < 199901L) + g_free (waitHandles); +# endif +#endif + return NULL; +} + +static +int +on_msgv ( + struct pgm_msgv_t* msgv, /* an array of msgvs */ + size_t len + ) +{ + g_message ("(%u bytes)", + (unsigned)len); + + guint i = 0; +/* for each apdu */ + do { + const struct pgm_sk_buff_t* pskb = msgv[i].msgv_skb[0]; + gsize apdu_len = 0; + for (unsigned j = 0; j < msgv[i].msgv_len; j++) + apdu_len += msgv[i].msgv_skb[j]->len; +/* truncate to first fragment to make GLib printing happy */ + char buf[2048], tsi[PGM_TSISTRLEN]; + const gsize buflen = MIN(sizeof(buf) - 1, pskb->len); + strncpy (buf, (const char*)pskb->data, buflen); + buf[buflen] = '\0'; + pgm_tsi_print_r (&pskb->tsi, tsi, sizeof(tsi)); + if (msgv[i].msgv_len > 1) + g_message ("\t%u: \"%s\" ... (%" G_GSIZE_FORMAT " bytes from %s)", + i, buf, apdu_len, tsi); + else + g_message ("\t%u: \"%s\" (%" G_GSIZE_FORMAT " bytes from %s)", + i, buf, apdu_len, tsi); + i++; + len -= apdu_len; + } while (len); + + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/pgmsend.c b/3rdparty/openpgm-svn-r1135/pgm/examples/pgmsend.c new file mode 100644 index 0000000..6fd85a1 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/pgmsend.c @@ -0,0 +1,305 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Simple sender using the PGM transport. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef G_OS_UNIX +# include +# include +# include +# include +# include +# include +#else +# include "getopt.h" +#endif +#include + +/* example dependencies */ +#include +#include + + +/* typedefs */ + +/* globals */ + +static int g_port = 0; +static const char* g_network = ""; +static gboolean g_multicast_loop = FALSE; +static int g_udp_encap_port = 0; + +static int g_max_tpdu = 1500; +static int g_max_rte = 400*1000; +static int g_sqns = 100; + +static gboolean g_fec = FALSE; +static int g_k = 8; +static int g_n = 255; + +static pgm_sock_t* g_sock = NULL; + +static gboolean create_pgm_socket (void); + + +G_GNUC_NORETURN static +void +usage (const char* bin) +{ + fprintf (stderr, "Usage: %s [options] message\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -r : Regulate to rate bytes per second\n"); + fprintf (stderr, " -f : Enable FEC with either proactive or ondemand parity\n"); + fprintf (stderr, " -K : Configure Reed-Solomon code (n, k)\n"); + fprintf (stderr, " -N \n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); + fprintf (stderr, " -i : List available interfaces\n"); + exit (1); +} + +int +main ( + int argc, + char *argv[] + ) +{ + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + +/* pre-initialise PGM messages module to add hook for GLib logging */ + pgm_messages_init(); + log_init(); + if (!pgm_init (&pgm_err)) { + g_error ("Unable to start PGM engine: %s", pgm_err->message); + pgm_error_free (pgm_err); + pgm_messages_shutdown(); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:p:r:f:K:N:lih")) != -1) + { + switch (c) { + case 'n': g_network = optarg; break; + case 's': g_port = atoi (optarg); break; + case 'p': g_udp_encap_port = atoi (optarg); break; + case 'r': g_max_rte = atoi (optarg); break; + + case 'f': g_fec = TRUE; break; + case 'K': g_k = atoi (optarg); break; + case 'N': g_n = atoi (optarg); break; + + case 'l': g_multicast_loop = TRUE; break; + + case 'i': + pgm_if_print_all(); + pgm_messages_shutdown(); + return EXIT_SUCCESS; + + case 'h': + case '?': + pgm_messages_shutdown(); + usage (binary_name); + } + } + + if (g_fec && ( !g_k || !g_n )) { + pgm_messages_shutdown(); + g_error ("Invalid Reed-Solomon parameters RS(%d, %d).", g_n, g_k); + usage (binary_name); + } + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif + + if (create_pgm_socket()) + { + while (optind < argc) { + const int status = pgm_send (g_sock, argv[optind], strlen(argv[optind]) + 1, NULL); + if (PGM_IO_STATUS_NORMAL != status) { + g_warning ("pgm_send failed."); + } + optind++; + } + } + +/* cleanup */ + if (g_sock) { + pgm_close (g_sock, TRUE); + g_sock = NULL; + } + pgm_shutdown(); + pgm_messages_shutdown(); + return EXIT_SUCCESS; +} + +static +gboolean +create_pgm_socket (void) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + +/* parse network parameter into PGM socket address structure */ + if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { + g_error ("Parsing network parameter: %s", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + if (g_udp_encap_port) { + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + g_error ("Creating PGM/UDP socket: %s", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + } else { + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + g_error ("Creating PGM/IP socket: %s", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int send_only = 1, + ambient_spm = pgm_secs (30), + heartbeat_spm[] = { pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (1300), + pgm_secs (7), + pgm_secs (16), + pgm_secs (25), + pgm_secs (30) }; + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_ONLY, &send_only, sizeof(send_only)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TXW_SQNS, &g_sqns, sizeof(g_sqns)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TXW_MAX_RTE, &g_max_rte, sizeof(g_max_rte)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm)); + if (g_fec) { + struct pgm_fecinfo_t fecinfo; + fecinfo.block_size = g_n; + fecinfo.proactive_packets = 0; + fecinfo.group_size = g_k; + fecinfo.ondemand_parity_enabled = TRUE; + fecinfo.var_pktlen_enabled = TRUE; + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); + } + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + g_error ("Creating GSI: %s", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (g_sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + g_error ("Binding PGM socket: %s", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int blocking = 0, + multicast_loop = g_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NOBLOCK, &blocking, sizeof(blocking)); + + if (!pgm_connect (g_sock, &pgm_err)) { + g_error ("Connecting PGM socket: %s", pgm_err->message); + goto err_abort; + } + + return TRUE; + +err_abort: + if (NULL != g_sock) { + pgm_close (g_sock, FALSE); + g_sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/pgmtop.c b/3rdparty/openpgm-svn-r1135/pgm/examples/pgmtop.c new file mode 100644 index 0000000..9b18310 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/pgmtop.c @@ -0,0 +1,1031 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM packet monitor. + * + * Copyright (c) 2006-2007 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* PGM internals */ +#include + +/* example dependencies */ +#include +#include + + +struct ncurses_window; + +typedef void (*paint_func)(struct ncurses_window*); +typedef void (*resize_func)(struct ncurses_window*, int, int); + +struct ncurses_window { + WINDOW* window; + PANEL* panel; + char* title; + paint_func paint; + resize_func resize; +}; + +struct pgm_stat { + gulong count, snap_count; + gulong bytes, snap_bytes; + gulong tsdu; + + gulong duplicate; + gulong invalid; + + struct timeval last; + struct timeval last_valid; + struct timeval last_invalid; +}; + +struct pgm_netstat { + struct in_addr addr; + gulong corrupt; +}; + +struct pgm_hoststat { + pgm_tsi_t tsi; + + struct in_addr last_addr; + struct in_addr nla; + + gulong txw_secs; + gulong txw_trail; + gulong txw_lead; + gulong txw_sqns; + + gulong rxw_trail; + gulong rxw_lead; + + gulong rxw_trail_init; + gboolean window_defined; + gboolean rxw_constrained; + + gulong spm_sqn; + + struct pgm_stat spm, + poll, + polr, + odata, + rdata, + nak, + nnak, + ncf, + spmr, + + general; + + struct timeval session_start; +}; + + +/* globals */ + +static int g_port = 7500; +static const char* g_network = "239.192.0.1"; +static struct in_addr g_filter = { 0 }; + +static GIOChannel* g_io_channel = NULL; +static GIOChannel* g_stdin_channel = NULL; + +static GMainLoop* g_loop = NULL; + +static guint g_status_height = 6; +static guint g_info_width = 10; +static time_t start_time; + +static struct ncurses_window *g_peer, *g_info, *g_status, *g_active; +static GList* g_window_list = NULL; +static guint g_paint_interval = ( 1 * 1000 ) / 15; +static guint g_snap_interval = 10 * 1000; +static struct timeval g_last_snap, g_now; + +static GList* g_status_list = NULL; + +static guint32 g_packets = 0; +static GHashTable *g_hosts = NULL; +static GHashTable *g_nets = NULL; + +static void init_ncurses (void); +static void paint_ncurses (void); +static void resize_ncurses (int, int); + +static void paint_peer (struct ncurses_window*); +static gboolean tsi_row (gpointer, gpointer, gpointer); + +static void paint_info (struct ncurses_window*); +static void paint_status (struct ncurses_window*); +static void resize_peer (struct ncurses_window*, int, int); +static void resize_info (struct ncurses_window*, int, int); +static void resize_status (struct ncurses_window*, int, int); + +static void write_status (const gchar*, ...) G_GNUC_PRINTF (1, 2); +static void write_statusv (const gchar*, va_list); + +static void on_signal (int, gpointer); +static void on_winch (int); +static gboolean on_startup (gpointer); +static gboolean on_snap (gpointer); +static gboolean on_paint (gpointer); + +static gboolean on_io_data (GIOChannel*, GIOCondition, gpointer); +static gboolean on_io_error (GIOChannel*, GIOCondition, gpointer); + +static gboolean on_stdin_data (GIOChannel*, GIOCondition, gpointer); + +int +main ( + G_GNUC_UNUSED int argc, + G_GNUC_UNUSED char *argv[] + ) +{ + GError* err = NULL; + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + + log_init (); + g_message ("pgmtop"); + + if (!pgm_init (&pgm_err)) { + g_error ("Unable to start PGM engine: %s", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + + g_loop = g_main_loop_new (NULL, FALSE); + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); + signal (SIGHUP, SIG_IGN); + pgm_signal_install (SIGINT, on_signal, g_loop); + pgm_signal_install (SIGTERM, on_signal, g_loop); + +/* delayed startup */ + g_message ("scheduling startup.n"); + g_timeout_add(0, (GSourceFunc)on_startup, g_loop); + +/* dispatch loop */ + g_message ("entering main event loop ..."); + g_main_loop_run (g_loop); + + endwin(); + g_message ("event loop terminated, cleaning up."); + +/* cleanup */ + g_main_loop_unref (g_loop); + g_loop = NULL; + if (g_io_channel) { + g_message ("closing socket."); + g_io_channel_shutdown (g_io_channel, FALSE, &err); + g_io_channel = NULL; + } + + if (g_stdin_channel) { + g_message ("unbinding stdin."); + g_io_channel_unref (g_stdin_channel); + g_stdin_channel = NULL; + } + + g_message ("PGM engine shutdown."); + pgm_shutdown (); + g_message ("finished."); + return EXIT_SUCCESS; +} + +static struct ncurses_window* +create_window ( + char* name, + paint_func paint, + resize_func resize + ) +{ + struct ncurses_window* nw = g_malloc0 (sizeof(struct ncurses_window)); + nw->window = newwin (0, 0, 0, 0); + nw->panel = new_panel (nw->window); + nw->title = name; + + nw->paint = paint; + nw->resize = resize; + + g_window_list = g_list_append (g_window_list, nw); + return nw; +} + +/* +-Peer list --------------++-Info-+ + * | || | + * | < peer window > || < info window > + * | || | + * +-------------------------++------+ + * +-Status--------------------------+ + * | < status window > | + * +---------------------------------+ + */ + +static void +init_ncurses (void) +{ +/* setup ncurses terminal display */ + initscr(); /* init ncurses library */ + +// signal_install (SIGWINCH, on_winch); + + noecho(); /* hide entered keys */ + cbreak(); + +/* setup ncurses windows */ + g_peer = create_window ("Peers", paint_peer, resize_peer); + + g_info = create_window ("Info", paint_info, resize_info); + start_time = time (0); + + g_status = create_window ("Status", paint_status, resize_status); + scrollok (g_status->window, 1); + + g_active = g_peer; + top_panel (g_active->panel); + + paint_ncurses(); +} + +static void +resize_ncurses ( + int hsize, + int vsize + ) +{ + GList* nw_list = g_window_list; + while (nw_list) + { + struct ncurses_window* nw = (struct ncurses_window*)nw_list->data; + + nw->resize (nw, hsize, vsize); + + nw_list = nw_list->next; + } +} + +static void +paint_ncurses (void) +{ + static int hsize = 0, vsize = 0; + + if (hsize != COLS || vsize != LINES) + { + hsize = COLS; vsize = LINES; + resize_ncurses(hsize, vsize); + } + + GList* nw_list = g_window_list; + while (nw_list) + { + struct ncurses_window* nw = (struct ncurses_window*)nw_list->data; + werase (nw->window); + + box (nw->window, ACS_VLINE, ACS_HLINE); + mvwaddstr (nw->window, 0, 2, nw->title); + + nw->paint (nw); + + nw_list = nw_list->next; + } + +/* have cursor stay at top left of active window */ + wmove (g_active->window, 0, 0); + + update_panels(); /* update virtual screen */ + doupdate(); /* update real screen */ +} + +/* peer window */ + +static void +paint_peer ( + struct ncurses_window* nw + ) +{ + +/* 1 2 3 4 5 6 7 8 + * 012345678901234567890123456789012345678901234567890123456789012345678901234567890 + * TSI Packets Bytes Packet/s Bit/s Data Inv Dupe + * 100.200.300.400.500.600.70000 1,000K 1,000MB 1,000 1,000 100% 100% 100% + */ + mvwaddstr (nw->window, 1, 1, "TSI"); + mvwaddstr (nw->window, 1, 32, "Packets"); + mvwaddstr (nw->window, 1, 40, "Bytes"); + mvwaddstr (nw->window, 1, 48, "Packet/s"); + mvwaddstr (nw->window, 1, 58, "Bit/s"); + mvwaddstr (nw->window, 1, 68, "Data"); + mvwaddstr (nw->window, 1, 73, "Inv"); + mvwaddstr (nw->window, 1, 78, "Dupe"); + + if (g_hosts) + { + int row = 2; + gettimeofday(&g_now, NULL); + g_hash_table_foreach (g_hosts, (GHFunc)tsi_row, &row); + } +} + +static char* +print_si ( + float* v + ) +{ + static char prefix[5] = ""; + + if (*v > 100 * 1000 * 1000) { + strcpy (prefix, "G"); + *v /= 1000.0 * 1000.0 * 1000.0; + } else if (*v > 100 * 1000) { + strcpy (prefix, "M"); + *v /= 1000.0 * 1000.0; + } else if (*v > 100) { + strcpy (prefix, "K"); + *v /= 1000.0; + } else { + *prefix = 0; + } + + return prefix; +} + +static gboolean +tsi_row ( + G_GNUC_UNUSED gpointer key, + gpointer value, + gpointer user_data + ) +{ + struct pgm_hoststat* hoststat = value; + int* row = user_data; + + float secs = (g_now.tv_sec - g_last_snap.tv_sec) + + ( (g_now.tv_usec - g_last_snap.tv_usec) / 1000.0 / 1000.0 ); + +/* TSI */ + char* tsi_string = pgm_tsi_print (&hoststat->tsi); + mvwaddstr (g_peer->window, *row, 1, tsi_string); + +/* Packets */ + char buffer[100]; + float v = hoststat->general.count; + char* prefix = print_si (&v); + snprintf (buffer, sizeof(buffer), "%lu%s", (gulong)v, prefix); + mvwaddstr (g_peer->window, *row, 32, buffer); + +/* Bytes */ + v = hoststat->general.bytes; + prefix = print_si (&v); + snprintf (buffer, sizeof(buffer), "%lu%s", (gulong)v, prefix); + mvwaddstr (g_peer->window, *row, 40, buffer); + +/* Packet/s */ + v = ( hoststat->general.count - hoststat->general.snap_count ) / secs; + prefix = print_si (&v); + snprintf (buffer, sizeof(buffer), "%.1f%s", v, prefix); + mvwaddstr (g_peer->window, *row, 48, buffer); + +/* Bit/s */ + float bitrate = ((float)( hoststat->general.bytes - hoststat->general.snap_bytes ) * 8.0 / secs); + char* bitprefix = print_si (&bitrate); + snprintf (buffer, sizeof(buffer), "%.1f%s", bitrate, bitprefix); + mvwaddstr (g_peer->window, *row, 58, buffer); + +/* % Data */ + snprintf (buffer, sizeof(buffer), "%d%%", (int)((100.0 * hoststat->odata.tsdu) / hoststat->general.bytes)); + mvwaddstr (g_peer->window, *row, 68, buffer); + +/* % Invalid */ + snprintf (buffer, sizeof(buffer), "%d%%", (int)(hoststat->general.invalid ? (100.0 * hoststat->general.invalid) / hoststat->general.count : 0.0)); + mvwaddstr (g_peer->window, *row, 73, buffer); + +/* % Duplicate */ + snprintf (buffer, sizeof(buffer), "%d%%", (int)(hoststat->general.duplicate ? (100.0 * hoststat->general.duplicate) / hoststat->general.count : 0.0)); + mvwaddstr (g_peer->window, *row, 78, buffer); + + *row = *row + 1; + + return FALSE; +} + +static void +resize_peer ( + struct ncurses_window* nw, + int hsize, /* COLS */ + int vsize /* LINES */ + ) +{ + wresize (nw->window, vsize - g_status_height, hsize - g_info_width); + replace_panel (nw->panel, nw->window); + move_panel (nw->panel, 0, 0); +} + +/* info window */ + +static void +paint_info ( + struct ncurses_window* nw + ) +{ + char buffer[20]; + + mvwaddstr (nw->window, 1, 2, "Peers"); + snprintf (buffer, sizeof(buffer), "%d", g_hosts ? g_hash_table_size (g_hosts) : 0); + mvwaddstr (nw->window, 2, 2, buffer); + + mvwaddstr (nw->window, 3, 2, "Packets"); + snprintf (buffer, sizeof(buffer), "%d", g_packets); + mvwaddstr (nw->window, 4, 2, buffer); + + mvwaddstr (nw->window, LINES - g_status_height - 2, 2, "Elapsed"); + time_t elapsed = time(0) - start_time; + snprintf (buffer, sizeof(buffer), "%02d:%02d:%02d", + (int) (elapsed / 60) / 60, (int) (elapsed / 60) % 60, + (int) elapsed % 60); + mvwaddstr (nw->window, LINES - g_status_height - 1, 1, buffer); +} + +static void +resize_info ( + struct ncurses_window* nw, + int hsize, /* COLS */ + int vsize /* LINES */ + ) +{ + wresize (nw->window, vsize - g_status_height, g_info_width); + replace_panel (nw->panel, nw->window); + move_panel (nw->panel, 0, hsize - g_info_width); +} + +/* status window */ + +static void +paint_status ( + G_GNUC_UNUSED struct ncurses_window* nw + ) +{ + if (!g_status_list) return; + + guint len = g_list_length (g_status_list); + while (len > g_status_height) { + g_free (g_status_list->data); + g_status_list = g_list_delete_link (g_status_list, g_status_list); + len--; + } + guint y = 1; + GList* list = g_status_list; + while (list) { + mvwaddstr (g_status->window, y++, 3, (char*)list->data); + list = list->next; + } +} + +static void +resize_status ( + struct ncurses_window* nw, + int hsize, /* COLS */ + int vsize /* LINES */ + ) +{ + wresize (nw->window, g_status_height, hsize); + replace_panel (nw->panel, nw->window); + move_panel (nw->panel, vsize - g_status_height, 0); +} + +static void +write_status ( + const gchar* format, + ... + ) +{ + va_list args; + + va_start (args, format); + write_statusv (format, args); + va_end (args); +} + +static void +write_statusv ( + const gchar* format, + va_list args1 + ) +{ + char buffer[1024]; + vsnprintf (buffer, sizeof(buffer), format, args1); + + g_status_list = g_list_append (g_status_list, g_memdup (buffer, strlen(buffer)+1)); +} + +static +void +on_signal ( + int signum, + gpointer user_data + ) +{ + GMainLoop* loop = (GMainLoop*)user_data; + puts ("on_signal"); + g_main_loop_quit (loop); +} + +/* terminal resize signal + */ + +static void +on_winch ( + G_GNUC_UNUSED int signum + ) +{ + paint_ncurses (); +} + +static gboolean +on_startup ( + gpointer user_data + ) +{ + GMainLoop* loop = (GMainLoop*)user_data; + int e; + + puts ("startup."); + +/* find PGM protocol id */ +// TODO: fix valgrind errors + int ipproto_pgm = IPPROTO_PGM; +#if HAVE_GETPROTOBYNAME_R + char b[1024]; + struct protoent protobuf, *proto; + e = getprotobyname_r ("pgm", &protobuf, b, sizeof(b), &proto); + if (e != -1 && proto != NULL) { + if (proto->p_proto != ipproto_pgm) { + print f("Setting PGM protocol number to %i from /etc/protocols.\n", proto->p_proto); + ipproto_pgm = proto->p_proto; + } + } +#else + struct protoent *proto = getprotobyname ("pgm"); + if (proto != NULL) { + if (proto->p_proto != ipproto_pgm) { + printf("Setting PGM protocol number to %i from /etc/protocols.\n", proto->p_proto); + ipproto_pgm = proto->p_proto; + } + } +#endif + +/* open socket for snooping */ + puts ("opening raw socket."); + int sock = socket (PF_INET, SOCK_RAW, ipproto_pgm); + if (sock < 0) { + int _e = errno; + puts ("on_startup() failed"); + + if (_e == EPERM && 0 != getuid()) { + puts ("PGM protocol requires this program to run as superuser."); + } + g_main_loop_quit (loop); + return FALSE; + } + +/* drop out of setuid 0 */ + if (0 == getuid ()) { + puts ("dropping superuser privileges."); + setuid ((gid_t)65534); + setgid ((uid_t)65534); + } + + char _t = 1; + e = setsockopt (sock, IPPROTO_IP, IP_HDRINCL, &_t, sizeof(_t)); + if (e < 0) { + printw ("on_startup() failed\n"); + close (sock); + g_main_loop_quit (loop); + return FALSE; + } + +/* buffers */ + int buffer_size = 0; + socklen_t len = 0; + e = getsockopt (sock, SOL_SOCKET, SO_RCVBUF, &buffer_size, &len); + if (e == 0) { + printf ("receive buffer set at %i bytes.\n", buffer_size); + } + e = getsockopt (sock, SOL_SOCKET, SO_SNDBUF, &buffer_size, &len); + if (e == 0) { + printf ("send buffer set at %i bytes.\n", buffer_size); + } + +/* bind */ + struct sockaddr_in addr; + memset (&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + e = bind (sock, (struct sockaddr*)&addr, sizeof(addr)); + if (e < 0) { + printw ("on_startup() failed\n"); + close (sock); + g_main_loop_quit (loop); + return FALSE; + } + +/* multicast */ + struct ip_mreq mreq; + memset (&mreq, 0, sizeof(mreq)); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + printf ("listening on interface %s.\n", inet_ntoa(mreq.imr_interface)); + mreq.imr_multiaddr.s_addr = inet_addr(g_network); + printf ("subscription on multicast address %s.\n", inet_ntoa(mreq.imr_multiaddr)); + e = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + if (e < 0) { + printw ("on_startup() failed\n"); + close (sock); + g_main_loop_quit (loop); + return FALSE; + } + +/* multicast loopback */ +/* multicast ttl */ + +/* add socket to event manager */ + g_io_channel = g_io_channel_unix_new (sock); + printf ("socket opened with encoding %s.\n", g_io_channel_get_encoding(g_io_channel)); + + /* guint event = */ g_io_add_watch (g_io_channel, G_IO_IN | G_IO_PRI, on_io_data, NULL); + /* guint event = */ g_io_add_watch (g_io_channel, G_IO_ERR | G_IO_HUP | G_IO_NVAL, on_io_error, NULL); + +/* add stdin to event manager */ + g_stdin_channel = g_io_channel_unix_new (fileno(stdin)); + printf ("binding stdin with encoding %s.\n", g_io_channel_get_encoding(g_stdin_channel)); + + g_io_add_watch (g_stdin_channel, G_IO_IN | G_IO_PRI, on_stdin_data, NULL); + +/* periodic timer to snapshot statistics */ + g_timeout_add (g_snap_interval, (GSourceFunc)on_snap, NULL); + +/* period timer to update screen */ + g_timeout_add (g_paint_interval, (GSourceFunc)on_paint, NULL); + + puts ("READY"); + + init_ncurses(); + return FALSE; +} + +static gboolean +on_paint ( + G_GNUC_UNUSED gpointer data + ) +{ + paint_ncurses(); + + return TRUE; +} + +static guint +tsi_hash ( + gconstpointer v + ) +{ + return g_str_hash(pgm_tsi_print(v)); +} + +static gint +tsi_equal ( + gconstpointer v, + gconstpointer v2 + ) +{ + return memcmp (v, v2, (6 * sizeof(guint8)) + sizeof(guint16)) == 0; +} + +static gboolean +on_io_data ( + GIOChannel* source, + G_GNUC_UNUSED GIOCondition condition, + G_GNUC_UNUSED gpointer user_data + ) +{ + struct timeval now; + struct pgm_sk_buff_t* skb = pgm_alloc_skb (4096); + struct sockaddr_storage src, dst; + struct sockaddr_in* sin = (struct sockaddr_in*)&src; + socklen_t src_addr_len = sizeof(src); + int fd = g_io_channel_unix_get_fd(source); + + skb->len = recvfrom(fd, skb->head, 4096, MSG_DONTWAIT, (struct sockaddr*)&src, &src_addr_len); + + gettimeofday (&now, NULL); + g_packets++; + + GError* err = NULL; + gboolean is_valid = pgm_parse_raw (skb, (struct sockaddr*)&dst, &err); + if (!is_valid && err && PGM_PACKET_ERROR_CKSUM == err->code) + { +/* corrupt packet */ + if (!g_nets) { + g_nets = g_hash_table_new (g_int_hash, g_int_equal); + } + + struct pgm_netstat* netstat = g_hash_table_lookup (g_nets, &sin->sin_addr); + if (netstat == NULL) { + write_status ("new host publishing corrupt data, local nla %s", inet_ntoa(sin->sin_addr)); + netstat = g_malloc0(sizeof(struct pgm_netstat)); + netstat->addr = sin->sin_addr; + g_hash_table_insert (g_nets, (gpointer)&netstat->addr, (gpointer)netstat); + } + + netstat->corrupt++; + pgm_free_skb (skb); + return TRUE; + } + else if (!is_valid) + { +/* general error */ + pgm_free_skb (skb); + return TRUE; + } + +/* search for existing session */ + if (!g_hosts) { + g_hosts = g_hash_table_new (tsi_hash, tsi_equal); + } + + struct pgm_hoststat* hoststat = g_hash_table_lookup (g_hosts, &skb->tsi); + if (hoststat == NULL) { + write_status ("new tsi %s with local nla %s", pgm_tsi_print (&skb->tsi), inet_ntoa(sin->sin_addr)); + + hoststat = g_malloc0(sizeof(struct pgm_hoststat)); + memcpy (&hoststat->tsi, &skb->tsi, sizeof(pgm_tsi_t)); + hoststat->session_start = now; + + g_hash_table_insert (g_hosts, (gpointer)&hoststat->tsi, (gpointer)hoststat); + } + +/* increment statistics */ + memcpy (&hoststat->last_addr, &sin->sin_addr, sizeof(sin->sin_addr)); + hoststat->general.count++; + hoststat->general.bytes += skb->len; + hoststat->general.last = now; + + skb->data = (guint8*)skb->data + sizeof(struct pgm_header); + skb->len -= sizeof(struct pgm_header); + +/* repurpose is_valid for PGM subtype */ + is_valid = FALSE; + switch (skb->pgm_header->pgm_type) { + case PGM_SPM: + hoststat->spm.count++; + hoststat->spm.bytes += skb->len; + hoststat->spm.last = now; + + is_valid = pgm_verify_spm (skb); + if (!is_valid) { + hoststat->spm.invalid++; + hoststat->spm.last_invalid = now; + } else { + const struct pgm_spm* spm = (struct pgm_spm*)skb->data; + + hoststat->nla.s_addr = spm->spm_nla.s_addr; + if (pgm_uint32_lte (g_ntohl( spm->spm_sqn ), hoststat->spm_sqn)) { + hoststat->general.duplicate++; + break; + } + hoststat->spm_sqn = g_ntohl( spm->spm_sqn ); + hoststat->txw_trail = g_ntohl( spm->spm_trail ); + hoststat->txw_lead = g_ntohl( spm->spm_lead ); + hoststat->rxw_trail = hoststat->txw_trail; + hoststat->window_defined = TRUE; + } + break; + + case PGM_ODATA: + hoststat->odata.count++; + hoststat->odata.bytes += skb->len; + hoststat->odata.last = now; + + const struct pgm_data* data = (struct pgm_data*)skb->data; + + if (!hoststat->window_defined) { + hoststat->rxw_lead = g_ntohl (data->data_sqn) - 1; + hoststat->rxw_trail = hoststat->rxw_trail_init = hoststat->rxw_lead + 1; + hoststat->rxw_constrained = TRUE; + hoststat->window_defined = TRUE; + } else { + if (! pgm_uint32_gte( g_ntohl (data->data_sqn) , hoststat->rxw_trail ) ) + { + hoststat->odata.invalid++; + hoststat->odata.last_invalid = now; + break; + } + hoststat->rxw_trail = g_ntohl (data->data_trail); + } + + if (hoststat->rxw_constrained && hoststat->txw_trail > hoststat->rxw_trail_init) { + hoststat->rxw_constrained = FALSE; + } + + if ( pgm_uint32_lte ( g_ntohl (data->data_sqn), hoststat->rxw_lead ) ) { + hoststat->general.duplicate++; + break; + } else { + hoststat->rxw_lead = g_ntohl (data->data_sqn); + + hoststat->odata.tsdu += g_ntohs (skb->pgm_header->pgm_tsdu_length); + } + break; + + case PGM_RDATA: + hoststat->rdata.count++; + hoststat->rdata.bytes += skb->len; + hoststat->rdata.last = now; + break; + + case PGM_POLL: + hoststat->poll.count++; + hoststat->poll.bytes += skb->len; + hoststat->poll.last = now; + break; + + case PGM_POLR: + hoststat->polr.count++; + hoststat->polr.bytes += skb->len; + hoststat->polr.last = now; + break; + + case PGM_NAK: + hoststat->nak.count++; + hoststat->nak.bytes += skb->len; + hoststat->nak.last = now; + + is_valid = pgm_verify_nak (skb); + if (!is_valid) { + hoststat->nak.invalid++; + hoststat->nak.last_invalid = now; + } + break; + + case PGM_NNAK: + hoststat->nnak.count++; + hoststat->nnak.bytes += skb->len; + hoststat->nnak.last = now; + break; + + case PGM_NCF: + hoststat->ncf.count++; + hoststat->ncf.bytes += skb->len; + hoststat->ncf.last = now; + break; + + case PGM_SPMR: + hoststat->spmr.count++; + hoststat->spmr.bytes += skb->len; + hoststat->spmr.last = now; + + is_valid = pgm_verify_spmr (skb); + if (!is_valid) { + hoststat->spmr.invalid++; + hoststat->spmr.last_invalid = now; + } + break; + + default: + break; + } + + if (!is_valid) { + hoststat->general.invalid++; + hoststat->general.last_invalid = now; + } else { + hoststat->general.last_valid = now; + } + + pgm_free_skb (skb); + return TRUE; +} + +static gboolean +on_io_error ( + GIOChannel* source, + G_GNUC_UNUSED GIOCondition condition, + G_GNUC_UNUSED gpointer data + ) +{ + puts ("on_error."); + + GError *err; + g_io_channel_shutdown (source, FALSE, &err); + +/* remove event */ + return FALSE; +} + +/* process input commands from stdin/fd + */ + +static gboolean +on_stdin_data ( + G_GNUC_UNUSED GIOChannel* source, + G_GNUC_UNUSED GIOCondition condition, + G_GNUC_UNUSED gpointer data + ) +{ + int ch = wgetch (g_active->window); + if (ch == ERR) { + goto out; + } + +/* force redraw */ + if (ch == 12) { + clearok (curscr, TRUE); + paint_ncurses (); + goto out; + } + + if (ch == 'q') { + g_main_loop_quit(g_loop); + } + +out: + return TRUE; +} + +static gboolean +snap_stat ( + G_GNUC_UNUSED gpointer key, + gpointer value, + G_GNUC_UNUSED gpointer user_data + ) +{ + struct pgm_hoststat* hoststat = value; + +#define SNAP_STAT(name) \ + { \ + hoststat->name.snap_count = hoststat->name.count; \ + hoststat->name.snap_bytes = hoststat->name.bytes; \ + } + + SNAP_STAT(spm); + SNAP_STAT(poll); + SNAP_STAT(polr); + SNAP_STAT(odata); + SNAP_STAT(rdata); + SNAP_STAT(nak); + SNAP_STAT(nnak); + SNAP_STAT(ncf); + SNAP_STAT(spmr); + + SNAP_STAT(general); + + return FALSE; +} + +static gboolean +on_snap ( + gpointer data + ) +{ + if (!g_hosts) return TRUE; + + gettimeofday (&g_last_snap, NULL); + g_hash_table_foreach (g_hosts, (GHFunc)snap_stat, NULL); + + return TRUE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/ping.proto b/3rdparty/openpgm-svn-r1135/pgm/examples/ping.proto new file mode 100644 index 0000000..8c6dfd1 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/ping.proto @@ -0,0 +1,47 @@ +package example; + +message SubscriptionHeader { + required string subject = 1; +} + +message MarketDataHeader { + enum MsgType { + MSG_VERIFY = 0; + MSG_UPDATE = 1; + MSG_CORRECT = 2; + MSG_CLOSING = 3; + MSG_DROP = 4; + MSG_AGGREGATE = 5; + MSG_STATUS = 6; + MSG_CANCEL = 7; + MSG_INITIAL = 8; + } + required MsgType msg_type = 1; + enum RecType { + PING = 1; + } + required RecType rec_type = 2; + enum RecStatus { + STATUS_OK = 0; + STATUS_BAD_NAME = 1; + STATUS_BAD_LINE = 2; + STATUS_CACHE_FULL = 3; + STATUS_PERMISSION_DENIED = 4; + STATUS_PREEMPTED = 5; + STATUS_BAD_ACCESS = 6; + STATUS_TEMP_UNAVAIL = 7; + STATUS_REASSIGN = 8; + STATUS_NOSUBSCRIBERS = 9; + STATUS_EXPIRED = 10; + } + required RecStatus rec_status = 3; +} + +message Ping { + required SubscriptionHeader subscription_header = 1; + required MarketDataHeader market_data_header = 2; + required fixed64 time = 3; + required fixed64 seqno = 4; + required fixed64 latency = 5; + required bytes payload = 6; +} diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/pnonblocksyncrecv.c b/3rdparty/openpgm-svn-r1135/pgm/examples/pnonblocksyncrecv.c new file mode 100644 index 0000000..b5a2e13 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/pnonblocksyncrecv.c @@ -0,0 +1,385 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Simple PGM receiver: poll based non-blocking synchronous receiver. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef G_OS_UNIX +# include +# include +# include +# include +#endif +#include + +/* example dependencies */ +#include +#include + + +/* typedefs */ + +/* globals */ + +static int g_port = 0; +static const char* g_network = ""; +static gboolean g_multicast_loop = FALSE; +static int g_udp_encap_port = 0; + +static int g_max_tpdu = 1500; +static int g_sqns = 100; + +static pgm_sock_t* g_sock = NULL; +static gboolean g_quit; +static int g_quit_pipe[2]; + +static void on_signal (int); +static gboolean on_startup (void); + +static int on_data (gconstpointer, size_t, struct pgm_sockaddr_t*); + + +G_GNUC_NORETURN static +void +usage ( + const char* bin + ) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); + exit (1); +} + +int +main ( + int argc, + char* argv[] + ) +{ + int e; + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + + log_init (); + g_message ("pnonblocksyncrecv"); + + if (!pgm_init (&pgm_err)) { + g_error ("Unable to start PGM engine: %s", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) + { + switch (c) { + case 'n': g_network = optarg; break; + case 's': g_port = atoi (optarg); break; + case 'p': g_udp_encap_port = atoi (optarg); break; + case 'l': g_multicast_loop = TRUE; break; + + case 'h': + case '?': usage (binary_name); + } + } + + g_quit = FALSE; +#ifdef G_OS_UNIX + e = pipe (g_quit_pipe); +#else + e = _pipe (g_quit_pipe, 4096, _O_BINARY | _O_NOINHERIT); +#endif + g_assert (0 == e); + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); + signal (SIGINT, on_signal); + signal (SIGTERM, on_signal); +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif + + if (!on_startup()) { + g_error ("startup failed"); + exit(1); + } + +/* dispatch loop */ + g_message ("entering PGM message loop ... "); + do { + struct timeval tv; + int timeout; + int n_fds = 2; + struct pollfd fds[ 1 + n_fds ]; + char buffer[4096]; + size_t len; + struct pgm_sockaddr_t from; + socklen_t fromlen = sizeof(from); + const int status = pgm_recvfrom (g_sock, + buffer, + sizeof(buffer), + 0, + &len, + &from, + &fromlen, + &pgm_err); + switch (status) { + case PGM_IO_STATUS_NORMAL: + on_data (buffer, len, &from); + break; + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } +/* fall through */ + case PGM_IO_STATUS_WOULD_BLOCK: +/* poll for next event */ +block: + timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + memset (fds, 0, sizeof(fds)); + fds[0].fd = g_quit_pipe[0]; + fds[0].events = POLLIN; + pgm_poll_info (g_sock, &fds[1], &n_fds, POLLIN); + poll (fds, 1 + n_fds, timeout /* ms */); + break; + default: + if (pgm_err) { + g_warning ("%s", pgm_err->message); + pgm_error_free (pgm_err); + pgm_err = NULL; + } + if (PGM_IO_STATUS_ERROR == status) + break; + } + } while (!g_quit); + + g_message ("message loop terminated, cleaning up."); + +/* cleanup */ + close (g_quit_pipe[0]); + close (g_quit_pipe[1]); + + if (g_sock) { + g_message ("closing PGM socket."); + pgm_close (g_sock, TRUE); + g_sock = NULL; + } + + g_message ("PGM engine shutdown."); + pgm_shutdown (); + g_message ("finished."); + return EXIT_SUCCESS; +} + +static +void +on_signal ( + int signum + ) +{ + g_message ("on_signal (signum:%d)", signum); + g_quit = TRUE; + const char one = '1'; + const size_t writelen = write (g_quit_pipe[1], &one, sizeof(one)); + g_assert (sizeof(one) == writelen); +} + +static +gboolean +on_startup (void) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + + g_message ("startup."); + +/* parse network parameter into transport address structure */ + if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { + g_error ("parsing network parameter: %s", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + if (g_udp_encap_port) { + g_message ("create PGM/UDP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + } else { + g_message ("create PGM/IP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int recv_only = 1, + passive = 0, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PASSIVE, &passive, sizeof(passive)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + g_error ("creating GSI: %s", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (g_sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + g_error ("binding PGM socket: %s", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int nonblocking = 1, + multicast_loop = g_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); + + if (!pgm_connect (g_sock, &pgm_err)) { + g_error ("connecting PGM socket: %s", pgm_err->message); + goto err_abort; + } + + g_message ("startup complete."); + return TRUE; + +err_abort: + if (NULL != g_sock) { + pgm_close (g_sock, FALSE); + g_sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +static +int +on_data ( + gconstpointer data, + size_t len, + struct pgm_sockaddr_t* from + ) +{ +/* protect against non-null terminated strings */ + char buf[1024], tsi[PGM_TSISTRLEN]; + const size_t buflen = MIN(sizeof(buf) - 1, len); + strncpy (buf, (const char*)data, buflen); + buf[buflen] = '\0'; + pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); + + g_message ("\"%s\" (%u bytes from %s)", + buf, + (unsigned)len, + tsi); + + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/purinrecv.c b/3rdparty/openpgm-svn-r1135/pgm/examples/purinrecv.c new file mode 100644 index 0000000..0ac38d9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/purinrecv.c @@ -0,0 +1,479 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * プリン PGM receiver + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#ifndef _WIN32 +# include +#else +# include "getopt.h" +#endif +#include + + +/* globals */ + +static int port = 0; +static const char* network = ""; +static bool use_multicast_loop = FALSE; +static int udp_encap_port = 0; + +static int max_tpdu = 1500; +static int sqns = 100; + +static bool use_pgmcc = FALSE; +static bool use_fec = FALSE; +static int rs_k = 8; +static int rs_n = 255; + +static pgm_sock_t* sock = NULL; +static bool is_terminated = FALSE; + +#ifndef _WIN32 +static int terminate_pipe[2]; +static void on_signal (int); +#else +static HANDLE terminate_event; +static BOOL on_console_ctrl (DWORD); +#endif +#ifndef _MSC_VER +static void usage (const char*) __attribute__((__noreturn__)); +#else +static void usage (const char*); +#endif + +static bool on_startup (void); +static int on_data (const void*restrict, const size_t, const struct pgm_sockaddr_t*restrict); + + +static void +usage ( + const char* bin + ) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -c : Enable PGMCC\n"); + fprintf (stderr, " -f : Enable FEC with either proactive or ondemand parity\n"); + fprintf (stderr, " -K : Configure Reed-Solomon code (n, k)\n"); + fprintf (stderr, " -N \n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); + fprintf (stderr, " -i : List available interfaces\n"); + exit (EXIT_SUCCESS); +} + +int +main ( + int argc, + char* argv[] + ) +{ + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + +#if !defined(_WIN32) || defined(CONFIG_TARGET_WINE) + puts ("プリン プリン"); +#else + _putws (L"プリン プリン"); +#endif + + if (!pgm_init (&pgm_err)) { + fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ +#ifdef _WIN32 + const char* binary_name = strrchr (argv[0], '\\') + 1; +#else + const char* binary_name = strrchr (argv[0], '/') + 1; +#endif + int c; + while ((c = getopt (argc, argv, "s:n:p:cf:K:N:lih")) != -1) + { + switch (c) { + case 'n': network = optarg; break; + case 's': port = atoi (optarg); break; + case 'p': udp_encap_port = atoi (optarg); break; + case 'c': use_pgmcc = TRUE; break; + case 'f': use_fec = TRUE; break; + case 'K': rs_k = atoi (optarg); break; + case 'N': rs_n = atoi (optarg); break; + case 'l': use_multicast_loop = TRUE; break; + + case 'i': + pgm_if_print_all(); + return EXIT_SUCCESS; + + case 'h': + case '?': usage (binary_name); + } + } + + if (use_fec && ( !rs_n || !rs_k )) { + fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); + usage (binary_name); + } + +/* setup signal handlers */ +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif +#ifndef _WIN32 + int e = pipe (terminate_pipe); + assert (0 == e); + signal (SIGINT, on_signal); + signal (SIGTERM, on_signal); +#else + terminate_event = CreateEvent (NULL, TRUE, FALSE, TEXT("TerminateEvent")); + SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); +#endif /* !_WIN32 */ + + if (!on_startup()) { + fprintf (stderr, "Startup failed\n"); + return EXIT_FAILURE; + } + +/* dispatch loop */ +#ifndef _WIN32 + int fds; + fd_set readfds; +#else + int n_handles = 3, recv_sock, pending_sock; + HANDLE waitHandles[ 3 ]; + DWORD dwTimeout, dwEvents; + WSAEVENT recvEvent, pendingEvent; + socklen_t socklen = sizeof(int); + + recvEvent = WSACreateEvent (); + pgm_getsockopt (sock, IPPROTO_PGM, PGM_RECV_SOCK, &recv_sock, &socklen); + WSAEventSelect (recv_sock, recvEvent, FD_READ); + pendingEvent = WSACreateEvent (); + pgm_getsockopt (sock, IPPROTO_PGM, PGM_PENDING_SOCK, &pending_sock, &socklen); + WSAEventSelect (pending_sock, pendingEvent, FD_READ); + + waitHandles[0] = terminate_event; + waitHandles[1] = recvEvent; + waitHandles[2] = pendingEvent; +#endif /* !_WIN32 */ + puts ("Entering PGM message loop ... "); + do { + struct timeval tv; + char buffer[4096]; + size_t len; + struct pgm_sockaddr_t from; + socklen_t fromlen = sizeof (from); + const int status = pgm_recvfrom (sock, + buffer, + sizeof(buffer), + 0, + &len, + &from, + &fromlen, + &pgm_err); + switch (status) { + case PGM_IO_STATUS_NORMAL: + on_data (buffer, len, &from); + break; + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } + case PGM_IO_STATUS_WOULD_BLOCK: +/* select for next event */ +block: +#ifndef _WIN32 + fds = terminate_pipe[0] + 1; + FD_ZERO(&readfds); + FD_SET(terminate_pipe[0], &readfds); + pgm_select_info (sock, &readfds, NULL, &fds); + fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); +#else + dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout); + switch (dwEvents) { + case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; + case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break; + default: break; + } +#endif /* !_WIN32 */ + break; + + default: + if (pgm_err) { + fprintf (stderr, "%s\n", pgm_err->message); + pgm_error_free (pgm_err); + pgm_err = NULL; + } + if (PGM_IO_STATUS_ERROR == status) + break; + } + } while (!is_terminated); + + puts ("Message loop terminated, cleaning up."); + +/* cleanup */ +#ifndef _WIN32 + close (terminate_pipe[0]); + close (terminate_pipe[1]); +#else + WSACloseEvent (recvEvent); + WSACloseEvent (pendingEvent); + CloseHandle (terminate_event); +#endif /* !_WIN32 */ + + if (sock) { + puts ("Destroying PGM socket."); + pgm_close (sock, TRUE); + sock = NULL; + } + + puts ("PGM engine shutdown."); + pgm_shutdown (); + puts ("finished."); + return EXIT_SUCCESS; +} + +#ifndef _WIN32 +static +void +on_signal ( + int signum + ) +{ + printf ("on_signal (signum:%d)\n", signum); + is_terminated = TRUE; + const char one = '1'; + const size_t writelen = write (terminate_pipe[1], &one, sizeof(one)); + assert (sizeof(one) == writelen); +} +#else +static +BOOL +on_console_ctrl ( + DWORD dwCtrlType + ) +{ + printf ("on_console_ctrl (dwCtrlType:%lu)\n", (unsigned long)dwCtrlType); + is_terminated = TRUE; + SetEvent (terminate_event); + return TRUE; +} +#endif /* !_WIN32 */ + +static +bool +on_startup (void) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + +/* parse network parameter into PGM socket address structure */ + if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { + fprintf (stderr, "Parsing network parameter: %s\n", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + if (udp_encap_port) { + puts ("Create PGM/UDP socket."); + if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + fprintf (stderr, "Creating PGM/UDP socket: %s\n", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + } else { + puts ("Create PGM/IP socket."); + if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + fprintf (stderr, "Creating PGM/IP socket: %s\n", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int recv_only = 1, + passive = 0, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + pgm_setsockopt (sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_PASSIVE, &passive, sizeof(passive)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MTU, &max_tpdu, sizeof(max_tpdu)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_RXW_SQNS, &sqns, sizeof(sqns)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); + +#ifdef I_UNDERSTAND_PGMCC_AND_FEC_ARE_NOT_SUPPORTED + if (use_pgmcc) { + struct pgm_pgmccinfo_t pgmccinfo; + pgmccinfo.ack_bo_ivl = pgm_msecs (50); + pgmccinfo.ack_c = 75; + pgmccinfo.ack_c_p = 500; + pgm_setsockopt (sock, IPPROTO_PGM, PGM_USE_PGMCC, &pgmccinfo, sizeof(pgmccinfo)); + } + if (use_fec) { + struct pgm_fecinfo_t fecinfo; + fecinfo.block_size = rs_n; + fecinfo.proactive_packets = 0; + fecinfo.group_size = rs_k; + fecinfo.ondemand_parity_enabled = TRUE; + fecinfo.var_pktlen_enabled = FALSE; + pgm_setsockopt (sock, IPPROTO_PGM, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); + } +#endif + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = port ? port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + fprintf (stderr, "Creating GSI: %s\n", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + fprintf (stderr, "Binding PGM socket: %s\n", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int nonblocking = 1, + multicast_loop = use_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); + + if (!pgm_connect (sock, &pgm_err)) { + fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message); + goto err_abort; + } + + puts ("Startup complete."); + return TRUE; + +err_abort: + if (NULL != sock) { + pgm_close (sock, FALSE); + sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + if (NULL != sock) { + pgm_close (sock, FALSE); + sock = NULL; + } + return FALSE; +} + +static +int +on_data ( + const void* restrict data, + const size_t len, + const struct pgm_sockaddr_t* restrict from + ) +{ +/* protect against non-null terminated strings */ + char buf[1024], tsi[PGM_TSISTRLEN]; + const size_t buflen = MIN(sizeof(buf) - 1, len); +#ifndef _MSC_VER + strncpy (buf, (const char*)data, buflen); + buf[buflen] = '\0'; + pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); + printf ("\"%s\" (%zu bytes from %s)\n", + buf, len, tsi); +#else + strncpy_s (buf, buflen, (const char*)data, _TRUNCATE); + pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); +/* Microsoft CRT will crash on %zu */ + printf ("\"%s\" (%u bytes from %s)\n", + buf, (unsigned)len, tsi); +#endif + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/purinrecvcc.cc b/3rdparty/openpgm-svn-r1135/pgm/examples/purinrecvcc.cc new file mode 100644 index 0000000..84631dd --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/purinrecvcc.cc @@ -0,0 +1,434 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * プリン PGM receiver + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +# include +# include +# include +#else +# include "getopt.h" +#endif +#include + + +/* globals */ + +static int port = 0; +static const char* network = ""; +static bool use_multicast_loop = FALSE; +static int udp_encap_port = 0; + +static int max_tpdu = 1500; +static int sqns = 100; + +static bool use_fec = FALSE; +static int rs_k = 8; +static int rs_n = 255; + +static ip::pgm::endpoint* endpoint = NULL; +static ip::pgm::socket* sock = NULL; +static bool is_terminated = FALSE; + +#ifndef _WIN32 +static int terminate_pipe[2]; +static void on_signal (int); +#else +static HANDLE terminate_event; +static BOOL on_console_ctrl (DWORD); +#endif +#ifndef _MSC_VER +static void usage (const char*) __attribute__((__noreturn__)); +#else +static void usage (const char*); +#endif + +static bool on_startup (void); +static int on_data (const void*, size_t, const ip::pgm::endpoint&); + + +static void +usage ( + const char* bin + ) +{ + std::cerr << "Usage: " << bin << " [options]" << std::endl; + std::cerr << " -n : Multicast group or unicast IP address" << std::endl; + std::cerr << " -s : IP port" << std::endl; + std::cerr << " -p : Encapsulate PGM in UDP on IP port" << std::endl; + std::cerr << " -f : Enable FEC with either proactive or ondemand parity" << std::endl; + std::cerr << " -K : Configure Reed-Solomon code (n, k)" << std::endl; + std::cerr << " -N " << std::endl; + std::cerr << " -l : Enable multicast loopback and address sharing" << std::endl; + std::cerr << " -i : List available interfaces" << std::endl; + exit (EXIT_SUCCESS); +} + +int +main ( + int argc, + char* argv[] + ) +{ + cpgm::pgm_error_t* pgm_err = NULL; + + std::setlocale (LC_ALL, ""); + +#if !defined(_WIN32) || defined(CONFIG_TARGET_WINE) + std::cout << "プリン プリン" << std::endl; +#else + std::wcout << L"プリン プリン" << std::endl; +#endif + + if (!cpgm::pgm_init (&pgm_err)) { + std::cerr << "Unable to start PGM engine: " << pgm_err->message << std::endl; + cpgm::pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = std::strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:p:f:K:N:lih")) != -1) + { + switch (c) { + case 'n': network = optarg; break; + case 's': port = atoi (optarg); break; + case 'p': udp_encap_port = atoi (optarg); break; + case 'f': use_fec = TRUE; break; + case 'K': rs_k = atoi (optarg); break; + case 'N': rs_n = atoi (optarg); break; + case 'l': use_multicast_loop = TRUE; break; + + case 'i': + cpgm::pgm_if_print_all(); + return EXIT_SUCCESS; + + case 'h': + case '?': usage (binary_name); + } + } + + if (use_fec && ( !rs_n || !rs_k )) { + std::cerr << "Invalid Reed-Solomon parameters RS(" << rs_n << "," << rs_k << ")." << std::endl; + usage (binary_name); + } + +/* setup signal handlers */ +#ifdef SIGHUP + std::signal (SIGHUP, SIG_IGN); +#endif +#ifndef _WIN32 + int e = pipe (terminate_pipe); + assert (0 == e); + std::signal (SIGINT, on_signal); + std::signal (SIGTERM, on_signal); +#else + terminate_event = CreateEvent (NULL, TRUE, FALSE, TEXT("TerminateEvent")); + SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); +#endif /* !_WIN32 */ + + if (!on_startup()) { + std::cerr << "Startup failed" << std::endl; + return EXIT_FAILURE; + } + +/* dispatch loop */ +#ifndef _WIN32 + int fds; + fd_set readfds; +#else + int n_handles = 3, recv_sock, pending_sock; + HANDLE waitHandles[ 3 ]; + DWORD dwTimeout, dwEvents; + WSAEVENT recvEvent, pendingEvent; + socklen_t socklen = sizeof(int); + + recvEvent = WSACreateEvent (); + sock->get_option (IPPROTO_PGM, cpgm::PGM_RECV_SOCK, &recv_sock, &socklen); + WSAEventSelect (recv_sock, recvEvent, FD_READ); + pendingEvent = WSACreateEvent (); + sock->get_option (IPPROTO_PGM, cpgm::PGM_PENDING_SOCK, &pending_sock, &socklen); + WSAEventSelect (pending_sock, pendingEvent, FD_READ); + + waitHandles[0] = terminate_event; + waitHandles[1] = recvEvent; + waitHandles[2] = pendingEvent; +#endif /* !_WIN32 */ + std::cout << "Entering PGM message loop ... " << std::endl; + do { + socklen_t optlen; + struct timeval tv; + char buffer[4096]; + size_t len; + ip::pgm::endpoint from; + const int status = sock->receive_from (buffer, + sizeof(buffer), + 0, + &len, + &from, + &pgm_err); + switch (status) { + case cpgm::PGM_IO_STATUS_NORMAL: + on_data (buffer, len, from); + break; + case cpgm::PGM_IO_STATUS_TIMER_PENDING: + optlen = sizeof (tv); + sock->get_option (IPPROTO_PGM, cpgm::PGM_TIME_REMAIN, &tv, &optlen); + goto block; + case cpgm::PGM_IO_STATUS_RATE_LIMITED: + optlen = sizeof (tv); + sock->get_option (IPPROTO_PGM, cpgm::PGM_RATE_REMAIN, &tv, &optlen); + case cpgm::PGM_IO_STATUS_WOULD_BLOCK: +/* select for next event */ +block: +#ifndef _WIN32 + fds = terminate_pipe[0] + 1; + FD_ZERO(&readfds); + FD_SET(terminate_pipe[0], &readfds); + pgm_select_info (sock->native(), &readfds, NULL, &fds); + fds = select (fds, &readfds, NULL, NULL, cpgm::PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); +#else + dwTimeout = cpgm::PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : (DWORD)((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout); + switch (dwEvents) { + case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; + case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break; + default: break; + } +#endif /* !_WIN32 */ + break; + + default: + if (pgm_err) { + std::cerr << pgm_err->message << std::endl; + cpgm::pgm_error_free (pgm_err); + pgm_err = NULL; + } + if (cpgm::PGM_IO_STATUS_ERROR == status) + break; + } + } while (!is_terminated); + + std::cout << "Message loop terminated, cleaning up." << std::endl; + +/* cleanup */ +#ifndef _WIN32 + close (terminate_pipe[0]); + close (terminate_pipe[1]); +#else + WSACloseEvent (recvEvent); + WSACloseEvent (pendingEvent); + CloseHandle (terminate_event); +#endif /* !_WIN32 */ + + if (sock) { + std::cout << "Closing PGM socket." << std::endl; + sock->close (TRUE); + sock = NULL; + } + + std::cout << "PGM engine shutdown." << std::endl; + cpgm::pgm_shutdown (); + std::cout << "finished." << std::endl; + return EXIT_SUCCESS; +} + +#ifndef _WIN32 +static +void +on_signal ( + int signum + ) +{ + std::cout << "on_signal (signum:" << signum << ")" << std::endl; + is_terminated = TRUE; + const char one = '1'; + const size_t writelen = write (terminate_pipe[1], &one, sizeof(one)); + assert (sizeof(one) == writelen); +} +#else +static +BOOL +on_console_ctrl ( + DWORD dwCtrlType + ) +{ + std::cout << "on_console_ctrl (dwCtrlType:" << dwCtrlType << ")" << std::endl; + is_terminated = TRUE; + SetEvent (terminate_event); + return TRUE; +} +#endif /* !_WIN32 */ + +static +bool +on_startup (void) +{ + struct cpgm::pgm_addrinfo_t* res = NULL; + cpgm::pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + +/* parse network parameter into PGM socket address structure */ + if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { + std::cerr << "Parsing network parameter: " << pgm_err->message << std::endl; + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + sock = new ip::pgm::socket(); + + if (udp_encap_port) { + std::cout << "Create PGM/UDP socket." << std::endl; + if (!sock->open (sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + std::cerr << "Creating PGM/UDP socket: " << pgm_err->message << std::endl; + goto err_abort; + } + sock->set_option (IPPROTO_PGM, cpgm::PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + } else { + std::cout << "Create PGM/IP socket." << std::endl; + if (!sock->open (sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + std::cerr << "Creating PGM/IP socket: " << pgm_err->message << std::endl; + goto err_abort; + } + } + + { +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + sock->set_option (IPPROTO_PGM, cpgm::PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + } + + cpgm::pgm_drop_superuser(); + + { +/* set PGM parameters */ + const int recv_only = 1, + passive = 0, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + sock->set_option (IPPROTO_PGM, cpgm::PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_PASSIVE, &passive, sizeof(passive)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_MTU, &max_tpdu, sizeof(max_tpdu)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_RXW_SQNS, &sqns, sizeof(sqns)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); + } + if (use_fec) { + struct cpgm::pgm_fecinfo_t fecinfo; + fecinfo.block_size = rs_n; + fecinfo.proactive_packets = 0; + fecinfo.group_size = rs_k; + fecinfo.ondemand_parity_enabled = TRUE; + fecinfo.var_pktlen_enabled = FALSE; + sock->set_option (IPPROTO_PGM, cpgm::PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); + } + +/* create global session identifier */ + endpoint = new ip::pgm::endpoint (DEFAULT_DATA_DESTINATION_PORT); + +/* assign socket to specified address */ + if (!sock->bind (*endpoint, &pgm_err)) { + std::cerr << "Binding PGM socket: " << pgm_err->message << std::endl; + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + sock->set_option (IPPROTO_PGM, cpgm::PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + + { +/* set IP parameters */ + const int nonblocking = 1, + multicast_loop = use_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + sock->set_option (IPPROTO_PGM, cpgm::PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_TOS, &dscp, sizeof(dscp)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); + } + + if (!sock->connect (&pgm_err)) { + std::cerr << "Connecting PGM socket: " << pgm_err->message << std::endl; + goto err_abort; + } + + std::cout << "Startup complete." << std::endl; + return TRUE; + +err_abort: + if (NULL != sock) { + sock->close (FALSE); + sock = NULL; + } + if (NULL != res) { + cpgm::pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + cpgm::pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +static +int +on_data ( + const void* data, + size_t len, + const ip::pgm::endpoint& from + ) +{ +/* protect against non-null terminated strings */ + char buf[1024], tsi[PGM_TSISTRLEN]; + const size_t buflen = MIN(sizeof(buf) - 1, len); + strncpy (buf, (char*)data, buflen); + buf[buflen] = '\0'; + cpgm::pgm_tsi_print_r (from.address(), tsi, sizeof(tsi)); + std::cout << "\"" << buf << "\" (" << len << " bytes from " << tsi << ")" << std::endl; + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/purinsend.c b/3rdparty/openpgm-svn-r1135/pgm/examples/purinsend.c new file mode 100644 index 0000000..871c631 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/purinsend.c @@ -0,0 +1,284 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * プリン PGM sender + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#ifndef _WIN32 +# include +#else +# include "getopt.h" +#endif +#include + + +/* globals */ + +static int port = 0; +static const char* network = ""; +static bool use_multicast_loop = FALSE; +static int udp_encap_port = 0; + +static int max_tpdu = 1500; +static int max_rte = 400*1000; /* very conservative rate, 2.5mb/s */ +static int sqns = 100; + +static bool use_fec = FALSE; +static int rs_k = 8; +static int rs_n = 255; + +static pgm_sock_t* sock = NULL; + +#ifndef _MSC_VER +static void usage (const char*) __attribute__((__noreturn__)); +#else +static void usage (const char*); +#endif +static bool create_sock (void); + + +static void +usage ( + const char* bin + ) +{ + fprintf (stderr, "Usage: %s [options] message\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -r : Regulate to rate bytes per second\n"); + fprintf (stderr, " -f : Enable FEC with either proactive or ondemand parity\n"); + fprintf (stderr, " -K : Configure Reed-Solomon code (n, k)\n"); + fprintf (stderr, " -N \n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); + fprintf (stderr, " -i : List available interfaces\n"); + exit (EXIT_SUCCESS); +} + +int +main ( + int argc, + char *argv[] + ) +{ + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + + if (!pgm_init (&pgm_err)) { + fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ +#ifdef _WIN32 + const char* binary_name = strrchr (argv[0], '\\') + 1; +#else + const char* binary_name = strrchr (argv[0], '/') + 1; +#endif + int c; + while ((c = getopt (argc, argv, "s:n:p:r:f:K:N:lih")) != -1) + { + switch (c) { + case 'n': network = optarg; break; + case 's': port = atoi (optarg); break; + case 'p': udp_encap_port = atoi (optarg); break; + case 'r': max_rte = atoi (optarg); break; + case 'f': use_fec = TRUE; break; + case 'K': rs_k = atoi (optarg); break; + case 'N': rs_n = atoi (optarg); break; + + case 'l': use_multicast_loop = TRUE; break; + + case 'i': + pgm_if_print_all(); + return EXIT_SUCCESS; + + case 'h': + case '?': + usage (binary_name); + } + } + + if (use_fec && ( !rs_n || !rs_k )) { + fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); + usage (binary_name); + } + + if (create_sock()) + { + while (optind < argc) { + const int status = pgm_send (sock, argv[optind], strlen (argv[optind]) + 1, NULL); + if (PGM_IO_STATUS_NORMAL != status) { + fprintf (stderr, "pgm_send() failed.\n"); + } + optind++; + } + } + +/* cleanup */ + if (sock) { + pgm_close (sock, TRUE); + sock = NULL; + } + pgm_shutdown(); + return EXIT_SUCCESS; +} + +static +bool +create_sock (void) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + +/* parse network parameter into PGM socket address structure */ + if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { + fprintf (stderr, "Parsing network parameter: %s\n", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + if (udp_encap_port) { + if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + fprintf (stderr, "Creating PGM/UDP socket: %s\n", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + } else { + if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + fprintf (stderr, "Creating PGM/IP socket: %s\n", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int send_only = 1, + ambient_spm = pgm_secs (30), + heartbeat_spm[] = { pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (1300), + pgm_secs (7), + pgm_secs (16), + pgm_secs (25), + pgm_secs (30) }; + + pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_ONLY, &send_only, sizeof(send_only)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MTU, &max_tpdu, sizeof(max_tpdu)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_SQNS, &sqns, sizeof(sqns)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_MAX_RTE, &max_rte, sizeof(max_rte)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm)); + if (use_fec) { + struct pgm_fecinfo_t fecinfo; + fecinfo.block_size = rs_n; + fecinfo.proactive_packets = 0; + fecinfo.group_size = rs_k; + fecinfo.ondemand_parity_enabled = TRUE; + fecinfo.var_pktlen_enabled = TRUE; + pgm_setsockopt (sock, IPPROTO_PGM, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); + } + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = port ? port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + fprintf (stderr, "Creating GSI: %s\n", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + fprintf (stderr, "Binding PGM socket: %s\n", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + unsigned i; + for (i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int blocking = 0, + multicast_loop = use_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NOBLOCK, &blocking, sizeof(blocking)); + + if (!pgm_connect (sock, &pgm_err)) { + fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message); + goto err_abort; + } + + return TRUE; + +err_abort: + if (NULL != sock) { + pgm_close (sock, FALSE); + sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/purinsendcc.cc b/3rdparty/openpgm-svn-r1135/pgm/examples/purinsendcc.cc new file mode 100644 index 0000000..6ce9648 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/purinsendcc.cc @@ -0,0 +1,269 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * プリン PGM sender + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#ifndef _WIN32 +# include +# include +#else +# include "getopt.h" +#endif +#include + + +/* globals */ + +static int port = 0; +static const char* network = ""; +static bool use_multicast_loop = FALSE; +static int udp_encap_port = 0; + +static int max_tpdu = 1500; +static int max_rte = 400*1000; /* very conservative rate, 2.5mb/s */ +static int sqns = 100; + +static bool use_fec = FALSE; +static int rs_k = 8; +static int rs_n = 255; + +static ip::pgm::endpoint* endpoint = NULL; +static ip::pgm::socket* sock = NULL; + +#ifndef _MSC_VER +static void usage (const char*) __attribute__((__noreturn__)); +#else +static void usage (const char*); +#endif +static bool create_sock (void); + + +static void +usage ( + const char* bin + ) +{ + std::cerr << "Usage: " << bin << " [options] message" << std::endl; + std::cerr << " -n : Multicast group or unicast IP address" << std::endl; + std::cerr << " -s : IP port" << std::endl; + std::cerr << " -p : Encapsulate PGM in UDP on IP port" << std::endl; + std::cerr << " -r : Regulate to rate bytes per second" << std::endl; + std::cerr << " -f : Enable FEC with either proactive or ondemand parity" << std::endl; + std::cerr << " -K : Configure Reed-Solomon code (n, k)" << std::endl; + std::cerr << " -N " << std::endl; + std::cerr << " -l : Enable multicast loopback and address sharing" << std::endl; + std::cerr << " -i : List available interfaces" << std::endl; + exit (EXIT_SUCCESS); +} + +int +main ( + int argc, + char *argv[] + ) +{ + cpgm::pgm_error_t* pgm_err = NULL; + + std::setlocale (LC_ALL, ""); + + if (!cpgm::pgm_init (&pgm_err)) { + std::cerr << "Unable to start PGM engine: " << pgm_err->message << std::endl; + cpgm::pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:p:r:f:K:N:lih")) != -1) + { + switch (c) { + case 'n': network = optarg; break; + case 's': port = atoi (optarg); break; + case 'p': udp_encap_port = atoi (optarg); break; + case 'r': max_rte = atoi (optarg); break; + case 'f': use_fec = TRUE; break; + case 'K': rs_k = atoi (optarg); break; + case 'N': rs_n = atoi (optarg); break; + + case 'l': use_multicast_loop = TRUE; break; + + case 'i': + cpgm::pgm_if_print_all(); + return EXIT_SUCCESS; + + case 'h': + case '?': + usage (binary_name); + } + } + + if (use_fec && ( !rs_n || !rs_k )) { + std::cerr << "Invalid Reed-Solomon parameters RS(" << rs_n << "," << rs_k << ")." << std::endl; + usage (binary_name); + } + + if (create_sock()) + { + while (optind < argc) { + const int status = sock->send (argv[optind], strlen (argv[optind]) + 1, NULL); + if (cpgm::PGM_IO_STATUS_NORMAL != status) { + std::cerr << "pgm_send() failed.." << std::endl; + } + optind++; + } + } + +/* cleanup */ + if (sock) { + sock->close (TRUE); + sock = NULL; + } + cpgm::pgm_shutdown(); + return EXIT_SUCCESS; +} + +static +bool +create_sock (void) +{ + struct cpgm::pgm_addrinfo_t* res = NULL; + cpgm::pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + +/* parse network parameter into PGM socket address structure */ + if (!cpgm::pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { + std::cerr << "Parsing network parameter: " << pgm_err->message << std::endl; + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + sock = new ip::pgm::socket(); + + if (udp_encap_port) { + if (!sock->open (sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + std::cerr << "Creating PGM/UDP socket: " << pgm_err->message << std::endl; + goto err_abort; + } + sock->set_option (IPPROTO_PGM, cpgm::PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + } else { + if (!sock->open (sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + std::cerr << "Creating PGM/IP socket: " << pgm_err->message << std::endl; + goto err_abort; + } + } + + { +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + sock->set_option (IPPROTO_PGM, cpgm::PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + } + + cpgm::pgm_drop_superuser(); + + { +/* set PGM parameters */ + const int send_only = 1, + ambient_spm = pgm_secs (30), + heartbeat_spm[] = { pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (1300), + pgm_secs (7), + pgm_secs (16), + pgm_secs (25), + pgm_secs (30) }; + + sock->set_option (IPPROTO_PGM, cpgm::PGM_SEND_ONLY, &send_only, sizeof(send_only)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_MTU, &max_tpdu, sizeof(max_tpdu)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_TXW_SQNS, &sqns, sizeof(sqns)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_TXW_MAX_RTE, &max_rte, sizeof(max_rte)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm)); + } + if (use_fec) { + struct cpgm::pgm_fecinfo_t fecinfo; + fecinfo.block_size = rs_n; + fecinfo.proactive_packets = 0; + fecinfo.group_size = rs_k; + fecinfo.ondemand_parity_enabled = TRUE; + fecinfo.var_pktlen_enabled = TRUE; + sock->set_option (IPPROTO_PGM, cpgm::PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); + } + +/* create global session identifier */ + endpoint = new ip::pgm::endpoint (DEFAULT_DATA_DESTINATION_PORT); + +/* assign socket to specified address */ + if (!sock->bind (*endpoint, &pgm_err)) { + std::cerr << "Binding PGM socket: " << pgm_err->message << std::endl; + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + sock->set_option (IPPROTO_PGM, cpgm::PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + cpgm::pgm_freeaddrinfo (res); + + { +/* set IP parameters */ + const int blocking = 0, + multicast_loop = use_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + sock->set_option (IPPROTO_PGM, cpgm::PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_TOS, &dscp, sizeof(dscp)); + sock->set_option (IPPROTO_PGM, cpgm::PGM_NOBLOCK, &blocking, sizeof(blocking)); + } + + if (!sock->connect (&pgm_err)) { + fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message); + goto err_abort; + } + + return TRUE; + +err_abort: + if (NULL != sock) { + sock->close (FALSE); + sock = NULL; + } + if (NULL != res) { + cpgm::pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + cpgm::pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/shortcakerecv.c b/3rdparty/openpgm-svn-r1135/pgm/examples/shortcakerecv.c new file mode 100644 index 0000000..bcaec4a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/shortcakerecv.c @@ -0,0 +1,430 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * ショートケーキ PGM receiver + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#ifndef _WIN32 +# include +#else +# include "getopt.h" +# define snprintf _snprintf +#endif +#include + +#include "async.h" + + +/* globals */ + +static int port = 0; +static const char* network = ""; +static bool use_multicast_loop = FALSE; +static int udp_encap_port = 0; + +static int max_tpdu = 1500; +static int sqns = 100; + +static bool use_fec = FALSE; +static int rs_k = 8; +static int rs_n = 255; + +static pgm_sock_t* sock = NULL; +static async_t* async = NULL; +static bool is_terminated = FALSE; + +#ifndef _WIN32 +static int terminate_pipe[2]; +static void on_signal (int); +#else +static HANDLE terminate_event; +static BOOL on_console_ctrl (DWORD); +#endif +#ifndef _MSC_VER +static void usage (const char*) __attribute__((__noreturn__)); +#else +static void usage (const char*); +#endif + +static bool on_startup (void); +static int on_data (const void*restrict, const size_t, const struct pgm_sockaddr_t*restrict); + + +static void +usage ( + const char* bin + ) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -f : Enable FEC with either proactive or ondemand parity\n"); + fprintf (stderr, " -K : Configure Reed-Solomon code (n, k)\n"); + fprintf (stderr, " -N \n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); + fprintf (stderr, " -i : List available interfaces\n"); + exit (EXIT_SUCCESS); +} + +int +main ( + int argc, + char* argv[] + ) +{ + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + +#if !defined(_WIN32) || defined(CONFIG_TARGET_WINE) + puts ("いちごのショートケーキ"); +#else + _putws (L"いちごのショートケーキ"); +#endif + + if (!pgm_init (&pgm_err)) { + fprintf (stderr, "Unable to start PGM engine: %s\n", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:p:f:K:N:lih")) != -1) + { + switch (c) { + case 'n': network = optarg; break; + case 's': port = atoi (optarg); break; + case 'p': udp_encap_port = atoi (optarg); break; + case 'f': use_fec = TRUE; break; + case 'K': rs_k = atoi (optarg); break; + case 'N': rs_n = atoi (optarg); break; + case 'l': use_multicast_loop = TRUE; break; + + case 'i': + pgm_if_print_all(); + return EXIT_SUCCESS; + + case 'h': + case '?': usage (binary_name); + } + } + + if (use_fec && ( !rs_n || !rs_k )) { + fprintf (stderr, "Invalid Reed-Solomon parameters RS(%d,%d).\n", rs_n, rs_k); + usage (binary_name); + } + +/* setup signal handlers */ +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif +#ifndef _WIN32 + int e = pipe (terminate_pipe); + assert (0 == e); + signal (SIGINT, on_signal); + signal (SIGTERM, on_signal); +#else + terminate_event = CreateEvent (NULL, TRUE, FALSE, TEXT("TerminateEvent")); + SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); +#endif /* !_WIN32 */ + + if (!on_startup()) { + fprintf (stderr, "Startup failed\n"); + return EXIT_FAILURE; + } + +/* dispatch loop */ +#ifndef _WIN32 + int fds, read_fd = async_get_fd (async); + fd_set readfds; +#else + int n_handles = 2; + HANDLE waitHandles[ 2 ]; + DWORD dwEvents; + WSAEVENT recvEvent; + + recvEvent = async_get_event (async); + + waitHandles[0] = terminate_event; + waitHandles[1] = recvEvent; +#endif /* !_WIN32 */ + puts ("Entering PGM message loop ... "); + do { + char buffer[4096]; + struct pgm_sockaddr_t from; + socklen_t fromlen = sizeof (from); + const ssize_t len = async_recvfrom (async, + buffer, + sizeof(buffer), + &from, + &fromlen); + if (len >= 0) { + on_data (buffer, len, &from); + } else { +#ifndef _WIN32 + fds = MAX(terminate_pipe[0], read_fd) + 1; + FD_ZERO(&readfds); + FD_SET(terminate_pipe[0], &readfds); + FD_SET(read_fd, &readfds); + fds = select (fds, &readfds, NULL, NULL, NULL); +#else + dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, INFINITE); + switch (dwEvents) { + case WAIT_OBJECT_0+1: ResetEvent (recvEvent); break; + default: break; + } +#endif /* _WIN32 */ + } + } while (!is_terminated); + + puts ("Message loop terminated, cleaning up."); + +/* cleanup */ +#ifndef _WIN32 + close (terminate_pipe[0]); + close (terminate_pipe[1]); +#else + CloseHandle (terminate_event); +#endif /* !_WIN32 */ + + if (async) { + puts ("Destroying asynchronous queue."); + async_destroy (async); + async = NULL; + } + + if (sock) { + puts ("Closing PGM socket."); + pgm_close (sock, TRUE); + sock = NULL; + } + + puts ("PGM engine shutdown."); + pgm_shutdown (); + puts ("finished."); + return EXIT_SUCCESS; +} + +#ifndef _WIN32 +static +void +on_signal ( + int signum + ) +{ + printf ("on_signal (signum:%d)\n", signum); + is_terminated = TRUE; + const char one = '1'; + const size_t writelen = write (terminate_pipe[1], &one, sizeof(one)); + assert (sizeof(one) == writelen); +} +#else +static +BOOL +on_console_ctrl ( + DWORD dwCtrlType + ) +{ + printf ("on_console_ctrl (dwCtrlType:%lu)\n", (unsigned long)dwCtrlType); + is_terminated = TRUE; + SetEvent (terminate_event); + return TRUE; +} +#endif /* !_WIN32 */ + +static +bool +on_startup (void) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + +/* parse network parameter into PGM socket address structure */ + if (!pgm_getaddrinfo (network, NULL, &res, &pgm_err)) { + fprintf (stderr, "Parsing network parameter: %s\n", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + puts ("Create PGM socket."); + if (udp_encap_port) { + if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + fprintf (stderr, "Creating PGM/UDP socket: %s\n", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &udp_encap_port, sizeof(udp_encap_port)); + } else { + if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + fprintf (stderr, "Creating PGM/IP socket: %s\n", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int recv_only = 1, + passive = 0, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + pgm_setsockopt (sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_PASSIVE, &passive, sizeof(passive)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MTU, &max_tpdu, sizeof(max_tpdu)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_RXW_SQNS, &sqns, sizeof(sqns)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); + if (use_fec) { + struct pgm_fecinfo_t fecinfo; + fecinfo.block_size = rs_n; + fecinfo.proactive_packets = 0; + fecinfo.group_size = rs_k; + fecinfo.ondemand_parity_enabled = TRUE; + fecinfo.var_pktlen_enabled = TRUE; + pgm_setsockopt (sock, IPPROTO_PGM, PGM_USE_FEC, &fecinfo, sizeof(fecinfo)); + } + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = port ? port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + fprintf (stderr, "Creating GSI: %s\n", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + fprintf (stderr, "Binding PGM socket: %s\n", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int nonblocking = 1, + multicast_loop = use_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); + + if (!pgm_connect (sock, &pgm_err)) { + fprintf (stderr, "Connecting PGM socket: %s\n", pgm_err->message); + goto err_abort; + } + +/* wrap bound socket in asynchronous queue */ + if (0 != async_create (&async, sock)) { + fprintf (stderr, "Creating asynchronous queue failed: %s\n", strerror(errno)); + goto err_abort; + } + + puts ("Startup complete."); + return TRUE; + +err_abort: + if (NULL != sock) { + pgm_close (sock, FALSE); + sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +static +int +on_data ( + const void* restrict data, + const size_t len, + const struct pgm_sockaddr_t* restrict from + ) +{ +/* protect against non-null terminated strings */ + char buf[1024], tsi[PGM_TSISTRLEN]; + const size_t buflen = MIN(sizeof(buf) - 1, len); + strncpy (buf, (const char*)data, buflen); + buf[buflen] = '\0'; + pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); +#ifndef _MSC_VER + printf ("\"%s\" (%zu bytes from %s)\n", + buf, len, tsi); +#else +/* Microsoft CRT will crash on %zu */ + printf ("\"%s\" (%u bytes from %s)\n", + buf, (unsigned)len, tsi); +#endif + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/examples/snonblocksyncrecv.c b/3rdparty/openpgm-svn-r1135/pgm/examples/snonblocksyncrecv.c new file mode 100644 index 0000000..4d72b71 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/examples/snonblocksyncrecv.c @@ -0,0 +1,435 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Simple PGM receiver: select based non-blocking synchronous receiver. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef G_OS_UNIX +# include +# include +# include +# include +#endif +#include + +/* example dependencies */ +#include +#include + + +/* typedefs */ + +/* globals */ + +static int g_port = 0; +static const char* g_network = ""; +static gboolean g_multicast_loop = FALSE; +static int g_udp_encap_port = 0; + +static int g_max_tpdu = 1500; +static int g_sqns = 100; + +static pgm_sock_t* g_sock = NULL; +static gboolean g_quit; + +#ifdef G_OS_UNIX +static int g_quit_pipe[2]; +static void on_signal (int); +#else +static HANDLE g_quit_event; +static BOOL on_console_ctrl (DWORD); +#endif + +static gboolean on_startup (void); + +static int on_data (gconstpointer, size_t, struct pgm_sockaddr_t*); + + +G_GNUC_NORETURN static +void +usage ( + const char* bin + ) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + fprintf (stderr, " -p : Encapsulate PGM in UDP on IP port\n"); + fprintf (stderr, " -l : Enable multicast loopback and address sharing\n"); + exit (1); +} + +int +main ( + int argc, + char* argv[] + ) +{ + int e; + pgm_error_t* pgm_err = NULL; + + setlocale (LC_ALL, ""); + + log_init (); + g_message ("snonblocksyncrecv"); + + if (!pgm_init (&pgm_err)) { + g_error ("Unable to start PGM engine: %s", pgm_err->message); + pgm_error_free (pgm_err); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:p:lh")) != -1) + { + switch (c) { + case 'n': g_network = optarg; break; + case 's': g_port = atoi (optarg); break; + case 'p': g_udp_encap_port = atoi (optarg); break; + case 'l': g_multicast_loop = TRUE; break; + + case 'h': + case '?': usage (binary_name); + } + } + + g_quit = FALSE; + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); +#ifdef SIGHUP + signal (SIGHUP, SIG_IGN); +#endif +#ifdef G_OS_UNIX + e = pipe (g_quit_pipe); + g_assert (0 == e); + signal (SIGINT, on_signal); + signal (SIGTERM, on_signal); +#else + g_quit_event = CreateEvent (NULL, TRUE, FALSE, TEXT("QuitEvent")); + SetConsoleCtrlHandler ((PHANDLER_ROUTINE)on_console_ctrl, TRUE); +#endif /* !G_OS_UNIX */ + + if (!on_startup()) { + g_error ("startup failed"); + exit(1); + } + +/* dispatch loop */ +#ifdef G_OS_UNIX + int fds; + fd_set readfds; +#else + int n_handles = 3; + HANDLE waitHandles[ n_handles ]; + DWORD dwTimeout, dwEvents; + WSAEVENT recvEvent, pendingEvent; + + recvEvent = WSACreateEvent (); + WSAEventSelect (pgm_transport_get_recv_fd (g_transport), recvEvent, FD_READ); + pendingEvent = WSACreateEvent (); + WSAEventSelect (pgm_transport_get_pending_fd (g_transport), pendingEvent, FD_READ); + + waitHandles[0] = g_quit_event; + waitHandles[1] = recvEvent; + waitHandles[2] = pendingEvent; +#endif /* !G_OS_UNIX */ + g_message ("entering PGM message loop ... "); + do { + struct timeval tv; + char buffer[4096]; + size_t len; + struct pgm_sockaddr_t from; + socklen_t fromlen = sizeof(from); + const int status = pgm_recvfrom (g_sock, + buffer, + sizeof(buffer), + 0, + &len, + &from, + &fromlen, + &pgm_err); + switch (status) { + case PGM_IO_STATUS_NORMAL: + on_data (buffer, len, &from); + break; + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (g_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } +/* fall through */ + case PGM_IO_STATUS_WOULD_BLOCK: +/* select for next event */ +block: +#ifdef G_OS_UNIX + fds = g_quit_pipe[0] + 1; + FD_ZERO(&readfds); + FD_SET(g_quit_pipe[0], &readfds); + pgm_select_info (g_sock, &readfds, NULL, &fds); + fds = select (fds, &readfds, NULL, NULL, PGM_IO_STATUS_WOULD_BLOCK == status ? NULL : &tv); +#else + dwTimeout = PGM_IO_STATUS_WOULD_BLOCK == status ? INFINITE : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + dwEvents = WaitForMultipleObjects (n_handles, waitHandles, FALSE, dwTimeout); + switch (dwEvents) { + case WAIT_OBJECT_0+1: WSAResetEvent (recvEvent); break; + case WAIT_OBJECT_0+2: WSAResetEvent (pendingEvent); break; + default: break; + } +#endif /* !G_OS_UNIX */ + break; + + default: + if (pgm_err) { + g_warning ("%s", pgm_err->message); + pgm_error_free (pgm_err); + pgm_err = NULL; + } + if (PGM_IO_STATUS_ERROR == status) + break; + } + } while (!g_quit); + + g_message ("message loop terminated, cleaning up."); + +/* cleanup */ +#ifdef G_OS_UNIX + close (g_quit_pipe[0]); + close (g_quit_pipe[1]); +#else + WSACloseEvent (recvEvent); + WSACloseEvent (pendingEvent); + CloseHandle (g_quit_event); +#endif /* !G_OS_UNIX */ + + if (g_sock) { + g_message ("closing PGM socket."); + pgm_close (g_sock, TRUE); + g_sock = NULL; + } + + g_message ("PGM engine shutdown."); + pgm_shutdown (); + g_message ("finished."); + return EXIT_SUCCESS; +} + +#ifdef G_OS_UNIX +static +void +on_signal ( + int signum + ) +{ + g_message ("on_signal (signum:%d)", signum); + g_quit = TRUE; + const char one = '1'; + const size_t writelen = write (g_quit_pipe[1], &one, sizeof(one)); + g_assert (sizeof(one) == writelen); +} +#else +static +BOOL +on_console_ctrl ( + DWORD dwCtrlType + ) +{ + g_message ("on_console_ctrl (dwCtrlType:%lu)", (unsigned long)dwCtrlType); + SetEvent (g_quit_event); + return TRUE; +} +#endif /* !G_OS_UNIX */ + +static +gboolean +on_startup (void) +{ + struct pgm_addrinfo_t* res = NULL; + pgm_error_t* pgm_err = NULL; + sa_family_t sa_family = AF_UNSPEC; + + g_message ("startup."); + +/* parse network parameter into transport address structure */ + if (!pgm_getaddrinfo (g_network, NULL, &res, &pgm_err)) { + g_error ("parsing network parameter: %s", pgm_err->message); + goto err_abort; + } + + sa_family = res->ai_send_addrs[0].gsr_group.ss_family; + + if (g_udp_encap_port) { + g_message ("create PGM/UDP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT, &g_udp_encap_port, sizeof(g_udp_encap_port)); + } else { + g_message ("create PGM/IP socket."); + if (!pgm_socket (&g_sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + g_error ("socket: %s", pgm_err->message); + goto err_abort; + } + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist)); + + pgm_drop_superuser(); + +/* set PGM parameters */ + const int recv_only = 1, + passive = 0, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only, sizeof(recv_only)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PASSIVE, &passive, sizeof(passive)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MTU, &g_max_tpdu, sizeof(g_max_tpdu)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_RXW_SQNS, &g_sqns, sizeof(g_sqns)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries)); + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = g_port ? g_port : DEFAULT_DATA_DESTINATION_PORT; + addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + g_error ("creating GSI: %s", pgm_err->message); + goto err_abort; + } + +/* assign socket to specified address */ + struct pgm_interface_req_t if_req; + memset (&if_req, 0, sizeof(if_req)); + if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface; + if_req.ir_scope_id = 0; + if (AF_INET6 == sa_family) { + struct sockaddr_in6 sa6; + memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof(sa6)); + if_req.ir_scope_id = sa6.sin6_scope_id; + } + if (!pgm_bind3 (g_sock, + &addr, sizeof(addr), + &if_req, sizeof(if_req), /* tx interface */ + &if_req, sizeof(if_req), /* rx interface */ + &pgm_err)) + { + g_error ("binding PGM socket: %s", pgm_err->message); + goto err_abort; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req)); + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int nonblocking = 1, + multicast_loop = g_multicast_loop ? 1 : 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &multicast_loop, sizeof(multicast_loop)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops)); + if (AF_INET6 != sa_family) + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp)); + pgm_setsockopt (g_sock, IPPROTO_PGM, PGM_NOBLOCK, &nonblocking, sizeof(nonblocking)); + + if (!pgm_connect (g_sock, &pgm_err)) { + g_error ("connecting PGM socket: %s", pgm_err->message); + goto err_abort; + } + + g_message ("startup complete."); + return TRUE; + +err_abort: + if (NULL != g_sock) { + pgm_close (g_sock, FALSE); + g_sock = NULL; + } + if (NULL != res) { + pgm_freeaddrinfo (res); + res = NULL; + } + if (NULL != pgm_err) { + pgm_error_free (pgm_err); + pgm_err = NULL; + } + return FALSE; +} + +static +int +on_data ( + gconstpointer data, + size_t len, + struct pgm_sockaddr_t* from + ) +{ +/* protect against non-null terminated strings */ + char buf[1024], tsi[PGM_TSISTRLEN]; + const size_t buflen = MIN(sizeof(buf) - 1, len); + strncpy (buf, (const char*)data, buflen); + buf[buflen] = '\0'; + pgm_tsi_print_r (&from->sa_addr, tsi, sizeof(tsi)); + + g_message ("\"%s\" (%u bytes from %s)", + buf, + (unsigned)len, + tsi); + + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/fec-block.txt b/3rdparty/openpgm-svn-r1135/pgm/fec-block.txt new file mode 100644 index 0000000..8278fb6 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/fec-block.txt @@ -0,0 +1,66 @@ +from rfc5052 +------------ + + +step one: + + Input: + + B -- Maximum Source Block Length, i.e., the maximum number of source + symbols per source block + + L -- Transfer Length in octets + + E -- Encoding Symbol Length in octets + + Output: + + T -- the number of source symbols in the object. + + N -- the number of source blocks into which the object shall be + partitioned. + + Algorithm: + + 1. The number of source symbols in the transport object is computed + as T = ceil[L/E]. + + 2. The transport object shall be partitioned into N = ceil[T/B] + source blocks. + + +B = maximum TPDU - IP header ( - UDP header ) - PGM header +L = APDU length (pgm_transport_send length parameter). +E = 1 (fixed). + +T = ceil( L / E ) = ceil( L / 1 ) = L +N = ceil( T / B ) = ceil( L / B ) + +step two: + + Input: + + T -- the number of source symbols in the object. + + N -- the number of source blocks into which the object is + partitioned. + + Output: + + I -- the number of larger source blocks. + + A_large -- the length of each of the larger source blocks in + symbols. + + A_small -- the length of each of the smaller source blocks in + symbols. + + Algorithm: + + 1. A_large = ceil[T/N] + + 2. A_small = floor[T/N] + + 3. I = T - A_small * N + + diff --git a/3rdparty/openpgm-svn-r1135/pgm/fec.txt b/3rdparty/openpgm-svn-r1135/pgm/fec.txt new file mode 100644 index 0000000..b83590d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/fec.txt @@ -0,0 +1,77 @@ +pkt:k=1 + +non-parity + +rs eqn: + +n = 255 +k = 2t +255 = 2k +k = 128 +=> 2t = 128 + +-------------------------------------------------------------------------------- + +1456, 1442 + +pkt:k=2 ( 2 data packets ) + +1 packet loss: + +pkt:h=1 +pkt:n=3 + +rs eqn: + +n = 255 +# reed-solomon codes = tsdu / n +k = 2 4 6 ... 254 +=> 2t = 1 2 3 127 (k/2) + +255 = k + (k/2) +510 = 2k + k +510 = 3k +170 = k +=> 2t = 85 + +2 packet loss: + +pkt:h=2 pkts +pkt:n=4 pkts + +-------------------------------------------------------------------------------- + +pkt:k=4 ( 4 data packets ) + +1 packet loss: + +255 = k + (k/4) +k = 51 +2t = 13 (rounded up) + +-------------------------------------------------------------------------------- + +pkt:k=8 ( 8 data packets ) + +1 packet loss: + +255 = k + (k/8) +k = 29 +2t = 4 (rounded up) + +-------------------------------------------------------------------------------- + +pkt:k=16 ( 16 data packets ) + +1 packet loss: + +255 = k + (k/16) +k = 15 +2t = 1 (invalid?) + +2 packet loss: + +255 = k + (2k/16) +k = 29 +2t = 4 + diff --git a/3rdparty/openpgm-svn-r1135/pgm/galois_generator.pl b/3rdparty/openpgm-svn-r1135/pgm/galois_generator.pl new file mode 100755 index 0000000..b3f531d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/galois_generator.pl @@ -0,0 +1,139 @@ +#!/usr/bin/perl +# +# Galois field table generator. +# +# Copyright (c) 2006-2010 Miru Limited. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +use strict; + +my $GF_ELEMENT_BYTES = 1; +my $GF_ELEMENT_BITS = 8 * $GF_ELEMENT_BYTES; +my $GF_NO_ELEMENTS = 1 << $GF_ELEMENT_BITS; +my $GF_MAX = $GF_NO_ELEMENTS - 1; + +my $GF_GENERATOR = 0x11d; + +my @gflog; +my @gfantilog; + +my $j = 1; + +for (my $i = 0; $i < $GF_MAX; $i++) +{ + $gflog[ $j ] = $i; + $gfantilog[ $i ] = $j; + + $j <<= 1; + if ($j & $GF_NO_ELEMENTS) { + $j ^= $GF_GENERATOR; + } +} + +$gflog[ 0 ] = $GF_MAX; +$gfantilog[ $GF_MAX ] = 0; + +print< + + +/* globals */ + +const pgm_gf8_t pgm_gflog[PGM_GF_NO_ELEMENTS] = +{ +MOO + +# print out y = log₂(x) table +for (my $i = 0; $i < $GF_NO_ELEMENTS; $i++) +{ + print "\t" if ($i % 8 == 0); + print sprintf("0x%2.2x", $gflog[ $i ]); + print ',' unless ($i == $GF_MAX); + print ( (($i % 8) == 7) ? "\n" : ' ' ); +} + +print<= $GF_MAX) ? $gfantilog[ $sum - $GF_MAX ] : $gfantilog[ $sum ]; +} + +# print out multiplication table z = x • y +for (my $i = 0; $i < $GF_NO_ELEMENTS; $i++) +{ + for (my $j = 0; $j < $GF_NO_ELEMENTS; $j++) + { + print "\t" if ($j % 8 == 0); + print sprintf("0x%2.2x", gfmul( $i, $j )); + print ',' unless ($i == $GF_MAX && $j == $GF_MAX); + print ( (($j % 8) == 7) ? "\n" : ' ' ); + } +} + +print<) { + chomp; + if (/^(Function|File) '(.+)'/) { + $type = $1; + $target = $2; + } elsif (/^Lines executed:(\d+\.\d+)% of (\d+)/) { +# print "$type,$target,$1,$2\n"; + if ($type cmp 'File') { + $files{$target} = $1; + } else { + $functions{$target} = $1; + } + } +} + +#@sorted = sort { $files{$a} <=> $files{$b} } keys %files; +#foreach $name (@sorted) +#{ +# print "$name:$files{$name}\n"; +#} +@sorted = sort { $functions{$a} <=> $functions{$b} } keys %functions; +$total = 0; +$count = 0; +foreach $name (@sorted) +{ + next if $name =~ m#^/#; + next if $name =~ m#.+\.h$#; + next if $name =~ m#_unittest\.c$#; + print sprintf("%20s: %3.1f%%\n", $name, $functions{$name}); + $total += $functions{$name}; + $count++; +} +$total /= $count; +print "\n TOTAL: ~" . int($total) . "%\n\n"; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/gcov-seed.sh b/3rdparty/openpgm-svn-r1135/pgm/gcov-seed.sh new file mode 100755 index 0000000..853fbe6 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/gcov-seed.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +./ref/debug/async_unittest +./ref/debug/checksum_unittest +./ref/debug/getifaddrs_unittest +./ref/debug/getnodeaddr_unittest +./ref/debug/gsi_unittest +./ref/debug/http_unittest +./ref/debug/if_unittest +./ref/debug/indextoaddr_unittest +./ref/debug/inet_network_unittest +./ref/debug/md5_unittest +./ref/debug/net_unittest +./ref/debug/packet_unittest +./ref/debug/pgmMIB_unittest +./ref/debug/pgm_unittest +./ref/debug/rate_control_unittest +./ref/debug/receiver_unittest +./ref/debug/recv_unittest +./ref/debug/reed_solomon_unittest +./ref/debug/rxwi_unittest +./ref/debug/signal_unittest +./ref/debug/snmp_unittest +./ref/debug/source_unittest +./ref/debug/timer_unittest +./ref/debug/time_unittest +user=`id -nu` +group=`id -ng` +sudo execcap 'cap_net_raw=ep' /sbin/sucap $user $group ./ref/debug/transport_unittest +sudo find ref/debug/ -user 0 -exec chown $user:$group {} \; +./ref/debug/tsi_unittest +./ref/debug/txwi_unittest + diff --git a/3rdparty/openpgm-svn-r1135/pgm/gcov.sh b/3rdparty/openpgm-svn-r1135/pgm/gcov.sh new file mode 100755 index 0000000..ca17d62 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/gcov.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +gcov -fno ref/debug async_unittest.c +gcov -fno ref/debug checksum_unittest.c +gcov -fno ref/debug getifaddrs_unittest.c +gcov -fno ref/debug getnodeaddr_unittest.c +gcov -fno ref/debug gsi_unittest.c +gcov -fno ref/debug http_unittest.c +gcov -fno ref/debug if_unittest.c +gcov -fno ref/debug indextoaddr_unittest.c +gcov -fno ref/debug inet_network_unittest.c +gcov -fno ref/debug md5_unittest.c +gcov -fno ref/debug net_unittest.c +gcov -fno ref/debug packet_unittest.c +gcov -fno ref/debug pgmMIB_unittest.c +gcov -fno ref/debug pgm_unittest.c +gcov -fno ref/debug rate_control_unittest.c +gcov -fno ref/debug receiver_unittest.c +gcov -fno ref/debug recv_unittest.c +gcov -fno ref/debug reed_solomon_unittest.c +gcov -fno ref/debug rxwi_unittest.c +gcov -fno ref/debug signal_unittest.c +gcov -fno ref/debug snmp_unittest.c +gcov -fno ref/debug source_unittest.c +gcov -fno ref/debug timer_unittest.c +gcov -fno ref/debug time_unittest.c +gcov -fno ref/debug tsi_unittest.c +gcov -fno ref/debug txwi_unittest.c + diff --git a/3rdparty/openpgm-svn-r1135/pgm/getifaddrs.c b/3rdparty/openpgm-svn-r1135/pgm/getifaddrs.c new file mode 100644 index 0000000..9db1d86 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/getifaddrs.c @@ -0,0 +1,840 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable getifaddrs implementation. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#ifdef CONFIG_HAVE_GETIFADDRS +# include +# include +#endif +#if defined( sun ) +# include +#endif +#if defined( _WIN32 ) +# include +# include +#endif +#include +#include + + +//#define GETIFADDRS_DEBUG + +/* locals */ +struct _pgm_ifaddrs_t +{ + struct pgm_ifaddrs_t _ifa; + char _name[IF_NAMESIZE]; + struct sockaddr_storage _addr; + struct sockaddr_storage _netmask; +}; + +/* Number of attempts to try enumerating the interface list */ +#define MAX_TRIES 3 +#define DEFAULT_BUFFER_SIZE 4096 + +/* returns TRUE on success setting ifap to a linked list of system interfaces, + * returns FALSE on failure and sets error appropriately. + */ + +#ifdef SIOCGLIFCONF +static +bool +_pgm_getlifaddrs ( + struct pgm_ifaddrs_t** restrict ifap, + pgm_error_t** restrict error + ) +{ + const int sock = socket (AF_INET, SOCK_DGRAM, 0); + if (-1 == sock) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("Opening IPv4 datagram socket: %s"), + strerror (errno)); + return FALSE; + } + +/* process IPv6 interfaces */ + const int sock6 = socket (AF_INET6, SOCK_DGRAM, 0); + if (-1 == sock6) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("Opening IPv6 datagram socket: %s"), + strerror (errno)); + close (sock); + return FALSE; + } + + struct lifnum lifn; +again: + lifn.lifn_family = AF_INET; + lifn.lifn_flags = 0; + if (-1 == ioctl (sock, SIOCGLIFNUM, &lifn)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("SIOCGLIFNUM failed on IPv4 socket: %s"), + strerror (errno)); + close (sock); + close (sock6); + return FALSE; + } + unsigned if_count = lifn.lifn_count; + pgm_debug ("ioctl(AF_INET, SIOCGLIFNUM) = %d", lifn.lifn_count); + +/* nb: Sun and Apple code likes to pad the interface count here in case interfaces + * are coming up between calls, + */ + lifn.lifn_count += 4; + +/* process all interfaces with family-agnostic ioctl, unfortunately it still + * must be called on each family socket despite what if_tcp(7P) says. + */ + struct lifconf lifc, lifc6; + lifc.lifc_family = AF_INET; + lifc.lifc_flags = 0; + lifc.lifc_len = lifn.lifn_count * sizeof(struct lifreq); + lifc.lifc_buf = alloca (lifc.lifc_len); + if (-1 == ioctl (sock, SIOCGLIFCONF, &lifc)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("SIOCGLIFCONF failed on IPv4 socket: %s"), + strerror (errno)); + close (sock); + close (sock6); + return FALSE; + } + pgm_debug ("ioctl(AF_INET, SIOCGLIFCONF) = %d (%d)", lifc.lifc_len, (int)(lifc.lifc_len / sizeof(struct lifreq))); + +/* repeat everything for IPv6 */ + lifn.lifn_family = AF_INET6; + lifn.lifn_flags = 0; + if (-1 == ioctl (sock6, SIOCGLIFNUM, &lifn)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("SIOCGLIFNUM failed on IPv6 socket: %s"), + strerror (errno)); + close (sock); + close (sock6); + return FALSE; + } + if_count += lifn.lifn_count; + pgm_debug ("ioctl(AF_INET6, SIOCGLIFNUM) = %d", lifn.lifn_count); + + lifn.lifn_count += 4; + + lifc6.lifc_family = AF_INET6; + lifc6.lifc_flags = 0; + lifc6.lifc_len = lifn.lifn_count * sizeof(struct lifreq); + lifc6.lifc_buf = alloca (lifc6.lifc_len); + if (-1 == ioctl (sock6, SIOCGLIFCONF, &lifc6)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("SIOCGLIFCONF failed on IPv6 socket: %s"), + strerror (errno)); + close (sock); + close (sock6); + return FALSE; + } + pgm_debug ("ioctl(AF_INET6, SIOCGLIFCONF) = %d (%d)", lifc6.lifc_len, (int)(lifc6.lifc_len / sizeof(struct lifreq))); + + unsigned nlifr = (lifc.lifc_len + lifc6.lifc_len) / sizeof(struct lifreq); + if (nlifr > if_count) + goto again; + +/* alloc a contiguous block for entire list */ + struct _pgm_ifaddrs_t* ifa = calloc (nlifr, sizeof (struct _pgm_ifaddrs_t)); + pgm_assert (NULL != ifa); + + struct _pgm_ifaddrs_t* ift = ifa; + struct lifreq* lifr = lifc.lifc_req; + struct lifreq* lifr_end = (struct lifreq *)&lifc.lifc_buf[lifc.lifc_len]; + + pgm_assert (IF_NAMESIZE >= LIFNAMSIZ); + + while (lifr < lifr_end) + { +/* name */ + pgm_debug ("AF_INET/name: %s", lifr->lifr_name ? lifr->lifr_name : "(null)"); + ift->_ifa.ifa_name = ift->_name; + strncpy (ift->_ifa.ifa_name, lifr->lifr_name, LIFNAMSIZ); + ift->_ifa.ifa_name[LIFNAMSIZ - 1] = 0; + +/* flags */ + if (-1 != ioctl (sock, SIOCGLIFFLAGS, lifr)) { + ift->_ifa.ifa_flags = lifr->lifr_flags; + } else { + pgm_warn (_("SIOCGLIFFLAGS failed on interface %s%s%s"), + lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); + } + +/* address */ + if (-1 != ioctl (sock, SIOCGLIFADDR, lifr)) { + ift->_ifa.ifa_addr = (void*)&ift->_addr; + memcpy (ift->_ifa.ifa_addr, &lifr->lifr_addr, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_addr)); + } else { + pgm_warn (_("SIOCGLIFADDR failed on interface %s%s%s"), + lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); + } + +/* netmask */ + if (-1 != ioctl (sock, SIOCGLIFNETMASK, lifr)) { + ift->_ifa.ifa_netmask = (void*)&ift->_netmask; +# ifdef CONFIG_HAVE_IFR_NETMASK + memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_netmask, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_netmask)); +# else + memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_addr, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_addr)); +# endif + } else { + pgm_warn (_("SIOCGLIFNETMASK failed on interface %s%s%s"), + lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); + } + + ++lifr; + if (lifr < lifr_end) { + ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); + ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); + } + } + +/* repeat everything for IPv6 */ + lifr = lifc6.lifc_req; + lifr_end = (struct lifreq *)&lifc6.lifc_buf[lifc6.lifc_len]; + + while (lifr < lifr_end) + { + if (ift != ifa) { + ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); + ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); + } + +/* name */ + pgm_debug ("AF_INET6/name: %s", lifr->lifr_name ? lifr->lifr_name : "(null)"); + ift->_ifa.ifa_name = ift->_name; + strncpy (ift->_ifa.ifa_name, lifr->lifr_name, sizeof(lifr->lifr_name)); + ift->_ifa.ifa_name[sizeof(lifr->lifr_name) - 1] = 0; + +/* flags */ + if (-1 != ioctl (sock6, SIOCGLIFFLAGS, lifr)) { + ift->_ifa.ifa_flags = lifr->lifr_flags; + } else { + pgm_warn (_("SIOCGLIFFLAGS failed on interface %s%s%s"), + lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); + } + +/* address */ + if (-1 != ioctl (sock6, SIOCGLIFADDR, lifr)) { + ift->_ifa.ifa_addr = (void*)&ift->_addr; + memcpy (ift->_ifa.ifa_addr, &lifr->lifr_addr, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_addr)); + } else { + pgm_warn (_("SIOCGLIFADDR failed on interface %s%s%s"), + lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); + } + +/* netmask */ + if (ioctl (sock6, SIOCGLIFNETMASK, lifr) != -1) { + ift->_ifa.ifa_netmask = (void*)&ift->_netmask; +# ifdef CONFIG_HAVE_IFR_NETMASK + memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_netmask, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_netmask)); +# else + memcpy (ift->_ifa.ifa_netmask, &lifr->lifr_addr, pgm_sockaddr_len((struct sockaddr*)&lifr->lifr_addr)); +# endif + } else { + pgm_warn (_("SIOCGLIFNETMASK failed on interface %s%s%s"), + lifr->lifr_name ? "\"" : "", lifr->lifr_name ? lifr->lifr_name : "(null)", lifr->lifr_name ? "\"" : ""); + } + + ++lifr; + } + + if (-1 == close (sock6)) + pgm_warn (_("Closing IPv6 socket failed: %s"), strerror(errno)); + if (-1 == close (sock)) + pgm_warn (_("Closing IPv4 socket failed: %s"), strerror(errno)); + + *ifap = (struct pgm_ifaddrs_t*)ifa; + return TRUE; +} +#endif /* SIOCGLIFCONF */ + +#ifdef SIOCGIFCONF +static +bool +_pgm_getifaddrs ( + struct pgm_ifaddrs_t** restrict ifap, + pgm_error_t** restrict error + ) +{ + const int sock = socket (AF_INET, SOCK_DGRAM, 0); + if (-1 == sock) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("Opening IPv4 datagram socket: %s"), + strerror (errno)); + return FALSE; + } + +/* process IPv4 interfaces */ + char buf[ DEFAULT_BUFFER_SIZE ]; + struct ifconf ifc; + ifc.ifc_buf = buf; + ifc.ifc_len = sizeof(buf); + if (-1 == ioctl (sock, SIOCGIFCONF, &ifc)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("SIOCGIFCONF failed on IPv4 socket: %s"), + strerror (errno)); + close (sock); + return FALSE; + } + int if_count = ifc.ifc_len / sizeof(struct ifreq); + +# ifdef CONFIG_HAVE_IPV6_SIOCGIFADDR +/* process IPv6 interfaces */ + const int sock6 = socket (AF_INET6, SOCK_DGRAM, 0); + if (-1 == sock6) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("Opening IPv6 datagram socket: %s"), + strerror (errno)); + close (sock); + return FALSE; + } + + char buf6[1024]; + struct ifconf ifc6; + ifc6.ifc_buf = buf6; + ifc6.ifc_len = sizeof(buf6); + if (-1 == ioctl (sock6, SIOCGIFCONF, &ifc6)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("SIOCGIFCONF failed on IPv6 socket: %s"), + strerror (errno)); + close (sock); + close (sock6); + return FALSE; + } + if_count += ifc6.ifc_len / sizeof(struct ifreq); +# endif /* CONFIG_HAVE_IPV6_SIOCGIFADDR */ + +/* alloc a contiguous block for entire list */ + struct _pgm_ifaddrs_t* ifa = pgm_new0 (struct _pgm_ifaddrs_t, if_count); + struct _pgm_ifaddrs_t* ift = ifa; + struct ifreq *ifr = ifc.ifc_req; + struct ifreq *ifr_end = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; + + pgm_assert (IF_NAMESIZE >= sizeof(ifr->ifr_name)); + + while (ifr < ifr_end) + { +/* name */ + pgm_debug ("AF_INET/name:%s", ifr->ifr_name ? ifr->ifr_name : "(null)"); + ift->_ifa.ifa_name = ift->_name; + strncpy (ift->_ifa.ifa_name, ifr->ifr_name, sizeof(ifr->ifr_name)); + ift->_ifa.ifa_name[sizeof(ifr->ifr_name) - 1] = 0; + +/* flags */ + if (-1 != ioctl (sock, SIOCGIFFLAGS, ifr)) { + ift->_ifa.ifa_flags = ifr->ifr_flags; + } else { + pgm_warn (_("SIOCGIFFLAGS failed on interface %s%s%s"), + ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); + } + +/* address */ + if (-1 != ioctl (sock, SIOCGIFADDR, ifr)) { + ift->_ifa.ifa_addr = (void*)&ift->_addr; + memcpy (ift->_ifa.ifa_addr, &ifr->ifr_addr, pgm_sockaddr_len(&ifr->ifr_addr)); + } else { + pgm_warn (_("SIOCGIFADDR failed on interface %s%s%s"), + ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); + } + +/* netmask */ + if (-1 != ioctl (sock, SIOCGIFNETMASK, ifr)) { + ift->_ifa.ifa_netmask = (void*)&ift->_netmask; +# ifdef CONFIG_HAVE_IFR_NETMASK + memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_netmask, pgm_sockaddr_len(&ifr->ifr_netmask)); +# else + memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_addr, pgm_sockaddr_len(&ifr->ifr_addr)); +# endif + } else { + pgm_warn (_("SIOCGIFNETMASK failed on interface %s%s%s"), + ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); + } + + ++ifr; + if (ifr < ifr_end) { + ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); + ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); + } + } + +# ifdef CONFIG_HAVE_IPV6_SIOCGIFADDR +/* repeat everything for IPv6 */ + ifr = ifc6.ifc_req; + ifr_end = (struct ifreq *)&ifc6.ifc_buf[ifc6.ifc_len]; + + while (ifr < ifr_end) + { + if (ift != ifa) { + ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); + ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); + } + +/* name */ + pgm_debug ("AF_INET6/name:%s", ifr->ifr_name ? ifr->ifr_name : "(null)"); + ift->_ifa.ifa_name = ift->_name; + strncpy (ift->_ifa.ifa_name, ifr->ifr_name, sizeof(ifr->ifr_name)); + ift->_ifa.ifa_name[sizeof(ifr->ifr_name) - 1] = 0; + +/* flags */ + if (-1 != ioctl (sock6, SIOCGIFFLAGS, ifr)) { + ift->_ifa.ifa_flags = ifr->ifr_flags; + } else { + pgm_warn (_("SIOCGIFFLAGS failed on interface %s%s%s"), + ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); + } + +/* address, note this does not work on Linux as struct ifreq is too small for an IPv6 address */ + if (-1 != ioctl (sock6, SIOCGIFADDR, ifr)) { + ift->_ifa.ifa_addr = (void*)&ift->_addr; + memcpy (ift->_ifa.ifa_addr, &ifr->ifr_addr, pgm_sockaddr_len(&ifr->ifr_addr)); + } else { + pgm_warn (_("SIOCGIFADDR failed on interface %s%s%s"), + ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); + } + +/* netmask */ + if (-1 != ioctl (sock6, SIOCGIFNETMASK, ifr)) { + ift->_ifa.ifa_netmask = (void*)&ift->_netmask; +# ifdef CONFIG_HAVE_IFR_NETMASK + memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_netmask, pgm_sockaddr_len(&ifr->ifr_netmask)); +# else + memcpy (ift->_ifa.ifa_netmask, &ifr->ifr_addr, pgm_sockaddr_len(&ifr->ifr_addr)); +# endif + } else { + pgm_warn (_("SIOCGIFNETMASK failed on interface %s%s%s"), + ifr->ifr_name ? "\"" : "", ifr->ifr_name ? ifr->ifr_name : "(null)", ifr->ifr_name ? "\"" : ""); + } + + ++ifr; + } + + if (-1 == close (sock6)) + pgm_warn (_("Closing IPv6 socket failed: %s"), strerror(errno)); +# endif /* CONFIG_HAVE_IPV6_SIOCGIFADDR */ + + if (-1 == close (sock)) + pgm_warn (_("Closing IPv4 socket failed: %s"), strerror(errno)); + + *ifap = (struct pgm_ifaddrs_t*)ifa; + return TRUE; +} +#endif /* SIOCLIFCONF */ + +#if defined(_WIN32) +static inline +void* +_pgm_heap_alloc ( + const size_t n_bytes + ) +{ +# ifdef CONFIG_USE_HEAPALLOC +/* Does not appear very safe with re-entrant calls on XP */ + return HeapAlloc (GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, n_bytes); +# else + return pgm_malloc (n_bytes); +# endif +} + +static inline +void +_pgm_heap_free ( + void* mem + ) +{ +# ifdef CONFIG_USE_HEAPALLOC + HeapFree (GetProcessHeap(), 0, mem); +# else + pgm_free (mem); +# endif +} + +/* NB: IP_ADAPTER_INFO size varies size due to sizeof (time_t), the API assumes + * 4-byte datatype whilst compiler uses an 8-byte datatype. Size can be forced + * with -D_USE_32BIT_TIME_T with side effects to everything else. + */ + +static +bool +_pgm_getadaptersinfo ( + struct pgm_ifaddrs_t** restrict ifap, + pgm_error_t** restrict error + ) +{ + DWORD dwRet; + ULONG ulOutBufLen = DEFAULT_BUFFER_SIZE; + PIP_ADAPTER_INFO pAdapterInfo = NULL; + PIP_ADAPTER_INFO pAdapter = NULL; + +/* loop to handle interfaces coming online causing a buffer overflow + * between first call to list buffer length and second call to enumerate. + */ + for (unsigned i = MAX_TRIES; i; i--) + { + pgm_debug ("IP_ADAPTER_INFO buffer length %lu bytes.", ulOutBufLen); + pAdapterInfo = (IP_ADAPTER_INFO*)_pgm_heap_alloc (ulOutBufLen); + dwRet = GetAdaptersInfo (pAdapterInfo, &ulOutBufLen); + if (ERROR_BUFFER_OVERFLOW == dwRet) { + _pgm_heap_free (pAdapterInfo); + pAdapterInfo = NULL; + } else { + break; + } + } + + switch (dwRet) { + case ERROR_SUCCESS: /* NO_ERROR */ + break; + case ERROR_BUFFER_OVERFLOW: + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NOBUFS, + _("GetAdaptersInfo repeatedly failed with ERROR_BUFFER_OVERFLOW.")); + if (pAdapterInfo) + _pgm_heap_free (pAdapterInfo); + return FALSE; + default: + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_win_errno (dwRet), + _("GetAdaptersInfo failed: %s"), + pgm_adapter_strerror (dwRet)); + if (pAdapterInfo) + _pgm_heap_free (pAdapterInfo); + return FALSE; + } + +/* count valid adapters */ + int n = 0, k = 0; + for (pAdapter = pAdapterInfo; + pAdapter; + pAdapter = pAdapter->Next) + { + for (IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList; + pIPAddr; + pIPAddr = pIPAddr->Next) + { +/* skip null adapters */ + if (strlen (pIPAddr->IpAddress.String) == 0) + continue; + ++n; + } + } + + pgm_debug ("GetAdaptersInfo() discovered %d interfaces.", n); + +/* contiguous block for adapter list */ + struct _pgm_ifaddrs_t* ifa = pgm_new0 (struct _pgm_ifaddrs_t, n); + struct _pgm_ifaddrs_t* ift = ifa; + +/* now populate list */ + for (pAdapter = pAdapterInfo; + pAdapter; + pAdapter = pAdapter->Next) + { + for (IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList; + pIPAddr; + pIPAddr = pIPAddr->Next) + { +/* skip null adapters */ + if (strlen (pIPAddr->IpAddress.String) == 0) + continue; + +/* address */ + ift->_ifa.ifa_addr = (void*)&ift->_addr; + pgm_assert (pgm_sockaddr_pton (pIPAddr->IpAddress.String, ift->_ifa.ifa_addr)); + +/* name */ + pgm_debug ("name:%s IPv4 index:%lu", + pAdapter->AdapterName, pAdapter->Index); + ift->_ifa.ifa_name = ift->_name; + strncpy (ift->_ifa.ifa_name, pAdapter->AdapterName, IF_NAMESIZE); + ift->_ifa.ifa_name[IF_NAMESIZE - 1] = 0; + +/* flags: assume up, broadcast and multicast */ + ift->_ifa.ifa_flags = IFF_UP | IFF_BROADCAST | IFF_MULTICAST; + if (pAdapter->Type == MIB_IF_TYPE_LOOPBACK) + ift->_ifa.ifa_flags |= IFF_LOOPBACK; + +/* netmask */ + ift->_ifa.ifa_netmask = (void*)&ift->_netmask; + pgm_assert (pgm_sockaddr_pton (pIPAddr->IpMask.String, ift->_ifa.ifa_netmask)); + +/* next */ + if (k++ < (n - 1)) { + ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); + ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); + } + } + } + + if (pAdapterInfo) + free (pAdapterInfo); + *ifap = (struct pgm_ifaddrs_t*)ifa; + return TRUE; +} + +static +bool +_pgm_getadaptersaddresses ( + struct pgm_ifaddrs_t** restrict ifap, + pgm_error_t** restrict error + ) +{ + DWORD dwSize = DEFAULT_BUFFER_SIZE, dwRet; + IP_ADAPTER_ADDRESSES *pAdapterAddresses = NULL, *adapter; + +/* loop to handle interfaces coming online causing a buffer overflow + * between first call to list buffer length and second call to enumerate. + */ + for (unsigned i = MAX_TRIES; i; i--) + { + pgm_debug ("IP_ADAPTER_ADDRESSES buffer length %lu bytes.", dwSize); + pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_pgm_heap_alloc (dwSize); + dwRet = GetAdaptersAddresses (AF_UNSPEC, + GAA_FLAG_INCLUDE_PREFIX | + GAA_FLAG_SKIP_ANYCAST | + GAA_FLAG_SKIP_DNS_SERVER | + GAA_FLAG_SKIP_FRIENDLY_NAME | + GAA_FLAG_SKIP_MULTICAST, + NULL, + pAdapterAddresses, + &dwSize); + if (ERROR_BUFFER_OVERFLOW == dwRet) { + _pgm_heap_free (pAdapterAddresses); + pAdapterAddresses = NULL; + } else { + break; + } + } + + switch (dwRet) { + case ERROR_SUCCESS: + break; + case ERROR_BUFFER_OVERFLOW: + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NOBUFS, + _("GetAdaptersAddresses repeatedly failed with ERROR_BUFFER_OVERFLOW.")); + if (pAdapterAddresses) + free (pAdapterAddresses); + return FALSE; + default: + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_win_errno (dwRet), + _("GetAdaptersAddresses failed: %s"), + pgm_adapter_strerror (dwRet)); + if (pAdapterAddresses) + free (pAdapterAddresses); + return FALSE; + } + +/* count valid adapters */ + int n = 0, k = 0; + for (adapter = pAdapterAddresses; + adapter; + adapter = adapter->Next) + { + for (IP_ADAPTER_UNICAST_ADDRESS *unicast = adapter->FirstUnicastAddress; + unicast; + unicast = unicast->Next) + { +/* ensure IP adapter */ + if (AF_INET != unicast->Address.lpSockaddr->sa_family && + AF_INET6 != unicast->Address.lpSockaddr->sa_family) + { + continue; + } + + ++n; + } + } + +/* contiguous block for adapter list */ + struct _pgm_ifaddrs_t* ifa = pgm_new0 (struct _pgm_ifaddrs_t, n); + struct _pgm_ifaddrs_t* ift = ifa; + +/* now populate list */ + for (adapter = pAdapterAddresses; + adapter; + adapter = adapter->Next) + { + int unicastIndex = 0; + for (IP_ADAPTER_UNICAST_ADDRESS *unicast = adapter->FirstUnicastAddress; + unicast; + unicast = unicast->Next, ++unicastIndex) + { +/* ensure IP adapter */ + if (AF_INET != unicast->Address.lpSockaddr->sa_family && + AF_INET6 != unicast->Address.lpSockaddr->sa_family) + { + continue; + } + +/* address */ + ift->_ifa.ifa_addr = (void*)&ift->_addr; + memcpy (ift->_ifa.ifa_addr, unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength); + +/* name */ + pgm_debug ("name:%s IPv4 index:%lu IPv6 index:%lu", + adapter->AdapterName, adapter->IfIndex, adapter->Ipv6IfIndex); + ift->_ifa.ifa_name = ift->_name; + strncpy (ift->_ifa.ifa_name, adapter->AdapterName, IF_NAMESIZE); + ift->_ifa.ifa_name[IF_NAMESIZE - 1] = 0; + +/* flags */ + ift->_ifa.ifa_flags = 0; + if (IfOperStatusUp == adapter->OperStatus) + ift->_ifa.ifa_flags |= IFF_UP; + if (IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType) + ift->_ifa.ifa_flags |= IFF_LOOPBACK; + if (!(adapter->Flags & IP_ADAPTER_NO_MULTICAST)) + ift->_ifa.ifa_flags |= IFF_MULTICAST; + +/* netmask */ + ift->_ifa.ifa_netmask = (void*)&ift->_netmask; + +/* pre-Vista must hunt for matching prefix in linked list, otherwise use OnLinkPrefixLength */ + int prefixIndex = 0; + ULONG prefixLength = 0; + for (IP_ADAPTER_PREFIX *prefix = adapter->FirstPrefix; + prefix; + prefix = prefix->Next, ++prefixIndex) + { + if (prefixIndex == unicastIndex) { + prefixLength = prefix->PrefixLength; + break; + } + } + +/* map prefix to netmask */ + ift->_ifa.ifa_netmask->sa_family = unicast->Address.lpSockaddr->sa_family; + switch (unicast->Address.lpSockaddr->sa_family) { + case AF_INET: + if (0 == prefixLength) { + pgm_warn (_("IPv4 adapter %s prefix length is 0, overriding to 32."), adapter->AdapterName); + prefixLength = 32; + } + ((struct sockaddr_in*)ift->_ifa.ifa_netmask)->sin_addr.s_addr = htonl( 0xffffffffU << ( 32 - prefixLength ) ); + break; + + case AF_INET6: + if (0 == prefixLength) { + pgm_warn (_("IPv6 adapter %s prefix length is 0, overriding to 128."), adapter->AdapterName); + prefixLength = 128; + } + for (ULONG i = prefixLength, j = 0; i > 0; i -= 8, ++j) + { + ((struct sockaddr_in6*)ift->_ifa.ifa_netmask)->sin6_addr.s6_addr[ j ] = i >= 8 ? 0xff : (ULONG)(( 0xffU << ( 8 - i ) ) & 0xffU ); + } + break; + } + +/* next */ + if (k++ < (n - 1)) { + ift->_ifa.ifa_next = (struct pgm_ifaddrs_t*)(ift + 1); + ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); + } + } + } + + if (pAdapterAddresses) + free (pAdapterAddresses); + *ifap = (struct pgm_ifaddrs_t*)ifa; + return TRUE; +} +#endif /* _WIN32 */ + +/* returns TRUE on success setting ifap to a linked list of system interfaces, + * returns FALSE on failure and sets error appropriately. + */ + +bool +pgm_getifaddrs ( + struct pgm_ifaddrs_t** restrict ifap, + pgm_error_t** restrict error + ) +{ + pgm_assert (NULL != ifap); + + pgm_debug ("pgm_getifaddrs (ifap:%p error:%p)", + (void*)ifap, (void*)error); + +#ifdef CONFIG_HAVE_GETIFADDRS + const int e = getifaddrs ((struct ifaddrs**)ifap); + if (-1 == e) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("getifaddrs failed: %s"), + strerror (errno)); + return FALSE; + } + return TRUE; +#elif defined(CONFIG_TARGET_WINE) + return _pgm_getadaptersinfo (ifap, error); +#elif defined(_WIN32) + return _pgm_getadaptersaddresses (ifap, error); +#elif defined(SIOCGLIFCONF) + return _pgm_getlifaddrs (ifap, error); +#elif defined(SIOCGIFCONF) + return _pgm_getifaddrs (ifap, error); +#else +# error "Unsupported interface enumeration on this platform." +#endif /* !CONFIG_HAVE_GETIFADDRS */ +} + +void +pgm_freeifaddrs ( + struct pgm_ifaddrs_t* ifa + ) +{ + pgm_return_if_fail (NULL != ifa); + +#ifdef CONFIG_HAVE_GETIFADDRS + freeifaddrs ((struct ifaddrs*)ifa); +#else + pgm_free (ifa); +#endif +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/getifaddrs.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/getifaddrs.c.c89.patch new file mode 100644 index 0000000..d7e7c08 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/getifaddrs.c.c89.patch @@ -0,0 +1,218 @@ +--- getifaddrs.c 2010-07-03 20:31:27.000000000 +0800 ++++ getifaddrs.c89 2010-08-04 10:49:52.000000000 +0800 +@@ -507,7 +507,9 @@ + /* loop to handle interfaces coming online causing a buffer overflow + * between first call to list buffer length and second call to enumerate. + */ +- for (unsigned i = MAX_TRIES; i; i--) ++ { ++ unsigned i; ++ for (i = MAX_TRIES; i; i--) + { + pgm_debug ("IP_ADAPTER_INFO buffer length %lu bytes.", ulOutBufLen); + pAdapterInfo = (IP_ADAPTER_INFO*)_pgm_heap_alloc (ulOutBufLen); +@@ -519,6 +521,7 @@ + break; + } + } ++ } + + switch (dwRet) { + case ERROR_SUCCESS: /* NO_ERROR */ +@@ -543,12 +546,15 @@ + } + + /* count valid adapters */ ++ { + int n = 0, k = 0; + for (pAdapter = pAdapterInfo; + pAdapter; + pAdapter = pAdapter->Next) + { +- for (IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList; ++ { ++ IP_ADDR_STRING *pIPAddr; ++ for (pIPAddr = &pAdapter->IpAddressList; + pIPAddr; + pIPAddr = pIPAddr->Next) + { +@@ -557,11 +563,13 @@ + continue; + ++n; + } ++ } + } + + pgm_debug ("GetAdaptersInfo() discovered %d interfaces.", n); + + /* contiguous block for adapter list */ ++ { + struct _pgm_ifaddrs_t* ifa = pgm_new0 (struct _pgm_ifaddrs_t, n); + struct _pgm_ifaddrs_t* ift = ifa; + +@@ -570,7 +578,9 @@ + pAdapter; + pAdapter = pAdapter->Next) + { +- for (IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList; ++ { ++ IP_ADDR_STRING *pIPAddr; ++ for (pIPAddr = &pAdapter->IpAddressList; + pIPAddr; + pIPAddr = pIPAddr->Next) + { +@@ -586,8 +596,12 @@ + pgm_debug ("name:%s IPv4 index:%lu", + pAdapter->AdapterName, pAdapter->Index); + ift->_ifa.ifa_name = ift->_name; ++#ifdef _MSC_VER ++ strncpy_s (ift->_ifa.ifa_name, IF_NAMESIZE, pAdapter->AdapterName, _TRUNCATE); ++#else + strncpy (ift->_ifa.ifa_name, pAdapter->AdapterName, IF_NAMESIZE); + ift->_ifa.ifa_name[IF_NAMESIZE - 1] = 0; ++#endif + + /* flags: assume up, broadcast and multicast */ + ift->_ifa.ifa_flags = IFF_UP | IFF_BROADCAST | IFF_MULTICAST; +@@ -604,11 +618,14 @@ + ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); + } + } ++ } + } + + if (pAdapterInfo) + free (pAdapterInfo); + *ifap = (struct pgm_ifaddrs_t*)ifa; ++ } ++ } + return TRUE; + } + +@@ -625,7 +642,9 @@ + /* loop to handle interfaces coming online causing a buffer overflow + * between first call to list buffer length and second call to enumerate. + */ +- for (unsigned i = MAX_TRIES; i; i--) ++ { ++ unsigned i; ++ for (i = MAX_TRIES; i; i--) + { + pgm_debug ("IP_ADAPTER_ADDRESSES buffer length %lu bytes.", dwSize); + pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_pgm_heap_alloc (dwSize); +@@ -645,6 +664,7 @@ + break; + } + } ++ } + + switch (dwRet) { + case ERROR_SUCCESS: +@@ -669,12 +689,15 @@ + } + + /* count valid adapters */ ++ { + int n = 0, k = 0; + for (adapter = pAdapterAddresses; + adapter; + adapter = adapter->Next) + { +- for (IP_ADAPTER_UNICAST_ADDRESS *unicast = adapter->FirstUnicastAddress; ++ { ++ IP_ADAPTER_UNICAST_ADDRESS *unicast; ++ for (unicast = adapter->FirstUnicastAddress; + unicast; + unicast = unicast->Next) + { +@@ -687,9 +710,11 @@ + + ++n; + } ++ } + } + + /* contiguous block for adapter list */ ++ { + struct _pgm_ifaddrs_t* ifa = pgm_new0 (struct _pgm_ifaddrs_t, n); + struct _pgm_ifaddrs_t* ift = ifa; + +@@ -699,7 +724,9 @@ + adapter = adapter->Next) + { + int unicastIndex = 0; +- for (IP_ADAPTER_UNICAST_ADDRESS *unicast = adapter->FirstUnicastAddress; ++ { ++ IP_ADAPTER_UNICAST_ADDRESS *unicast; ++ for (unicast = adapter->FirstUnicastAddress; + unicast; + unicast = unicast->Next, ++unicastIndex) + { +@@ -718,8 +745,12 @@ + pgm_debug ("name:%s IPv4 index:%lu IPv6 index:%lu", + adapter->AdapterName, adapter->IfIndex, adapter->Ipv6IfIndex); + ift->_ifa.ifa_name = ift->_name; ++#ifdef _MSC_VER ++ strncpy_s (ift->_ifa.ifa_name, IF_NAMESIZE, adapter->AdapterName, _TRUNCATE); ++#else + strncpy (ift->_ifa.ifa_name, adapter->AdapterName, IF_NAMESIZE); + ift->_ifa.ifa_name[IF_NAMESIZE - 1] = 0; ++#endif + + /* flags */ + ift->_ifa.ifa_flags = 0; +@@ -734,9 +765,12 @@ + ift->_ifa.ifa_netmask = (void*)&ift->_netmask; + + /* pre-Vista must hunt for matching prefix in linked list, otherwise use OnLinkPrefixLength */ ++ { + int prefixIndex = 0; + ULONG prefixLength = 0; +- for (IP_ADAPTER_PREFIX *prefix = adapter->FirstPrefix; ++ { ++ IP_ADAPTER_PREFIX *prefix; ++ for (prefix = adapter->FirstPrefix; + prefix; + prefix = prefix->Next, ++prefixIndex) + { +@@ -745,6 +779,7 @@ + break; + } + } ++ } + + /* map prefix to netmask */ + ift->_ifa.ifa_netmask->sa_family = unicast->Address.lpSockaddr->sa_family; +@@ -762,12 +797,16 @@ + pgm_warn (_("IPv6 adapter %s prefix length is 0, overriding to 128."), adapter->AdapterName); + prefixLength = 128; + } +- for (ULONG i = prefixLength, j = 0; i > 0; i -= 8, ++j) ++ { ++ ULONG i, j; ++ for (i = prefixLength, j = 0; i > 0; i -= 8, ++j) + { + ((struct sockaddr_in6*)ift->_ifa.ifa_netmask)->sin6_addr.s6_addr[ j ] = i >= 8 ? 0xff : (ULONG)(( 0xffU << ( 8 - i ) ) & 0xffU ); + } ++ } + break; + } ++ } + + /* next */ + if (k++ < (n - 1)) { +@@ -775,11 +814,14 @@ + ift = (struct _pgm_ifaddrs_t*)(ift->_ifa.ifa_next); + } + } ++ } + } + + if (pAdapterAddresses) + free (pAdapterAddresses); + *ifap = (struct pgm_ifaddrs_t*)ifa; ++ } ++ } + return TRUE; + } + #endif /* _WIN32 */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/getifaddrs_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/getifaddrs_unittest.c new file mode 100644 index 0000000..1ab7378 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/getifaddrs_unittest.c @@ -0,0 +1,262 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for portable getifaddrs implementation. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* IFF_UP */ +#define _BSD_SOURCE 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* mock state */ + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + + +#define GETIFADDRS_DEBUG +#include "getifaddrs.c" + + +char* +ifflags_string ( + unsigned int flags + ) +{ + static char s[1024]; + + s[0] = '\0'; + if (flags & IFF_UP) + strcat (s, "IFF_UP"); +#define IFF(flag) \ + do { \ + if (flags & flag) { \ + strcat (s, s[0] ? ("|" #flag) : (#flag)); \ + } \ + } while (0) +#ifdef IFF_BROADCAST + IFF(IFF_BROADCAST); +#endif +#ifdef IFF_DEBUG + IFF(IFF_DEBUG); +#endif +#ifdef IFF_LOOPBACK + IFF(IFF_LOOPBACK); +#endif +#ifdef IFF_POINTOPOINT + IFF(IFF_POINTOPOINT); +#endif +#ifdef IFF_RUNNING + IFF(IFF_RUNNING); +#endif +#ifdef IFF_NOARP + IFF(IFF_NOARP); +#endif +#ifdef IFF_PROMISC + IFF(IFF_PROMISC); +#endif +#ifdef IFF_NOTRAILERS + IFF(IFF_NOTRAILERS); +#endif +#ifdef IFF_ALLMULTI + IFF(IFF_ALLMULTI); +#endif +#ifdef IFF_MASTER + IFF(IFF_MASTER); +#endif +#ifdef IFF_SLAVE + IFF(IFF_SLAVE); +#endif +#ifdef IFF_MULTICAST + IFF(IFF_MULTICAST); +#endif +#ifdef IFF_PORTSEL + IFF(IFF_PORTSEL); +#endif +#ifdef IFF_AUTOMEDIA + IFF(IFF_AUTOMEDIA); +#endif +#ifdef IFF_DYNAMIC + IFF(IFF_DYNAMIC); +#endif +#ifdef IFF_LOWER_UP + IFF(IFF_LOWER_UP); +#endif +#ifdef IFF_DORMANT + IFF(IFF_DORMANT); +#endif +#ifdef IFF_ECHO + IFF(IFF_ECHO); +#endif + if (!s[0]) { + if (flags) + sprintf (s, "0x%x", flags); + else + strcpy (s, "(null)"); + } + return s; +} + +/* target: + * bool + * pgm_getifaddrs ( + * struct pgm_ifaddrs_t**restrict ifap, + * pgm_error_t**restrict error + * ) + */ + +START_TEST (test_getifaddrs_pass_001) +{ + char saddr[INET6_ADDRSTRLEN], snetmask[INET6_ADDRSTRLEN]; + struct pgm_ifaddrs_t *ifap = NULL, *ifa; + pgm_error_t* err = NULL; + fail_unless (TRUE == pgm_getifaddrs (&ifap, &err), "getifaddrs failed"); + for (ifa = ifap; ifa; ifa = ifa->ifa_next) + { + fail_unless (NULL != ifa, "invalid address"); + if (ifa->ifa_addr) { + if (AF_INET == ifa->ifa_addr->sa_family || + AF_INET6 == ifa->ifa_addr->sa_family) + pgm_sockaddr_ntop (ifa->ifa_addr, saddr, sizeof(saddr)); +#ifdef AF_PACKET + else if (AF_PACKET == ifa->ifa_addr->sa_family) + strcpy (saddr, "(AF_PACKET)"); +#endif + else + sprintf (saddr, "(AF = %d)", ifa->ifa_addr->sa_family); + } else + strcpy (saddr, "(null)"); + if (ifa->ifa_netmask) { + if (AF_INET == ifa->ifa_addr->sa_family || + AF_INET6 == ifa->ifa_addr->sa_family) + pgm_sockaddr_ntop (ifa->ifa_netmask, snetmask, sizeof(snetmask)); +#ifdef AF_PACKET + else if (AF_PACKET == ifa->ifa_addr->sa_family) + strcpy (snetmask, "(AF_PACKET)"); +#endif + else + sprintf (snetmask, "(AF = %d)", ifa->ifa_addr->sa_family); + } else + strcpy (snetmask, "(null)"); + g_message ("ifa = {" + "ifa_next = %p, " + "ifa_name = %s%s%s, " + "ifa_flags = %s, " + "ifa_addr = %s, " + "ifa_netmask = %s" + "}", + ifa->ifa_next, + ifa->ifa_name ? "\"" : "", ifa->ifa_name ? ifa->ifa_name : "(null)", ifa->ifa_name ? "\"" : "", + ifflags_string (ifa->ifa_flags), + saddr, + snetmask); + } +} +END_TEST + +START_TEST (test_getifaddrs_fail_001) +{ + fail_unless (FALSE == pgm_getifaddrs (NULL, NULL), "getifaddrs failed"); + g_message ("errno:%d", errno); +} +END_TEST + +/* target: + * void + * pgm_freeifaddrs ( + * struct pgm_ifaddrs* ifa + * ) + */ + +START_TEST (test_freeifaddrs_pass_001) +{ + struct pgm_ifaddrs_t* ifap = NULL; + pgm_error_t* err = NULL; + fail_unless (TRUE == pgm_getifaddrs (&ifap, &err), "getifaddrs failed"); + pgm_freeifaddrs (ifap); +} +END_TEST + +/* silent failure */ +START_TEST (test_freeifaddrs_pass_002) +{ + pgm_freeifaddrs (NULL); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_getifaddrs = tcase_create ("getifaddrs"); + suite_add_tcase (s, tc_getifaddrs); + tcase_add_test (tc_getifaddrs, test_getifaddrs_pass_001); + tcase_add_test_raise_signal (tc_getifaddrs, test_getifaddrs_fail_001, SIGABRT); + + TCase* tc_freeifaddrs = tcase_create ("freeifaddrs"); + suite_add_tcase (s, tc_freeifaddrs); + tcase_add_test (tc_freeifaddrs, test_freeifaddrs_pass_001); + tcase_add_test (tc_freeifaddrs, test_freeifaddrs_pass_002); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr.c b/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr.c new file mode 100644 index 0000000..0765c9f --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr.c @@ -0,0 +1,196 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable function to return the nodes IP address. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#ifndef _WIN32 +# include +#endif +#include +#include + + +//#define GETNODEADDR_DEBUG + + +/* globals */ + +static const char* pgm_family_string (const sa_family_t); + + +/* return node primary address on multi-address family interfaces. + * + * returns TRUE on success, returns FALSE on failure. + */ + +bool +pgm_if_getnodeaddr ( + const sa_family_t family, /* requested address family, AF_INET, AF_INET6, or AF_UNSPEC */ + struct sockaddr* restrict addr, + const socklen_t cnt, /* size of address pointed to by addr */ + pgm_error_t** restrict error + ) +{ + pgm_return_val_if_fail (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family, FALSE); + pgm_return_val_if_fail (NULL != addr, FALSE); + if (AF_INET == family || AF_UNSPEC == family) + pgm_return_val_if_fail (cnt >= sizeof(struct sockaddr_in), FALSE); + else + pgm_return_val_if_fail (cnt >= sizeof(struct sockaddr_in6), FALSE); + + pgm_debug ("pgm_if_getnodeaddr (family:%s addr:%p cnt:%d error:%p)", + pgm_family_string (family), (const void*)addr, cnt, (const void*)error); + + char hostname[NI_MAXHOST + 1]; + struct hostent* he; + + if (0 != gethostname (hostname, sizeof(hostname))) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("Resolving hostname: %s"), +#ifndef _WIN32 + strerror (errno) +#else + pgm_wsastrerror (WSAGetLastError()) +#endif + ); + return FALSE; + } + + addr->sa_family = family; + struct addrinfo hints = { + .ai_family = family, + .ai_socktype = SOCK_STREAM, /* not really */ + .ai_protocol = IPPROTO_TCP, /* not really */ + .ai_flags = AI_ADDRCONFIG, + }, *res; + + int e = getaddrinfo (hostname, NULL, &hints, &res); + if (0 == e) { + const socklen_t addrlen = res->ai_addrlen; + memcpy (addr, res->ai_addr, addrlen); + freeaddrinfo (res); + return TRUE; + } else if (EAI_NONAME != e) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_eai_errno (e, errno), + _("Resolving hostname address: %s"), + gai_strerror (e)); + return FALSE; + } else if (AF_UNSPEC == family) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NONAME, + _("Resolving hostname address family.")); + return FALSE; + } + +/* Common case a dual stack host has incorrect IPv6 configuration, i.e. + * hostname is only IPv4 and despite one or more IPv6 addresses. Workaround + * for this case is to resolve the IPv4 hostname, find the matching interface + * and from that interface find an active IPv6 address taking global scope as + * preference over link scoped addresses. + */ + he = gethostbyname (hostname); + if (NULL == he) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_h_errno (h_errno), +#ifndef _WIN32 + _("Resolving IPv4 hostname address: %s"), + hstrerror (h_errno) +#else + _("Resolving IPv4 hostname address: %s"), + pgm_wsastrerror (WSAGetLastError()) +#endif + ); + return FALSE; + } + + struct pgm_ifaddrs_t *ifap, *ifa, *ifa6; + if (!pgm_getifaddrs (&ifap, error)) { + pgm_prefix_error (error, + _("Enumerating network interfaces: ")); + return FALSE; + } + +/* hunt for IPv4 interface */ + for (ifa = ifap; ifa; ifa = ifa->ifa_next) + { + if (NULL == ifa->ifa_addr || + AF_INET != ifa->ifa_addr->sa_family) + continue; + if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == ((struct in_addr*)(he->h_addr_list[0]))->s_addr) + { + goto ipv4_found; + } + } + pgm_freeifaddrs (ifap); + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NONET, + _("Discovering primary IPv4 network interface.")); + return FALSE; +ipv4_found: + +/* hunt for IPv6 interface */ + for (ifa6 = ifap; ifa6; ifa6 = ifa6->ifa_next) + { + if (AF_INET6 != ifa6->ifa_addr->sa_family) + continue; + if (0 == strcmp (ifa->ifa_name, ifa6->ifa_name)) + { + goto ipv6_found; + } + } + pgm_freeifaddrs (ifap); + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NONET, + _("Discovering primary IPv6 network interface.")); + return FALSE; +ipv6_found: + + memcpy (addr, ifa6->ifa_addr, pgm_sockaddr_len (ifa6->ifa_addr)); + pgm_freeifaddrs (ifap); + return TRUE; +} + +static +const char* +pgm_family_string ( + const sa_family_t family + ) +{ + const char* c; + + switch (family) { + case AF_UNSPEC: c = "AF_UNSPEC"; break; + case AF_INET: c = "AF_INET"; break; + case AF_INET6: c = "AF_INET6"; break; + default: c = "(unknown)"; break; + } + + return c; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr.c.c89.patch new file mode 100644 index 0000000..06db807 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr.c.c89.patch @@ -0,0 +1,59 @@ +--- getnodeaddr.c 2010-05-21 11:35:15.000000000 +0800 ++++ getnodeaddr.c89 2010-08-05 13:17:31.000000000 +0800 +@@ -58,6 +58,7 @@ + pgm_debug ("pgm_if_getnodeaddr (family:%s addr:%p cnt:%d error:%p)", + pgm_family_string (family), (const void*)addr, cnt, (const void*)error); + ++ { + char hostname[NI_MAXHOST + 1]; + struct hostent* he; + +@@ -75,15 +76,22 @@ + return FALSE; + } + ++/* sa_family_t may be ADDRESS_FAMILY on Vista+ which is a USHORT, whilst ULONG ++ * on earlier targets. ++ */ ++#pragma warning( disable : 4244 ) + addr->sa_family = family; +- struct addrinfo hints = { +- .ai_family = family, +- .ai_socktype = SOCK_STREAM, /* not really */ +- .ai_protocol = IPPROTO_TCP, /* not really */ +- .ai_flags = AI_ADDRCONFIG, +- }, *res; ++#pragma warning( default : 4244 ) ++ { ++ int e; ++ struct addrinfo hints, *res; ++ memset (&hints, 0, sizeof(hints)); ++ hints.ai_family = family, ++ hints.ai_socktype = SOCK_STREAM, /* not really */ ++ hints.ai_protocol = IPPROTO_TCP, /* not really */ ++ hints.ai_flags = AI_ADDRCONFIG, + +- int e = getaddrinfo (hostname, NULL, &hints, &res); ++ e = getaddrinfo (hostname, NULL, &hints, &res); + if (0 == e) { + const socklen_t addrlen = res->ai_addrlen; + memcpy (addr, res->ai_addr, addrlen); +@@ -125,7 +133,9 @@ + ); + return FALSE; + } ++ } + ++ { + struct pgm_ifaddrs_t *ifap, *ifa, *ifa6; + if (!pgm_getifaddrs (&ifap, error)) { + pgm_prefix_error (error, +@@ -172,6 +182,8 @@ + + memcpy (addr, ifa6->ifa_addr, pgm_sockaddr_len (ifa6->ifa_addr)); + pgm_freeifaddrs (ifap); ++ } ++ } + return TRUE; + } + diff --git a/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr_unittest.c new file mode 100644 index 0000000..a226931 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr_unittest.c @@ -0,0 +1,573 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for portable function to return the nodes IP address. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* IFF_UP */ +#define _BSD_SOURCE 1 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* mock state */ + +struct addrinfo; + +struct mock_host_t { + struct sockaddr_storage address; + char* canonical_hostname; + char* alias; +}; + +struct mock_interface_t { + unsigned int index; + char* name; + unsigned int flags; + struct sockaddr_storage addr; + struct sockaddr_storage netmask; +}; + +static GList *mock_hosts = NULL, *mock_interfaces = NULL; + +#define MOCK_HOSTNAME "kiku" +static char* mock_kiku = MOCK_HOSTNAME; +static char* mock_localhost = "localhost"; +static char* mock_invalid = "invalid.invalid"; /* RFC 2606 */ +static char* mock_toolong = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij12345"; /* 65 */ +static char* mock_hostname = NULL; + +struct pgm_ifaddrs_t; +struct pgm_error_t; + +static bool mock_pgm_getifaddrs (struct pgm_ifaddrs_t**, struct pgm_error_t**); +static void mock_pgm_freeifaddrs (struct pgm_ifaddrs_t*); +static int mock_getaddrinfo (const char*, const char*, const struct addrinfo*, struct addrinfo**); +static void mock_freeaddrinfo (struct addrinfo*); +static int mock_gethostname (char*, size_t); +static struct hostent* mock_gethostbyname (const char*); + + +#define pgm_getifaddrs mock_pgm_getifaddrs +#define pgm_freeifaddrs mock_pgm_freeifaddrs +#define getaddrinfo mock_getaddrinfo +#define freeaddrinfo mock_freeaddrinfo +#define gethostname mock_gethostname +#define gethostbyname mock_gethostbyname + + +#define GETNODEADDR_DEBUG +#include "getnodeaddr.c" + + +static +gpointer +create_host ( + const char* address, + const char* canonical_hostname, + const char* alias + ) +{ + struct mock_host_t* new_host; + + g_assert (address); + g_assert (canonical_hostname); + + new_host = g_slice_alloc0 (sizeof(struct mock_host_t)); + g_assert (pgm_sockaddr_pton (address, (struct sockaddr*)&new_host->address)); + new_host->canonical_hostname = g_strdup (canonical_hostname); + new_host->alias = alias ? g_strdup (alias) : NULL; + + return new_host; +} + +static +gpointer +create_interface ( + const unsigned index, + const char* name, + const char* flags + ) +{ + struct mock_interface_t* new_interface; + + g_assert (name); + g_assert (flags); + + new_interface = g_slice_alloc0 (sizeof(struct mock_interface_t)); + new_interface->index = index; + new_interface->name = g_strdup (name); + + struct sockaddr_in* sin = (gpointer)&new_interface->addr; + struct sockaddr_in6* sin6 = (gpointer)&new_interface->addr; + + gchar** tokens = g_strsplit (flags, ",", 0); + for (guint i = 0; tokens[i]; i++) + { + if (strcmp (tokens[i], "up") == 0) + new_interface->flags |= IFF_UP; + else if (strcmp (tokens[i], "down") == 0) + new_interface->flags |= 0; + else if (strcmp (tokens[i], "loop") == 0) + new_interface->flags |= IFF_LOOPBACK; + else if (strcmp (tokens[i], "broadcast") == 0) + new_interface->flags |= IFF_BROADCAST; + else if (strcmp (tokens[i], "multicast") == 0) + new_interface->flags |= IFF_MULTICAST; + else if (strncmp (tokens[i], "ip=", strlen("ip=")) == 0) { + const char* addr = tokens[i] + strlen("ip="); + g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->addr)); + } + else if (strncmp (tokens[i], "netmask=", strlen("netmask=")) == 0) { + const char* addr = tokens[i] + strlen("netmask="); + g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->netmask)); + } + else if (strncmp (tokens[i], "scope=", strlen("scope=")) == 0) { + const char* scope = tokens[i] + strlen("scope="); + g_assert (AF_INET6 == ((struct sockaddr*)&new_interface->addr)->sa_family); + ((struct sockaddr_in6*)&new_interface->addr)->sin6_scope_id = atoi (scope); + } + else + g_error ("parsing failed for flag %s%s%s", + tokens[i] ? "\"" : "", tokens[i] ? tokens[i] : "(null)", tokens[i] ? "\"" : ""); + } + + g_strfreev (tokens); + return new_interface; +} + +#define APPEND_HOST2(a,b,c) \ + do { \ + gpointer data = create_host ((a), (b), (c)); \ + g_assert (data); \ + mock_hosts = g_list_append (mock_hosts, data); \ + g_assert (mock_hosts); g_assert (mock_hosts->data); \ + } while (0) +#define APPEND_HOST(a,b) APPEND_HOST2((a),(b),NULL) +#define APPEND_INTERFACE(a,b,c) \ + do { \ + gpointer data = create_interface ((a), (b), (c)); \ + g_assert (data); \ + mock_interfaces = g_list_append (mock_interfaces, data); \ + g_assert (mock_interfaces); g_assert (mock_interfaces->data); \ + } while (0) +static +void +mock_setup_net (void) +{ + mock_hostname = mock_kiku; + + APPEND_HOST ( "127.0.0.1", "localhost"); + APPEND_HOST2( "10.6.28.33", "kiku.hk.miru.hk", "kiku"); + APPEND_HOST2( "2002:dce8:d28e::33", "ip6-kiku", "kiku"); + APPEND_HOST2( "::1", "ip6-localhost", "ip6-loopback"); + + APPEND_INTERFACE( 1, "lo", "up,loop"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast"); + APPEND_INTERFACE( 3, "eth1", "down,broadcast,multicast"); + APPEND_INTERFACE( 1, "lo", "up,loop,ip=127.0.0.1,netmask=255.0.0.0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=10.6.28.33,netmask=255.255.255.0"); + APPEND_INTERFACE( 1, "lo", "up,loop,ip=::1,netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,scope=0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=2002:dce8:d28e::33,netmask=ffff:ffff:ffff:ffff::0,scope=0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=fe80::214:5eff:febd:6dda,netmask=ffff:ffff:ffff:ffff::0,scope=2"); +} + +/* with broken IPv6 hostname setup */ +static +void +mock_setup_net2 (void) +{ + mock_hostname = mock_kiku; + + APPEND_HOST ( "127.0.0.1", "localhost"); + APPEND_HOST2( "10.6.28.33", "kiku.hk.miru.hk", "kiku"); + APPEND_HOST( "2002:dce8:d28e::33", "ip6-kiku"); + APPEND_HOST2( "::1", "ip6-localhost", "ip6-loopback"); + + APPEND_INTERFACE( 1, "lo", "up,loop"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast"); + APPEND_INTERFACE( 3, "eth1", "down,broadcast,multicast"); + APPEND_INTERFACE( 1, "lo", "up,loop,ip=127.0.0.1,netmask=255.0.0.0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=10.6.28.33,netmask=255.255.255.0"); + APPEND_INTERFACE( 1, "lo", "up,loop,ip=::1,netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,scope=0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=2002:dce8:d28e::33,netmask=ffff:ffff:ffff:ffff::0,scope=0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=fe80::214:5eff:febd:6dda,netmask=ffff:ffff:ffff:ffff::0,scope=2"); +} + +static +void +mock_teardown_net (void) +{ + GList* list; + + list = mock_hosts; + while (list) { + struct mock_host_t* host = list->data; + g_free (host->canonical_hostname); + if (host->alias) + g_free (host->alias); + g_slice_free1 (sizeof(struct mock_host_t), host); + list = list->next; + } + g_list_free (mock_hosts); + + list = mock_interfaces; + while (list) { + struct mock_interface_t* interface = list->data; + g_free (interface->name); + g_slice_free1 (sizeof(struct mock_interface_t), interface); + list = list->next; + } + g_list_free (mock_interfaces); +} + + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + +static +bool +mock_pgm_getifaddrs ( + struct pgm_ifaddrs_t** ifap, + pgm_error_t** err + ) +{ + if (NULL == ifap) { + return FALSE; + } + + g_debug ("mock_getifaddrs (ifap:%p err:%p)", (gpointer)ifap, (gpointer)err); + + GList* list = mock_interfaces; + int n = g_list_length (list); + struct pgm_ifaddrs_t* ifa = malloc (n * sizeof(struct pgm_ifaddrs_t)); + memset (ifa, 0, n * sizeof(struct pgm_ifaddrs_t)); + struct pgm_ifaddrs_t* ift = ifa; + while (list) { + struct mock_interface_t* interface = list->data; + ift->ifa_addr = (gpointer)&interface->addr; + ift->ifa_name = interface->name; + ift->ifa_flags = interface->flags; + ift->ifa_netmask = (gpointer)&interface->netmask; + list = list->next; + if (list) { + ift->ifa_next = ift + 1; + ift = ift->ifa_next; + } + } + + *ifap = ifa; + return TRUE; +} + +static +void +mock_pgm_freeifaddrs ( + struct pgm_ifaddrs_t* ifa + ) +{ + g_debug ("mock_freeifaddrs (ifa:%p)", (gpointer)ifa); + free (ifa); +} + +static +struct hostent* +mock_gethostbyname ( + const char* name + ) +{ + static struct hostent he; + static char* aliases[2]; + static char* addr_list[2]; + +/* pre-conditions */ + g_assert (NULL != name); + + g_debug ("mock_gethostbyname (name:%s%s%s)", + name ? "\"" : "", name ? name : "(null)", name ? "\"" : ""); + + GList* list = mock_hosts; + while (list) { + struct mock_host_t* host = list->data; + const int host_family = ((struct sockaddr*)&host->address)->sa_family; + if (((strcmp (host->canonical_hostname, name) == 0) || + (host->alias && strcmp (host->alias, name) == 0))) + { + he.h_name = host->canonical_hostname; + aliases[0] = host->alias; + aliases[1] = NULL; + he.h_aliases = aliases; + he.h_addrtype = host_family; + switch (host->address.ss_family){ + case AF_INET: + he.h_length = sizeof (struct in_addr); + addr_list[0] = (char*)&host->address + G_STRUCT_OFFSET(struct sockaddr_in, sin_addr); + break; + case AF_INET6: + he.h_length = sizeof (struct in6_addr); + addr_list[0] = (char*)&host->address + G_STRUCT_OFFSET(struct sockaddr_in6, sin6_addr); + break; + default: + g_assert_not_reached(); + } + addr_list[1] = NULL; + he.h_addr_list = addr_list; + return &he; + } + list = list->next; + } + h_errno = HOST_NOT_FOUND; + return NULL; +} + +static +int +mock_getaddrinfo ( + const char* node, + const char* service, + const struct addrinfo* hints, + struct addrinfo** res + ) +{ + const int ai_flags = hints ? hints->ai_flags : (AI_V4MAPPED | AI_ADDRCONFIG); + const int ai_family = hints ? hints->ai_family : AF_UNSPEC; + GList* list; + struct sockaddr_storage addr; + + if (NULL == node && NULL == service) + return EAI_NONAME; + +/* pre-conditions */ + g_assert (NULL != node); + g_assert (NULL == service); + g_assert (!(ai_flags & AI_CANONNAME)); + g_assert (!(ai_flags & AI_NUMERICSERV)); + g_assert (!(ai_flags & AI_V4MAPPED)); + + g_debug ("mock_getaddrinfo (node:\"%s\" service:%s hints:%p res:%p)", + node ? node : "(null)", + service ? service : "(null)", + (gpointer)hints, + (gpointer)res); + + gboolean has_ip4_config; + gboolean has_ip6_config; + + if (hints && hints->ai_flags & AI_ADDRCONFIG) + { + has_ip4_config = has_ip6_config = FALSE; + list = mock_interfaces; + while (list) { + const struct mock_interface_t* interface = list->data; + if (AF_INET == ((struct sockaddr*)&interface->addr)->sa_family) + has_ip4_config = TRUE; + else if (AF_INET6 == ((struct sockaddr*)&interface->addr)->sa_family) + has_ip6_config = TRUE; + if (has_ip4_config && has_ip6_config) + break; + list = list->next; + } + } else { + has_ip4_config = has_ip6_config = TRUE; + } + + if (ai_flags & AI_NUMERICHOST) { + pgm_sockaddr_pton (node, (struct sockaddr*)&addr); + } + list = mock_hosts; + while (list) { + struct mock_host_t* host = list->data; + const int host_family = ((struct sockaddr*)&host->address)->sa_family; + if (((strcmp (host->canonical_hostname, node) == 0) || + (host->alias && strcmp (host->alias, node) == 0) || + (ai_flags & AI_NUMERICHOST && + 0 == pgm_sockaddr_cmp ((struct sockaddr*)&addr, (struct sockaddr*)&host->address))) + && + (host_family == ai_family || AF_UNSPEC == ai_family) && + ((AF_INET == host_family && has_ip4_config) || (AF_INET6 == host_family && has_ip6_config))) + { + struct addrinfo* ai = malloc (sizeof(struct addrinfo)); + memset (ai, 0, sizeof(struct addrinfo)); + ai->ai_family = host_family; + ai->ai_addrlen = AF_INET == host_family ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); + ai->ai_addr = (gpointer)&host->address; + *res = ai; + return 0; + } + list = list->next; + } + return EAI_NONAME; +} + +static +void +mock_freeaddrinfo ( + struct addrinfo* res + ) +{ + g_assert (NULL != res); + g_debug ("mock_freeaddrinfo (res:%p)", (gpointer)res); + free (res); +} + +static +int +mock_gethostname ( + char* name, + size_t len + ) +{ + g_debug ("mock_gethostname (name:%p len:%d)", + (gpointer)name, len); + + if (NULL == name) { + errno = EFAULT; + return -1; + } + if (len < 0) { + errno = EINVAL; + return -1; + } + if (len < (1 + strlen (mock_hostname))) { + errno = ENAMETOOLONG; + return -1; + } +/* force an error */ + if (mock_hostname == mock_toolong) { + errno = ENAMETOOLONG; + return -1; + } + strncpy (name, mock_hostname, len); + if (len > 0) + name[len - 1] = '\0'; + return 0; +} + + +/* target: + * bool + * pgm_if_getnodeaddr ( + * const sa_family_t family, + * struct sockaddr* addr, + * const socklen_t cnt, + * pgm_error_t** error + * ) + */ + +START_TEST (test_getnodeaddr_pass_001) +{ + struct sockaddr_storage addr; + char saddr[INET6_ADDRSTRLEN]; + pgm_error_t* err = NULL; + gboolean success = pgm_if_getnodeaddr (AF_UNSPEC, (struct sockaddr*)&addr, sizeof(addr), &err); + if (!success && err) { + g_error ("Resolving node address with AF_UNSPEC: %s", (err && err->message) ? err->message : "(null)"); + } + fail_unless (TRUE == success, "getnodeaddr failed"); + fail_unless (NULL == err, "error raised"); + pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); + g_message ("AF_UNSPEC:%s", saddr ? saddr : "(null)"); + fail_unless (TRUE == pgm_if_getnodeaddr (AF_INET, (struct sockaddr*)&addr, sizeof(addr), &err), "getnodeaddr failed"); + fail_unless (NULL == err, "error raised"); + pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); + g_message ("AF_INET:%s", saddr ? saddr : "(null)"); + fail_unless (TRUE == pgm_if_getnodeaddr (AF_INET6, (struct sockaddr*)&addr, sizeof(addr), &err), "getnodeaddr failed"); + fail_unless (NULL == err, "error raised"); + pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); + g_message ("AF_INET6:%s", saddr ? saddr : "(null)"); +} +END_TEST + +START_TEST (test_getnodeaddr_fail_001) +{ + pgm_error_t* err = NULL; + fail_unless (FALSE == pgm_if_getnodeaddr (AF_UNSPEC, NULL, 0, &err), "getnodeaddr failed"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + +{ + mock_setup_net(); + + struct sockaddr_storage addr; + char saddr[INET6_ADDRSTRLEN]; + pgm_error_t* err = NULL; + gboolean success = pgm_if_getnodeaddr (AF_UNSPEC, (struct sockaddr*)&addr, sizeof(addr), &err); + if (!success && err) { + g_error ("Resolving node address with AF_UNSPEC: %s", (err && err->message) ? err->message : "(null)"); + } +} + s = suite_create (__FILE__); + + TCase* tc_getnodeaddr = tcase_create ("getnodeaddr"); + suite_add_tcase (s, tc_getnodeaddr); + tcase_add_checked_fixture (tc_getnodeaddr, mock_setup_net, mock_teardown_net); + tcase_add_test (tc_getnodeaddr, test_getnodeaddr_pass_001); + tcase_add_test (tc_getnodeaddr, test_getnodeaddr_fail_001); + + TCase* tc_getnodeaddr2 = tcase_create ("getnodeaddr/2"); + suite_add_tcase (s, tc_getnodeaddr2); + tcase_add_checked_fixture (tc_getnodeaddr2, mock_setup_net2, mock_teardown_net); + tcase_add_test (tc_getnodeaddr2, test_getnodeaddr_pass_001); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/gsi.c b/3rdparty/openpgm-svn-r1135/pgm/gsi.c new file mode 100644 index 0000000..c086cb9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/gsi.c @@ -0,0 +1,232 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * global session ID helper functions. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#ifndef _WIN32 +# include +#endif +#include +#include + + +//#define GSI_DEBUG + + +/* create a GSI based on md5 of a user provided data block. + * + * returns TRUE on success, returns FALSE on error and sets error appropriately, + */ + +bool +pgm_gsi_create_from_data ( + pgm_gsi_t* restrict gsi, + const uint8_t* restrict data, + const size_t length + ) +{ + pgm_return_val_if_fail (NULL != gsi, FALSE); + pgm_return_val_if_fail (NULL != data, FALSE); + pgm_return_val_if_fail (length > 1, FALSE); + +#ifdef CONFIG_HAVE_GLIB_CHECKSUM + GChecksum* checksum = g_checksum_new (G_CHECKSUM_MD5); + pgm_return_val_if_fail (NULL != checksum, FALSE); + g_checksum_update (checksum, data, length); + memcpy (gsi, g_checksum_get_string (checksum) + 10, 6); + g_checksum_free (checksum); +#else + struct pgm_md5_t ctx; + char resblock[16]; + pgm_md5_init_ctx (&ctx); + pgm_md5_process_bytes (&ctx, data, length); + pgm_md5_finish_ctx (&ctx, resblock); + memcpy (gsi, resblock + 10, 6); +#endif + return TRUE; +} + +bool +pgm_gsi_create_from_string ( + pgm_gsi_t* restrict gsi, + const char* restrict str, + ssize_t length /* -1 for NULL terminated */ + ) +{ + pgm_return_val_if_fail (NULL != gsi, FALSE); + pgm_return_val_if_fail (NULL != str, FALSE); + + if (length < 0) + length = strlen (str); + + return pgm_gsi_create_from_data (gsi, (const uint8_t*)str, length); +} + +/* create a global session ID as recommended by the PGM draft specification using + * low order 48 bits of md5 of the hostname. + * + * returns TRUE on success, returns FALSE on error and sets error appropriately, + */ + +bool +pgm_gsi_create_from_hostname ( + pgm_gsi_t* restrict gsi, + pgm_error_t** restrict error + ) +{ + pgm_return_val_if_fail (NULL != gsi, FALSE); + + char hostname[NI_MAXHOST]; + int retval = gethostname (hostname, sizeof(hostname)); + if (0 != retval) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("Resolving hostname: %s"), +#ifndef _WIN32 + strerror (errno) +#else + pgm_wsastrerror (WSAGetLastError()) +#endif + ); + return FALSE; + } + + return pgm_gsi_create_from_string (gsi, hostname, -1); +} + +/* create a global session ID based on the IP address. + * + * returns TRUE on succcess, returns FALSE on error and sets error. + */ + +bool +pgm_gsi_create_from_addr ( + pgm_gsi_t* restrict gsi, + pgm_error_t** restrict error + ) +{ + char hostname[NI_MAXHOST]; + struct addrinfo hints, *res = NULL; + + pgm_return_val_if_fail (NULL != gsi, FALSE); + + int retval = gethostname (hostname, sizeof(hostname)); + if (0 != retval) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_errno (errno), + _("Resolving hostname: %s"), +#ifndef _WIN32 + strerror (errno) +#else + pgm_wsastrerror (WSAGetLastError()) +#endif + ); + return FALSE; + } + memset (&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_flags = AI_ADDRCONFIG; + retval = getaddrinfo (hostname, NULL, &hints, &res); + if (0 != retval) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_eai_errno (retval, errno), + _("Resolving hostname address: %s"), + gai_strerror (retval)); + return FALSE; + } + memcpy (gsi, &((struct sockaddr_in*)(res->ai_addr))->sin_addr, sizeof(struct in_addr)); + freeaddrinfo (res); + const uint16_t random_val = pgm_random_int_range (0, UINT16_MAX); + memcpy ((uint8_t*)gsi + sizeof(struct in_addr), &random_val, sizeof(random_val)); + return TRUE; +} + +/* re-entrant form of pgm_gsi_print() + * + * returns number of bytes written to buffer on success, returns -1 on + * invalid parameters. + */ + +int +pgm_gsi_print_r ( + const pgm_gsi_t* restrict gsi, + char* restrict buf, + const size_t bufsize + ) +{ + const uint8_t* restrict src = (const uint8_t* restrict)gsi; + + pgm_return_val_if_fail (NULL != gsi, -1); + pgm_return_val_if_fail (NULL != buf, -1); + pgm_return_val_if_fail (bufsize > 0, -1); + +#ifdef _MSC_VER + return _snprintf_s (buf, bufsize, _TRUNCATE, "%i.%i.%i.%i.%i.%i", + src[0], src[1], src[2], src[3], src[4], src[5]); +#else + return snprintf (buf, bufsize, "%i.%i.%i.%i.%i.%i", + src[0], src[1], src[2], src[3], src[4], src[5]); +#endif +} + +/* transform GSI to ASCII string form. + * + * on success, returns pointer to ASCII string. on error, returns NULL. + */ + +char* +pgm_gsi_print ( + const pgm_gsi_t* gsi + ) +{ + static char buf[PGM_GSISTRLEN]; + + pgm_return_val_if_fail (NULL != gsi, NULL); + + pgm_gsi_print_r (gsi, buf, sizeof(buf)); + return buf; +} + +/* compare two global session identifier GSI values and return TRUE if they are equal + */ + +bool +pgm_gsi_equal ( + const void* restrict p1, + const void* restrict p2 + ) +{ + const union { + pgm_gsi_t gsi; + uint16_t s[3]; + } *u1 = p1, *u2 = p2; + +/* pre-conditions */ + pgm_assert (NULL != p1); + pgm_assert (NULL != p2); + + return (u1->s[0] == u2->s[0] && u1->s[1] == u2->s[1] && u1->s[2] == u2->s[2]); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/gsi.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/gsi.c.c89.patch new file mode 100644 index 0000000..b7edc28 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/gsi.c.c89.patch @@ -0,0 +1,53 @@ +--- gsi.c 2010-08-04 11:14:59.000000000 +0800 ++++ gsi.c89 2010-08-04 11:16:29.000000000 +0800 +@@ -54,12 +54,14 @@ + memcpy (gsi, g_checksum_get_string (checksum) + 10, 6); + g_checksum_free (checksum); + #else ++ { + struct pgm_md5_t ctx; + char resblock[16]; + pgm_md5_init_ctx (&ctx); + pgm_md5_process_bytes (&ctx, data, length); + pgm_md5_finish_ctx (&ctx, resblock); + memcpy (gsi, resblock + 10, 6); ++ } + #endif + return TRUE; + } +@@ -94,6 +96,7 @@ + { + pgm_return_val_if_fail (NULL != gsi, FALSE); + ++ { + char hostname[NI_MAXHOST]; + int retval = gethostname (hostname, sizeof(hostname)); + if (0 != retval) { +@@ -111,6 +114,7 @@ + } + + return pgm_gsi_create_from_string (gsi, hostname, -1); ++ } + } + + /* create a global session ID based on the IP address. +@@ -129,6 +133,7 @@ + + pgm_return_val_if_fail (NULL != gsi, FALSE); + ++ { + int retval = gethostname (hostname, sizeof(hostname)); + if (0 != retval) { + pgm_set_error (error, +@@ -157,8 +162,11 @@ + } + memcpy (gsi, &((struct sockaddr_in*)(res->ai_addr))->sin_addr, sizeof(struct in_addr)); + freeaddrinfo (res); ++ { + const uint16_t random_val = pgm_random_int_range (0, UINT16_MAX); + memcpy ((uint8_t*)gsi + sizeof(struct in_addr), &random_val, sizeof(random_val)); ++ } ++ } + return TRUE; + } + diff --git a/3rdparty/openpgm-svn-r1135/pgm/gsi_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/gsi_unittest.c new file mode 100644 index 0000000..dc4c244 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/gsi_unittest.c @@ -0,0 +1,350 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for global session ID helper functions. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* mock state */ + +static char* mock_localhost = "localhost"; +static char* mock_invalid = "invalid.invalid"; /* RFC 2606 */ +static char* mock_toolong = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij12345"; /* 65 */ +static char* mock_hostname = NULL; + + +static +void +mock_setup_invalid (void) +{ + mock_hostname = mock_invalid; +} + +static +void +mock_setup_toolong (void) +{ + mock_hostname = mock_toolong; +} + +static +void +mock_setup_localhost (void) +{ + mock_hostname = mock_localhost; +} + +static +void +mock_teardown (void) +{ +// null +} + + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + +int +mock_gethostname ( + char* name, + size_t len + ) +{ + if (mock_hostname == mock_toolong) { + errno = EINVAL; + return -1; + } + strncpy (name, mock_hostname, len); + if (len > 0) + name[len - 1] = '\0'; + return 0; +} + + +#define gethostname mock_gethostname + +#define GSI_DEBUG +#include "gsi.c" + + +/* target: + * bool + * pgm_gsi_create_from_hostname ( + * pgm_gsi_t* gsi, + * pgm_error_t** err + * ) + */ + +START_TEST (test_create_from_hostname_pass_001) +{ + pgm_gsi_t gsi; + pgm_error_t* err = NULL; + fail_unless (pgm_gsi_create_from_hostname (&gsi, &err), "create_from_hostname failed"); + fail_if (err, "error raised"); + fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); +} +END_TEST + +START_TEST (test_create_from_hostname_pass_002) +{ + pgm_error_t* err = NULL; + fail_if (pgm_gsi_create_from_hostname (NULL, &err), "create_from_hostname failed"); + fail_if (err, "error raised"); + fail_if (pgm_gsi_create_from_hostname (NULL, NULL), "create_from_hostname failed"); +} +END_TEST + +/* hostname too long */ +START_TEST (test_create_from_hostname_pass_003) +{ + pgm_gsi_t gsi; + pgm_error_t* err = NULL; + fail_if (pgm_gsi_create_from_hostname (&gsi, &err), "create_from_hostname failed"); + fail_if (NULL == err, "error not raised"); + fail_if (NULL == err->message, "no error message"); + g_debug ("pgm_error_t: %s", err->message); + fail_if (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); +} +END_TEST + +/* target: + * bool + * pgm_gsi_create_from_addr ( + * pgm_gsi_t* gsi, + * pgm_error_t** err + * ) + */ + +START_TEST (test_create_from_addr_pass_001) +{ + pgm_gsi_t gsi; + pgm_error_t* err = NULL; + fail_unless (pgm_gsi_create_from_addr (&gsi, &err), "create_from_addr failed"); + fail_if (err, "error raised"); + fail_unless (pgm_gsi_create_from_addr (&gsi, NULL), "create_from_addr failed"); +} +END_TEST + +START_TEST (test_create_from_addr_pass_002) +{ + pgm_error_t* err = NULL; + fail_if (pgm_gsi_create_from_addr (NULL, &err), "create_from_addr failed"); + fail_if (pgm_gsi_create_from_addr (NULL, NULL), "create_from_addr failed"); +} +END_TEST + +/* invalid hostname */ +START_TEST (test_create_from_addr_pass_003) +{ + pgm_gsi_t gsi; + pgm_error_t* err = NULL; + fail_if (pgm_gsi_create_from_addr (&gsi, &err), "create_from_addr failed"); + fail_if (NULL == err, "error not raised"); + fail_if (NULL == err->message, "no error message"); + g_debug ("pgm_error_t: %s", err->message); + fail_if (pgm_gsi_create_from_addr (&gsi, NULL), "create_from_addr failed"); +} +END_TEST + +/* target: + * char* + * pgm_gsi_print ( + * const pgm_gsi_t* gsi + * ) + */ + +START_TEST (test_print_pass_001) +{ + pgm_gsi_t gsi; + fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); + fail_if (NULL == pgm_gsi_print (&gsi), "print failed"); +} +END_TEST + +START_TEST (test_print_pass_002) +{ + fail_unless (NULL == pgm_gsi_print (NULL), "print failed"); +} +END_TEST + +/* target: + * int + * pgm_gsi_print_r ( + * const pgm_gsi_t* gsi, + * char* buf, + * size_t bufsize + * ) + */ + +START_TEST (test_print_r_pass_001) +{ + pgm_gsi_t gsi; + char buf[PGM_GSISTRLEN]; + fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); + fail_unless (pgm_gsi_print_r (&gsi, buf, sizeof(buf)) > 0, "print_r failed"); +} +END_TEST + +START_TEST (test_print_r_pass_002) +{ + pgm_gsi_t gsi; + char buf[PGM_GSISTRLEN]; + fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); + fail_unless (pgm_gsi_print_r (NULL, buf, sizeof(buf)) == -1, "print_r failed"); + fail_unless (pgm_gsi_print_r (&gsi, NULL, sizeof(buf)) == -1, "print_r failed"); + fail_unless (pgm_gsi_print_r (&gsi, buf, 0) == -1, "print_r failed"); +} +END_TEST + +/* target: + * bool + * pgm_gsi_equal ( + * const void* gsi1, + * const void* gsi2 + * ) + */ + +START_TEST (test_equal_pass_001) +{ + pgm_gsi_t gsi1, gsi2; + fail_unless (pgm_gsi_create_from_hostname (&gsi1, NULL), "create_from_hostname failed"); + fail_unless (pgm_gsi_create_from_hostname (&gsi2, NULL), "create_from_hostname failed"); + fail_unless (pgm_gsi_equal (&gsi1, &gsi2), "equal failed"); +} +END_TEST + +START_TEST (test_equal_pass_002) +{ + pgm_gsi_t gsi1, gsi2; + fail_unless (pgm_gsi_create_from_hostname (&gsi1, NULL), "create_from_hostname failed"); + fail_unless (pgm_gsi_create_from_addr (&gsi2, NULL), "create_from_addr failed"); + fail_if (pgm_gsi_equal (&gsi1, &gsi2), "equal failed"); +} +END_TEST + +START_TEST (test_equal_fail_001) +{ + pgm_gsi_t gsi; + fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); + gboolean retval = pgm_gsi_equal (NULL, &gsi); + fail ("reached"); +} +END_TEST + +START_TEST (test_equal_fail_002) +{ + pgm_gsi_t gsi; + fail_unless (pgm_gsi_create_from_hostname (&gsi, NULL), "create_from_hostname failed"); + gboolean retval = pgm_gsi_equal (&gsi, NULL); + fail ("reached"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_create_from_hostname = tcase_create ("create-from-hostname"); + suite_add_tcase (s, tc_create_from_hostname); + tcase_add_checked_fixture (tc_create_from_hostname, mock_setup_localhost, mock_teardown); + tcase_add_test (tc_create_from_hostname, test_create_from_hostname_pass_001); + tcase_add_test (tc_create_from_hostname, test_create_from_hostname_pass_002); + + TCase* tc_create_from_hostname2 = tcase_create ("create-from-hostname/2"); + suite_add_tcase (s, tc_create_from_hostname2); + tcase_add_checked_fixture (tc_create_from_hostname2, mock_setup_toolong, mock_teardown); + tcase_add_test (tc_create_from_hostname2, test_create_from_hostname_pass_003); + + TCase* tc_create_from_addr = tcase_create ("create-from-addr"); + suite_add_tcase (s, tc_create_from_addr); + tcase_add_checked_fixture (tc_create_from_addr, mock_setup_localhost, mock_teardown); + tcase_add_test (tc_create_from_addr, test_create_from_addr_pass_001); + tcase_add_test (tc_create_from_addr, test_create_from_addr_pass_002); + + TCase* tc_create_from_addr2 = tcase_create ("create-from-addr/2"); + suite_add_tcase (s, tc_create_from_addr2); + tcase_add_checked_fixture (tc_create_from_addr2, mock_setup_invalid, mock_teardown); + tcase_add_test (tc_create_from_addr2, test_create_from_addr_pass_003); + + TCase* tc_print = tcase_create ("print"); + suite_add_tcase (s, tc_print); + tcase_add_checked_fixture (tc_print, mock_setup_localhost, mock_teardown); + tcase_add_test (tc_print, test_print_pass_001); + tcase_add_test (tc_print, test_print_pass_002); + + TCase* tc_print_r = tcase_create ("print-r"); + suite_add_tcase (s, tc_print_r); + tcase_add_checked_fixture (tc_print_r, mock_setup_localhost, mock_teardown); + tcase_add_test (tc_print_r, test_print_r_pass_001); + tcase_add_test (tc_print_r, test_print_r_pass_002); + + TCase* tc_equal = tcase_create ("equal"); + suite_add_tcase (s, tc_equal); + tcase_add_checked_fixture (tc_equal, mock_setup_localhost, mock_teardown); + tcase_add_test (tc_equal, test_equal_pass_001); + tcase_add_test (tc_equal, test_equal_pass_002); + tcase_add_test_raise_signal (tc_equal, test_equal_fail_001, SIGABRT); + tcase_add_test_raise_signal (tc_equal, test_equal_fail_002, SIGABRT); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/hashtable.c b/3rdparty/openpgm-svn-r1135/pgm/hashtable.c new file mode 100644 index 0000000..7b99cda --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/hashtable.c @@ -0,0 +1,327 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable hashtable. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + + +//#define HASHTABLE_DEBUG + +#define HASHTABLE_MIN_SIZE 11 +#define HASHTABLE_MAX_SIZE 13845163 + +struct pgm_hashnode_t +{ + const void* key; + void* value; + struct pgm_hashnode_t* next; + uint_fast32_t key_hash; +}; + +typedef struct pgm_hashnode_t pgm_hashnode_t; + +struct pgm_hashtable_t +{ + unsigned size; + unsigned nnodes; + pgm_hashnode_t** nodes; + pgm_hashfunc_t hash_func; + pgm_equalfunc_t key_equal_func; +}; + +#define PGM_HASHTABLE_RESIZE(hash_table) \ + do { \ + if ( (hash_table->size >= 3 * hash_table->nnodes && hash_table->size > HASHTABLE_MIN_SIZE) || \ + (3 * hash_table->size <= hash_table->nnodes && hash_table->size < HASHTABLE_MAX_SIZE) ) \ + { \ + pgm_hashtable_resize (hash_table); \ + } \ + } while (0) + +static void pgm_hashtable_resize (pgm_hashtable_t*); +static pgm_hashnode_t** pgm_hashtable_lookup_node (const pgm_hashtable_t*restrict, const void*restrict, pgm_hash_t*restrict) PGM_GNUC_PURE; +static pgm_hashnode_t* pgm_hash_node_new (const void*restrict, void*restrict, const pgm_hash_t); +static void pgm_hash_node_destroy (pgm_hashnode_t*); +static void pgm_hash_nodes_destroy (pgm_hashnode_t*); + + +pgm_hashtable_t* +pgm_hashtable_new ( + pgm_hashfunc_t hash_func, + pgm_equalfunc_t key_equal_func + ) +{ + pgm_return_val_if_fail (NULL != hash_func, NULL); + pgm_return_val_if_fail (NULL != key_equal_func, NULL); + + pgm_hashtable_t *hash_table; + + hash_table = pgm_new (pgm_hashtable_t, 1); + hash_table->size = HASHTABLE_MIN_SIZE; + hash_table->nnodes = 0; + hash_table->hash_func = hash_func; + hash_table->key_equal_func = key_equal_func; + hash_table->nodes = pgm_new0 (pgm_hashnode_t*, hash_table->size); + + return hash_table; +} + +void +pgm_hashtable_unref ( + pgm_hashtable_t* hash_table + ) +{ + pgm_return_if_fail (hash_table != NULL); + + for (unsigned i = 0; i < hash_table->size; i++) + pgm_hash_nodes_destroy (hash_table->nodes[i]); + pgm_free (hash_table->nodes); + pgm_free (hash_table); +} + +void +pgm_hashtable_destroy ( + pgm_hashtable_t* hash_table + ) +{ + pgm_return_if_fail (hash_table != NULL); + + pgm_hashtable_remove_all (hash_table); + pgm_hashtable_unref (hash_table); +} + +static inline +pgm_hashnode_t** +pgm_hashtable_lookup_node ( + const pgm_hashtable_t* restrict hash_table, + const void* restrict key, + pgm_hash_t* restrict hash_return /* non-NULL to return hash value */ + ) +{ + const pgm_hash_t hash_value = (*hash_table->hash_func) (key); + pgm_hashnode_t** node = &hash_table->nodes[hash_value % hash_table->size]; + + if (hash_return) + *hash_return = hash_value; + + while (*node && (((*node)->key_hash != hash_value) || + !(*hash_table->key_equal_func) ((*node)->key, key))) + { + node = &(*node)->next; + } + + return node; +} + +void* +pgm_hashtable_lookup ( + const pgm_hashtable_t* restrict hash_table, + const void* restrict key + ) +{ + pgm_return_val_if_fail (hash_table != NULL, NULL); + + const pgm_hashnode_t* node = *pgm_hashtable_lookup_node (hash_table, key, NULL); + return node ? node->value : NULL; +} + +void* +pgm_hashtable_lookup_extended ( + const pgm_hashtable_t* restrict hash_table, + const void* restrict key, + void* restrict hash_return + ) +{ + pgm_return_val_if_fail (hash_table != NULL, NULL); + + const pgm_hashnode_t* node = *pgm_hashtable_lookup_node (hash_table, key, hash_return); + return node ? node->value : NULL; +} + +void +pgm_hashtable_insert ( + pgm_hashtable_t* restrict hash_table, + const void* restrict key, + void* restrict value + ) +{ + pgm_hashnode_t **node; + pgm_hash_t key_hash; + + pgm_return_if_fail (hash_table != NULL); + + node = pgm_hashtable_lookup_node (hash_table, key, &key_hash); + pgm_return_if_fail (NULL == *node); + + *node = pgm_hash_node_new (key, value, key_hash); + hash_table->nnodes++; + PGM_HASHTABLE_RESIZE (hash_table); +} + +bool +pgm_hashtable_remove ( + pgm_hashtable_t* restrict hash_table, + const void* restrict key + ) +{ + pgm_hashnode_t **node, *dest; + + pgm_return_val_if_fail (hash_table != NULL, FALSE); + + node = pgm_hashtable_lookup_node (hash_table, key, NULL); + if (*node) + { + dest = *node; + (*node) = dest->next; + pgm_hash_node_destroy (dest); + hash_table->nnodes--; + PGM_HASHTABLE_RESIZE (hash_table); + return TRUE; + } + return FALSE; +} + +void +pgm_hashtable_remove_all ( + pgm_hashtable_t* hash_table + ) +{ + pgm_return_if_fail (hash_table != NULL); + + for (unsigned i = 0; i < hash_table->size; i++) + { + pgm_hash_nodes_destroy (hash_table->nodes[i]); + hash_table->nodes[i] = NULL; + } + hash_table->nnodes = 0; + PGM_HASHTABLE_RESIZE (hash_table); +} + +static +void +pgm_hashtable_resize ( + pgm_hashtable_t* hash_table + ) +{ + const unsigned new_size = CLAMP (pgm_spaced_primes_closest (hash_table->nnodes), + HASHTABLE_MIN_SIZE, HASHTABLE_MAX_SIZE); + pgm_hashnode_t** new_nodes = pgm_new0 (pgm_hashnode_t*, new_size); + + for (unsigned i = 0; i < hash_table->size; i++) + for (pgm_hashnode_t *node = hash_table->nodes[i], *next; node; node = next) + { + next = node->next; + const pgm_hash_t hash_val = node->key_hash % new_size; + node->next = new_nodes[hash_val]; + new_nodes[hash_val] = node; + } + + pgm_free (hash_table->nodes); + hash_table->nodes = new_nodes; + hash_table->size = new_size; +} + +static +pgm_hashnode_t* +pgm_hash_node_new ( + const void* restrict key, + void* restrict value, + const pgm_hash_t key_hash + ) +{ + pgm_hashnode_t *hash_node = pgm_new (pgm_hashnode_t, 1); + hash_node->key = key; + hash_node->value = value; + hash_node->key_hash = key_hash; + hash_node->next = NULL; + return hash_node; +} + +static +void +pgm_hash_node_destroy ( + pgm_hashnode_t* hash_node + ) +{ + pgm_free (hash_node); +} + +static +void +pgm_hash_nodes_destroy ( + pgm_hashnode_t* hash_node + ) +{ + while (hash_node) { + pgm_hashnode_t *next = hash_node->next; + pgm_free (hash_node); + hash_node = next; + } +} + +/* common hash value compare and hash key generation functions */ + +bool +pgm_str_equal ( + const void* restrict p1, + const void* restrict p2 + ) +{ + const char *restrict s1 = p1, *restrict s2 = p2; + return (strcmp (s1, s2) == 0); +} + +/* 31 bit hash function */ + +pgm_hash_t +pgm_str_hash ( + const void* p + ) +{ + const char* s = p; + pgm_hash_t hash_val = *s; + + if (PGM_LIKELY (hash_val)) + for (s++; *s; s++) + hash_val = (hash_val << 5) - hash_val + *s; + return hash_val; +} + +bool +pgm_int_equal ( + const void* restrict p1, + const void* restrict p2 + ) +{ + const int i1 = *(const int*restrict)p1, i2 = *(const int*restrict)p2; + return (i1 == i2); +} + +pgm_hash_t +pgm_int_hash ( + const void* p + ) +{ + const int i = *(const int*)p; + return (pgm_hash_t)i; +} + + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/hashtable.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/hashtable.c.c89.patch new file mode 100644 index 0000000..d4d7406 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/hashtable.c.c89.patch @@ -0,0 +1,47 @@ +73a74 +> { +83a85 +> } +93c95,97 +< for (unsigned i = 0; i < hash_table->size; i++) +--- +> { +> unsigned i; +> for (i = 0; i < hash_table->size; i++) +94a99 +> } +140a146 +> { +142a149 +> } +153a161 +> { +155a164 +> } +208c217,219 +< for (unsigned i = 0; i < hash_table->size; i++) +--- +> { +> unsigned i; +> for (i = 0; i < hash_table->size; i++) +212a224 +> } +226,228c238,244 +< +< for (unsigned i = 0; i < hash_table->size; i++) +< for (pgm_hashnode_t *node = hash_table->nodes[i], *next; node; node = next) +--- +> +> { +> unsigned i; +> for (i = 0; i < hash_table->size; i++) +> { +> pgm_hashnode_t *node, *next; +> for (node = hash_table->nodes[i]; node; node = next) +230a247 +> { +233a251,252 +> } +> } +234a254 +> } diff --git a/3rdparty/openpgm-svn-r1135/pgm/histogram.c b/3rdparty/openpgm-svn-r1135/pgm/histogram.c new file mode 100644 index 0000000..3e5ad66 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/histogram.c @@ -0,0 +1,414 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Histograms. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + + +//#define HISTOGRAM_DEBUG + + +pgm_slist_t* pgm_histograms = NULL; + + +static void sample_set_accumulate (pgm_sample_set_t*, pgm_sample_t, pgm_count_t, unsigned); +static pgm_count_t sample_set_total_count (const pgm_sample_set_t*) PGM_GNUC_PURE; + +static void set_bucket_range (pgm_histogram_t*, unsigned, pgm_sample_t); +static void initialize_bucket_range (pgm_histogram_t*); +static unsigned bucket_index (const pgm_histogram_t*, const pgm_sample_t); +static void accumulate (pgm_histogram_t*, pgm_sample_t, pgm_count_t, unsigned); +static double get_peak_bucket_size (const pgm_histogram_t*restrict, const pgm_sample_set_t*restrict); +static double get_bucket_size (const pgm_histogram_t*, const pgm_count_t, const unsigned); + +static void pgm_histogram_write_html_graph (pgm_histogram_t*restrict, pgm_string_t*restrict); +static void write_ascii (pgm_histogram_t*restrict, const char*restrict, pgm_string_t*restrict); +static void write_ascii_header (pgm_histogram_t*restrict, pgm_sample_set_t*restrict, pgm_count_t, pgm_string_t*restrict); +static void write_ascii_bucket_graph (double, double, pgm_string_t*); +static void write_ascii_bucket_context (int64_t, pgm_count_t, int64_t, unsigned, pgm_string_t*); +static void write_ascii_bucket_value (pgm_count_t, double, pgm_string_t*); +static pgm_string_t* get_ascii_bucket_range (pgm_histogram_t*, unsigned); + + +void +pgm_histogram_add ( + pgm_histogram_t* histogram, + int value + ) +{ + if (value > INT_MAX) + value = INT_MAX - 1; + if (value < 0) + value = 0; + const unsigned i = bucket_index (histogram, value); + pgm_assert (value >= histogram->ranges[ i ]); + pgm_assert (value < histogram->ranges[ i + 1 ]); + accumulate (histogram, value, 1, i); +} + +void +pgm_histogram_write_html_graph_all ( + pgm_string_t* string + ) +{ + if (!pgm_histograms) + return; + pgm_slist_t* snapshot = pgm_histograms; + while (snapshot) { + pgm_histogram_t* histogram = snapshot->data; + pgm_histogram_write_html_graph (histogram, string); + snapshot = snapshot->next; + } +} + +static +void +pgm_histogram_write_html_graph ( + pgm_histogram_t* histogram, + pgm_string_t* string + ) +{ + pgm_string_append (string, "
");
+	write_ascii (histogram, "
", string); + pgm_string_append (string, "
"); +} + +static +void +sample_set_accumulate ( + pgm_sample_set_t* sample_set, + pgm_sample_t value, + pgm_count_t count, + unsigned i + ) +{ + pgm_assert (1 == count || -1 == count); + sample_set->counts[ i ] += count; + sample_set->sum += count * value; + sample_set->square_sum += (count * value) * (int64_t)value; + pgm_assert (sample_set->counts[ i ] >= 0); + pgm_assert (sample_set->sum >= 0); + pgm_assert (sample_set->square_sum >= 0); +} + +static +pgm_count_t +sample_set_total_count ( + const pgm_sample_set_t* sample_set + ) +{ + pgm_count_t total = 0; + for (unsigned i = 0; i < sample_set->counts_len; i++) + total += sample_set->counts[ i ]; + return total; +} + +void +pgm_histogram_init ( + pgm_histogram_t* histogram + ) +{ + if (histogram->declared_min <= 0) + histogram->declared_min = 1; + pgm_assert (histogram->declared_min > 0); + histogram->declared_max = INT_MAX - 1; + pgm_assert (histogram->declared_min <= histogram->declared_max); + pgm_assert (1 < histogram->bucket_count); + set_bucket_range (histogram, histogram->bucket_count, INT_MAX); + initialize_bucket_range (histogram); + +/* register with global list */ + histogram->histograms_link.data = histogram; + histogram->histograms_link.next = pgm_histograms; + pgm_histograms = &histogram->histograms_link; + histogram->is_registered = TRUE; +} + +static +void +set_bucket_range ( + pgm_histogram_t* histogram, + unsigned i, + pgm_sample_t value + ) +{ + histogram->ranges[ i ] = value; +} + +static +void +initialize_bucket_range ( + pgm_histogram_t* histogram + ) +{ + const double log_max = log(histogram->declared_max); + double log_ratio; + double log_next; + unsigned i = 1; + pgm_sample_t current = histogram->declared_min; + + set_bucket_range (histogram, i, current); + while (histogram->bucket_count > ++i) { + double log_current = log(current); + log_ratio = (log_max - log_current) / (histogram->bucket_count - i); + log_next = log_current + log_ratio; + int next = floor(exp(log_next) + 0.5); + if (next > current) + current = next; + else + current++; + set_bucket_range (histogram, i, current); + } + pgm_assert (histogram->bucket_count == i); +} + +static +unsigned +bucket_index ( + const pgm_histogram_t* histogram, + const pgm_sample_t value + ) +{ + pgm_assert (histogram->ranges[0] <= value); + pgm_assert (histogram->ranges[ histogram->bucket_count ] > value); + unsigned under = 0; + unsigned over = histogram->bucket_count; + unsigned mid; + + do { + pgm_assert (over >= under); + mid = ((unsigned)under + (unsigned)over) >> 1; + if (mid == under) + break; + if (histogram->ranges[ mid ] <= value) + under = mid; + else + over = mid; + } while (TRUE); + pgm_assert (histogram->ranges[ mid ] <= value && + histogram->ranges[ mid + 1] > value); + return mid; +} + +static +void +accumulate ( + pgm_histogram_t* histogram, + pgm_sample_t value, + pgm_count_t count, + unsigned i + ) +{ + sample_set_accumulate (&histogram->sample, value, count, i); +} + +static +void +write_ascii ( + pgm_histogram_t* restrict histogram, + const char* restrict newline, + pgm_string_t* restrict output + ) +{ + pgm_count_t snapshot_counts[ histogram->sample.counts_len ]; + pgm_sample_set_t snapshot = { + .counts = snapshot_counts, + .counts_len = histogram->sample.counts_len, + .sum = histogram->sample.sum, + .square_sum = histogram->sample.square_sum + }; + memcpy (snapshot_counts, histogram->sample.counts, sizeof(pgm_count_t) * histogram->sample.counts_len); + + pgm_count_t sample_count = sample_set_total_count (&snapshot); + write_ascii_header (histogram, &snapshot, sample_count, output); + pgm_string_append (output, newline); + + double max_size = get_peak_bucket_size (histogram, &snapshot); + unsigned largest_non_empty_bucket = histogram->bucket_count - 1; + while (0 == snapshot.counts[ largest_non_empty_bucket ]) + { + if (0 == largest_non_empty_bucket) + break; + largest_non_empty_bucket--; + } + + int print_width = 1; + for (unsigned i = 0; i < histogram->bucket_count; ++i) + { + if (snapshot.counts[ i ]) { + pgm_string_t* bucket_range = get_ascii_bucket_range (histogram, i); + const int width = bucket_range->len + 1; + pgm_string_free (bucket_range, TRUE); + if (width > print_width) + print_width = width; + } + } + + int64_t remaining = sample_count; + int64_t past = 0; + for (unsigned i = 0; i < histogram->bucket_count; ++i) + { + pgm_count_t current = snapshot.counts[ i ]; + remaining -= current; + pgm_string_t* bucket_range = get_ascii_bucket_range (histogram, i); + pgm_string_append_printf (output, "%*s ", print_width, bucket_range->str); + pgm_string_free (bucket_range, TRUE); + if (0 == current && + i < histogram->bucket_count - 1 && + 0 == snapshot.counts[ i + 1 ]) + { + while (i < histogram->bucket_count - 1 && + 0 == snapshot.counts[ i + 1 ]) + { + i++; + } + pgm_string_append (output, "... "); + pgm_string_append (output, newline); + continue; + } + + const double current_size = get_bucket_size (histogram, current, i); + write_ascii_bucket_graph (current_size, max_size, output); + write_ascii_bucket_context (past, current, remaining, i, output); + pgm_string_append (output, newline); + past += current; + } +} + +static +void +write_ascii_header ( + pgm_histogram_t* restrict histogram, + pgm_sample_set_t* restrict sample_set, + pgm_count_t sample_count, + pgm_string_t* restrict output + ) +{ + pgm_string_append_printf (output, + "Histogram: %s recorded %d samples", + histogram->histogram_name ? histogram->histogram_name : "(null)", + sample_count); + if (sample_count > 0) { + const double average = sample_set->sum / sample_count; + const double variance = sample_set->square_sum / sample_count + - average * average; + const double standard_deviation = sqrt (variance); + pgm_string_append_printf (output, + ", average = %.1f, standard deviation = %.1f", + average, standard_deviation); + } +} + +static +void +write_ascii_bucket_graph ( + double current_size, + double max_size, + pgm_string_t* output + ) +{ + static const int k_line_length = 72; + int x_count = (k_line_length * (current_size / max_size) + 0.5); + int x_remainder = k_line_length - x_count; + while (0 < x_count--) + pgm_string_append_c (output, '-'); + pgm_string_append_c (output, 'O'); + while (0 < x_remainder--) + pgm_string_append_c (output, ' '); +} + +static +void +write_ascii_bucket_context ( + int64_t past, + pgm_count_t current, + int64_t remaining, + unsigned i, + pgm_string_t* output + ) +{ + const double scaled_sum = (past + current + remaining) / 100.0; + write_ascii_bucket_value (current, scaled_sum, output); + if (0 < i) { + const double percentage = past / scaled_sum; + pgm_string_append_printf (output, " {%3.1f%%}", percentage); + } +} + +static +void +write_ascii_bucket_value ( + pgm_count_t current, + double scaled_sum, + pgm_string_t* output + ) +{ + pgm_string_append_printf (output, " (%d = %3.1f%%)", current, current/scaled_sum); +} + +static +double +get_peak_bucket_size ( + const pgm_histogram_t* restrict histogram, + const pgm_sample_set_t* restrict sample_set + ) +{ + double max_size = 0; + for (unsigned i = 0; i < histogram->bucket_count; i++) { + const double current_size = get_bucket_size (histogram, sample_set->counts[ i ], i); + if (current_size > max_size) + max_size = current_size; + } + return max_size; +} + +static +double +get_bucket_size ( + const pgm_histogram_t* histogram, + const pgm_count_t current, + const unsigned i + ) +{ + pgm_assert (histogram->ranges[ i + 1 ] > histogram->ranges[ i ]); + static const double kTransitionWidth = 5; + double denominator = histogram->ranges[ i + 1 ] - histogram->ranges[ i ]; + if (denominator > kTransitionWidth) + denominator = kTransitionWidth; + return current / denominator; +} + +static +pgm_string_t* +get_ascii_bucket_range ( + pgm_histogram_t* histogram, + unsigned i + ) +{ + pgm_string_t* result = pgm_string_new (NULL); + pgm_string_printf (result, "%d", histogram->ranges[ i ]); + return result; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/histogram.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/histogram.c.c89.patch new file mode 100644 index 0000000..a5826fd --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/histogram.c.c89.patch @@ -0,0 +1,212 @@ +--- histogram.c 2010-05-21 11:35:50.000000000 +0800 ++++ histogram.c89 2010-08-04 11:32:46.000000000 +0800 +@@ -61,10 +61,12 @@ + value = INT_MAX - 1; + if (value < 0) + value = 0; ++ { + const unsigned i = bucket_index (histogram, value); + pgm_assert (value >= histogram->ranges[ i ]); + pgm_assert (value < histogram->ranges[ i + 1 ]); + accumulate (histogram, value, 1, i); ++ } + } + + void +@@ -74,12 +76,14 @@ + { + if (!pgm_histograms) + return; ++ { + pgm_slist_t* snapshot = pgm_histograms; + while (snapshot) { + pgm_histogram_t* histogram = snapshot->data; + pgm_histogram_write_html_graph (histogram, string); + snapshot = snapshot->next; + } ++ } + } + + static +@@ -119,8 +123,11 @@ + ) + { + pgm_count_t total = 0; +- for (unsigned i = 0; i < sample_set->counts_len; i++) ++ { ++ unsigned i; ++ for (i = 0; i < sample_set->counts_len; i++) + total += sample_set->counts[ i ]; ++ } + return total; + } + +@@ -173,12 +180,15 @@ + double log_current = log(current); + log_ratio = (log_max - log_current) / (histogram->bucket_count - i); + log_next = log_current + log_ratio; +- int next = floor(exp(log_next) + 0.5); ++ { ++/* force cast to ignore float to int conversion warning */ ++ int next = (int)floor(exp(log_next) + 0.5); + if (next > current) + current = next; + else + current++; + set_bucket_range (histogram, i, current); ++ } + } + pgm_assert (histogram->bucket_count == i); + } +@@ -192,6 +202,7 @@ + { + pgm_assert (histogram->ranges[0] <= value); + pgm_assert (histogram->ranges[ histogram->bucket_count ] > value); ++ { + unsigned under = 0; + unsigned over = histogram->bucket_count; + unsigned mid; +@@ -209,6 +220,7 @@ + pgm_assert (histogram->ranges[ mid ] <= value && + histogram->ranges[ mid + 1] > value); + return mid; ++ } + } + + static +@@ -231,19 +243,21 @@ + pgm_string_t* restrict output + ) + { +- pgm_count_t snapshot_counts[ histogram->sample.counts_len ]; +- pgm_sample_set_t snapshot = { +- .counts = snapshot_counts, +- .counts_len = histogram->sample.counts_len, +- .sum = histogram->sample.sum, +- .square_sum = histogram->sample.square_sum +- }; ++ pgm_count_t* snapshot_counts = pgm_newa (pgm_count_t, histogram->sample.counts_len); ++ pgm_sample_set_t snapshot; ++ snapshot.counts = snapshot_counts; ++ snapshot.counts_len = histogram->sample.counts_len; ++ snapshot.sum = histogram->sample.sum; ++ snapshot.square_sum = histogram->sample.square_sum; ++ + memcpy (snapshot_counts, histogram->sample.counts, sizeof(pgm_count_t) * histogram->sample.counts_len); + ++ { + pgm_count_t sample_count = sample_set_total_count (&snapshot); + write_ascii_header (histogram, &snapshot, sample_count, output); + pgm_string_append (output, newline); + ++ { + double max_size = get_peak_bucket_size (histogram, &snapshot); + unsigned largest_non_empty_bucket = histogram->bucket_count - 1; + while (0 == snapshot.counts[ largest_non_empty_bucket ]) +@@ -253,8 +267,11 @@ + largest_non_empty_bucket--; + } + ++ { + int print_width = 1; +- for (unsigned i = 0; i < histogram->bucket_count; ++i) ++ { ++ unsigned i; ++ for (i = 0; i < histogram->bucket_count; ++i) + { + if (snapshot.counts[ i ]) { + pgm_string_t* bucket_range = get_ascii_bucket_range (histogram, i); +@@ -264,16 +281,22 @@ + print_width = width; + } + } ++ } + ++ { + int64_t remaining = sample_count; + int64_t past = 0; +- for (unsigned i = 0; i < histogram->bucket_count; ++i) ++ { ++ unsigned i; ++ for (i = 0; i < histogram->bucket_count; ++i) + { + pgm_count_t current = snapshot.counts[ i ]; + remaining -= current; ++ { + pgm_string_t* bucket_range = get_ascii_bucket_range (histogram, i); + pgm_string_append_printf (output, "%*s ", print_width, bucket_range->str); + pgm_string_free (bucket_range, TRUE); ++ } + if (0 == current && + i < histogram->bucket_count - 1 && + 0 == snapshot.counts[ i + 1 ]) +@@ -288,12 +311,19 @@ + continue; + } + ++ { + const double current_size = get_bucket_size (histogram, current, i); + write_ascii_bucket_graph (current_size, max_size, output); ++ } + write_ascii_bucket_context (past, current, remaining, i, output); + pgm_string_append (output, newline); + past += current; + } ++ } ++ } ++ } ++ } ++ } + } + + static +@@ -310,8 +340,8 @@ + histogram->histogram_name ? histogram->histogram_name : "(null)", + sample_count); + if (sample_count > 0) { +- const double average = sample_set->sum / sample_count; +- const double variance = sample_set->square_sum / sample_count ++ const double average = (double)sample_set->sum / sample_count; ++ const double variance = (double)sample_set->square_sum / sample_count + - average * average; + const double standard_deviation = sqrt (variance); + pgm_string_append_printf (output, +@@ -329,7 +359,7 @@ + ) + { + static const int k_line_length = 72; +- int x_count = (k_line_length * (current_size / max_size) + 0.5); ++ int x_count = (int)(k_line_length * (current_size / max_size) + 0.5); + int x_remainder = k_line_length - x_count; + while (0 < x_count--) + pgm_string_append_c (output, '-'); +@@ -375,11 +405,14 @@ + ) + { + double max_size = 0; +- for (unsigned i = 0; i < histogram->bucket_count; i++) { ++ { ++ unsigned i; ++ for (i = 0; i < histogram->bucket_count; i++) { + const double current_size = get_bucket_size (histogram, sample_set->counts[ i ], i); + if (current_size > max_size) + max_size = current_size; + } ++ } + return max_size; + } + +@@ -392,11 +425,13 @@ + ) + { + pgm_assert (histogram->ranges[ i + 1 ] > histogram->ranges[ i ]); ++ { + static const double kTransitionWidth = 5; + double denominator = histogram->ranges[ i + 1 ] - histogram->ranges[ i ]; + if (denominator > kTransitionWidth) + denominator = kTransitionWidth; + return current / denominator; ++ } + } + + static diff --git a/3rdparty/openpgm-svn-r1135/pgm/htdocs/404.html b/3rdparty/openpgm-svn-r1135/pgm/htdocs/404.html new file mode 100644 index 0000000..538c90a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/htdocs/404.html @@ -0,0 +1,11 @@ + + + + OpenPGM - Page Not Found + + + +

Lah, page not found.

+

Return to main page

+ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/htdocs/base.css b/3rdparty/openpgm-svn-r1135/pgm/htdocs/base.css new file mode 100644 index 0000000..5aba236 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/htdocs/base.css @@ -0,0 +1,136 @@ +html { + background-color: white; + font-family: Verdana; + font-size: 12px; + color: black; +} + +a, a:link, a:visited { + color: #0033cc; + text-decoration: none; +} + +#header { + text-align: right; +} + +#header #hostname { + font-weight: bold; +} + +#header a { + color: black; +} + +#header a:hover { + text-decoration: underline; +} + +#footer { + clear: both; + margin-top: 3.5em; + margin-bottom: 1em; + padding-top: 20px; + text-align: center; +} + +#navigation a { + color: black; +} + +#navigation .tab { + -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; + padding: 4px 1em 2px; + margin-right: 8px; + float: left; + font-weight: bold; +} + +#navigation #tabtop,#tabline { + background-color: #fb879c; +} + +#navigation #tabbottom { + background-color: #fbc1a9; +} + +#navigation #tabline { + clear: left; + -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; + height: 4px; +} + +#content { + margin-top: 6px; + padding: 3px; +} + +#content a:hover { + background: #ffffaa; +} + +.heading { + -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; + background-color: #fb879c; + padding: 6px; + margin-bottom: 3px; +} + +table { + border-collapse: separate; +} + +th { + text-align: left; +} + +#information { + float: right; +} + +.rounded { + background-color: #fbc1a9; + -moz-border-radius: 4px; -webkit-border-radius: 4px; + padding: 5px; + margin-top: 6px; + margin-bottom: 6px; + width: 25em; +} + +.break { + border-top: 3px solid white; + margin-top: 1em; + padding-top: 6px; +} + +.bubbly { + background-color: #fb879c; + -moz-border-radius: 4px; -webkit-border-radius: 4px; + padding: 4px; +} + +.bubbly table { + width: 100%; +} + +.bubbly th,.bubbly td { + border-bottom: 1px solid #bbbbbb; +} + +.bubbly th { + background-color: #fbc1a9; + border-left: 1px solid #bbbbbb; + padding: 2px 1px 2px 2px; +} + +.bubbly td { + background-color: white; + padding: 4px; +} + +.bubbly .empty { + padding: 3em; + text-align: center; +} diff --git a/3rdparty/openpgm-svn-r1135/pgm/htdocs/convert_to_macro.pl b/3rdparty/openpgm-svn-r1135/pgm/htdocs/convert_to_macro.pl new file mode 100755 index 0000000..bea44af --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/htdocs/convert_to_macro.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl + +use strict; +use File::Basename; + +die "usage: $0 [text file]\n" unless ($ARGV[0]); +open(MOO, $ARGV[0]) or die "cannot open $ARGV[0]: $!"; +my $all = do { local $/; }; +close(MOO); +$all =~ s/"/\\"/g; +$all =~ s/\n/\\n/mg; +$all =~ s/\r/\\r/mg; + +my $var = uc (basename($ARGV[0])); +$var =~ s/\s+/_/g; +$var =~ s/\./_/g; + +print< + + diff --git a/3rdparty/openpgm-svn-r1135/pgm/http.c b/3rdparty/openpgm-svn-r1135/pgm/http.c new file mode 100644 index 0000000..442f6f3 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/http.c @@ -0,0 +1,1735 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * HTTP administrative interface + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#ifndef _WIN32 +# include +#else +# include +# include +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pgm/http.h" +#include "htdocs/404.html.h" +#include "htdocs/base.css.h" +#include "htdocs/robots.txt.h" +#include "htdocs/xhtml10_strict.doctype.h" + + +/* OpenSolaris */ +#ifndef LOGIN_NAME_MAX +# ifdef _WIN32 +# define LOGIN_NAME_MAX (UNLEN + 1) +# else +# define LOGIN_NAME_MAX 256 +# endif +#endif + +#ifdef _WIN32 +# define getpid _getpid +# define read _read +# define write _write +# define SHUT_WR SD_SEND +#endif + +#ifdef CONFIG_HAVE_SPRINTF_GROUPING +# define GROUP_FORMAT "'" +#else +# define GROUP_FORMAT "" +#endif + +#define HTTP_BACKLOG 10 /* connections */ +#define HTTP_TIMEOUT 60 /* seconds */ + + +/* locals */ + +struct http_connection_t { + pgm_list_t link_; + int sock; + enum { + HTTP_STATE_READ, + HTTP_STATE_WRITE, + HTTP_STATE_FINWAIT + } state; + + char* buf; + size_t buflen; + size_t bufoff; + unsigned status_code; + const char* status_text; + const char* content_type; +}; + +enum { + HTTP_MEMORY_STATIC, + HTTP_MEMORY_TAKE +}; + +static char http_hostname[NI_MAXHOST + 1]; +static char http_address[INET6_ADDRSTRLEN]; +static char http_username[LOGIN_NAME_MAX + 1]; +static int http_pid; + +#ifndef _WIN32 +static int http_sock = -1; +static pthread_t http_thread; +static void* http_routine (void*); +#else +static int http_sock = INVALID_SOCKET; +static HANDLE http_thread; +static unsigned __stdcall http_routine (void*); +#endif +static int http_max_sock = -1; +static fd_set http_readfds, http_writefds, http_exceptfds; +static pgm_list_t* http_socks = NULL; +static pgm_notify_t http_notify = PGM_NOTIFY_INIT; +static volatile uint32_t http_ref_count = 0; + + +static int http_tsi_response (struct http_connection_t*, pgm_tsi_t*); +static void http_each_receiver (pgm_peer_t*, pgm_string_t*); +static int http_receiver_response (struct http_connection_t*, pgm_peer_t*); + +static void default_callback (struct http_connection_t*, const char*); +static void robots_callback (struct http_connection_t*, const char*); +static void css_callback (struct http_connection_t*, const char*); +static void index_callback (struct http_connection_t*, const char*); +static void interfaces_callback (struct http_connection_t*, const char*); +static void transports_callback (struct http_connection_t*, const char*); +static void histograms_callback (struct http_connection_t*, const char*); + +static struct { + const char* path; + void (*callback) (struct http_connection_t*, const char*); +} http_directory[] = { + { "/robots.txt", robots_callback }, + { "/base.css", css_callback }, + { "/", index_callback }, + { "/interfaces", interfaces_callback }, + { "/transports", transports_callback } +#ifdef CONFIG_HISTOGRAMS + ,{ "/histograms", histograms_callback } +#endif +}; + + +static +int +http_sock_rcvtimeo ( + int sock, + int seconds + ) +{ +#if defined( sun ) + return 0; +#elif !defined( _WIN32 ) + const struct timeval timeout = { .tv_sec = seconds, .tv_usec = 0 }; + return setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)); +#else + const int optval = seconds * 1000; + return setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&optval, sizeof(optval)); +#endif +} + +static +int +http_sock_sndtimeo ( + int sock, + int seconds + ) +{ +#if defined( sun ) + return 0; +#elif !defined( _WIN32 ) + const struct timeval timeout = { .tv_sec = seconds, .tv_usec = 0 }; + return setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout)); +#else + const int optval = seconds * 1000; + return setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (const char*)&optval, sizeof(optval)); +#endif +} + +bool +pgm_http_init ( + uint16_t http_port, + pgm_error_t** error + ) +{ + int e; + + if (pgm_atomic_exchange_and_add32 (&http_ref_count, 1) > 0) + return TRUE; + +/* resolve and store relatively constant runtime information */ + if (0 != gethostname (http_hostname, sizeof(http_hostname))) { + const int save_errno = errno; + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_errno (save_errno), + _("Resolving hostname: %s"), + strerror (save_errno)); + goto err_cleanup; + } + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP, + .ai_flags = AI_ADDRCONFIG + }, *res = NULL; + e = getaddrinfo (http_hostname, NULL, &hints, &res); + if (0 != e) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_eai_errno (e, errno), + _("Resolving hostname address: %s"), + gai_strerror (e)); + goto err_cleanup; + } + e = getnameinfo (res->ai_addr, res->ai_addrlen, + http_address, sizeof(http_address), + NULL, 0, + NI_NUMERICHOST); + if (0 != e) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_eai_errno (e, errno), + _("Resolving numeric hostname: %s"), + gai_strerror (e)); + goto err_cleanup; + } + freeaddrinfo (res); +#ifndef _WIN32 + e = getlogin_r (http_username, sizeof(http_username)); + if (0 != e) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_errno (errno), + _("Retrieving user name: %s"), + strerror (errno)); + goto err_cleanup; + } +#else + wchar_t wusername[UNLEN + 1]; + DWORD nSize = PGM_N_ELEMENTS( wusername ); + if (!GetUserNameW (wusername, &nSize)) { + const DWORD save_errno = GetLastError(); + char winstr[1024]; + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_win_errno (save_errno), + _("Retrieving user name: %s"), + pgm_win_strerror (winstr, sizeof(winstr), save_errno)); + goto err_cleanup; + } + WideCharToMultiByte (CP_UTF8, 0, wusername, nSize + 1, http_username, sizeof(http_username), NULL, NULL); +#endif /* _WIN32 */ + http_pid = getpid(); + +/* create HTTP listen socket */ + if ((http_sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) { +#ifndef _WIN32 + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_errno (errno), + _("Creating HTTP socket: %s"), + strerror (errno)); +#else + const int save_errno = WSAGetLastError(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_wsa_errno (save_errno), + _("Creating HTTP socket: %s"), + pgm_wsastrerror (save_errno)); +#endif + goto err_cleanup; + } + const int v = 1; + if (0 != setsockopt (http_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&v, sizeof(v))) { +#ifndef _WIN32 + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_errno (errno), + _("Enabling reuse of socket local address: %s"), + strerror (errno)); +#else + const int save_errno = WSAGetLastError(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_wsa_errno (save_errno), + _("Enabling reuse of socket local address: %s"), + pgm_wsastrerror (save_errno)); +#endif + goto err_cleanup; + } + if (0 != http_sock_rcvtimeo (http_sock, HTTP_TIMEOUT) || + 0 != http_sock_sndtimeo (http_sock, HTTP_TIMEOUT)) { +#ifndef _WIN32 + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_errno (errno), + _("Setting socket timeout: %s"), + strerror (errno)); +#else + const int save_errno = WSAGetLastError(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_wsa_errno (save_errno), + _("Setting socket timeout: %s"), + pgm_wsastrerror (save_errno)); +#endif + goto err_cleanup; + } + struct sockaddr_in http_addr; + memset (&http_addr, 0, sizeof(http_addr)); + http_addr.sin_family = AF_INET; + http_addr.sin_addr.s_addr = INADDR_ANY; + http_addr.sin_port = htons (http_port); + if (0 != bind (http_sock, (struct sockaddr*)&http_addr, sizeof(http_addr))) { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&http_addr, addr, sizeof(addr)); +#ifndef _WIN32 + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_errno (errno), + _("Binding HTTP socket to address %s: %s"), + addr, + strerror (errno)); +#else + const int save_errno = WSAGetLastError(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_wsa_errno (save_errno), + _("Binding HTTP socket to address %s: %s"), + addr, + pgm_wsastrerror (save_errno)); +#endif + goto err_cleanup; + } + if (listen (http_sock, HTTP_BACKLOG) < 0) { +#ifndef _WIN32 + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_errno (errno), + _("Listening to HTTP socket: %s"), + strerror (errno)); +#else + const int save_errno = WSAGetLastError(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_wsa_errno (save_errno), + _("Listening to HTTP socket: %s"), + pgm_wsastrerror (save_errno)); +#endif + goto err_cleanup; + } + +/* non-blocking notification of new connections */ + pgm_sockaddr_nonblocking (http_sock, TRUE); + +/* create notification channel */ + if (0 != pgm_notify_init (&http_notify)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_errno (errno), + _("Creating HTTP notification channel: %s"), + strerror (errno)); + goto err_cleanup; + } + +/* spawn thread to handle HTTP requests */ +#ifndef _WIN32 + const int status = pthread_create (&http_thread, NULL, &http_routine, NULL); + if (0 != status) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_errno (errno), + _("Creating HTTP thread: %s"), + strerror (errno)); + goto err_cleanup; + } +#else + http_thread = (HANDLE)_beginthreadex (NULL, 0, &http_routine, NULL, 0, NULL); + const int save_errno = errno; + if (0 == http_thread) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_HTTP, + pgm_error_from_errno (save_errno), + _("Creating HTTP thread: %s"), + strerror (save_errno)); + goto err_cleanup; + } +#endif /* _WIN32 */ + pgm_minor (_("Web interface: http://%s:%i"), + http_hostname, + http_port); + return TRUE; + +err_cleanup: +#ifndef _WIN32 + if (-1 != http_sock) { + close (http_sock); + http_sock = -1; + } +#else + if (INVALID_SOCKET != http_sock) { + closesocket (http_sock); + http_sock = INVALID_SOCKET; + } +#endif /* _WIN32 */ + if (pgm_notify_is_valid (&http_notify)) { + pgm_notify_destroy (&http_notify); + } + pgm_atomic_dec32 (&http_ref_count); + return FALSE; +} + +/* notify HTTP thread to shutdown, wait for shutdown and cleanup. + */ + +bool +pgm_http_shutdown (void) +{ + pgm_return_val_if_fail (pgm_atomic_read32 (&http_ref_count) > 0, FALSE); + + if (pgm_atomic_exchange_and_add32 (&http_ref_count, (uint32_t)-1) != 1) + return TRUE; + + pgm_notify_send (&http_notify); +#ifndef _WIN32 + pthread_join (http_thread, NULL); +#else + CloseHandle (http_thread); +#endif +#ifndef _WIN32 + if (-1 != http_sock) { + close (http_sock); + http_sock = -1; + } +#else + if (INVALID_SOCKET != http_sock) { + closesocket (http_sock); + http_sock = INVALID_SOCKET; + } +#endif /* _WIN32 */ + pgm_notify_destroy (&http_notify); + return TRUE; +} + +/* accept a new incoming HTTP connection. + */ + +static +void +http_accept ( + int listen_sock + ) +{ +/* new connection */ + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + int new_sock = accept (listen_sock, (struct sockaddr*)&addr, &addrlen); + if (-1 == new_sock) { + if (EAGAIN == errno) + return; +#ifndef _WIN32 + pgm_warn (_("HTTP accept: %s"), strerror (errno)); +#else + const int save_errno = WSAGetLastError(); + pgm_warn (_("HTTP accept: %s"), pgm_wsastrerror (save_errno)); +#endif + return; + } + +#ifndef _WIN32 +/* out of bounds file descriptor for select() */ + if (new_sock >= FD_SETSIZE) { + close (new_sock); + pgm_warn (_("Rejected new HTTP client socket due to out of bounds file descriptor.")); + return; + } +#endif + + pgm_sockaddr_nonblocking (new_sock, TRUE); + + struct http_connection_t* connection = pgm_new0 (struct http_connection_t, 1); + connection->sock = new_sock; + connection->state = HTTP_STATE_READ; + http_socks = pgm_list_prepend_link (http_socks, &connection->link_); + FD_SET( new_sock, &http_readfds ); + FD_SET( new_sock, &http_exceptfds ); + if (new_sock > http_max_sock) + http_max_sock = new_sock; +} + +static +void +http_close ( + struct http_connection_t* connection + ) +{ +#ifndef _WIN32 + if (0 != close (connection->sock)) { + pgm_warn (_("Close HTTP client socket: %s"), strerror (errno)); + } +#else + if (0 != closesocket (connection->sock)) { + const int save_errno = WSAGetLastError(); + pgm_warn (_("Close HTTP client socket: %s"), pgm_wsastrerror (save_errno)); + } +#endif + switch (connection->state) { + case HTTP_STATE_READ: + case HTTP_STATE_FINWAIT: + FD_CLR( connection->sock, &http_readfds ); + break; + case HTTP_STATE_WRITE: + FD_CLR( connection->sock, &http_writefds ); + break; + } + FD_CLR( connection->sock, &http_exceptfds ); + http_socks = pgm_list_remove_link (http_socks, &connection->link_); + if (connection->buflen > 0) { + pgm_free (connection->buf); + connection->buf = NULL; + connection->buflen = 0; + } +/* find new highest fd */ + if (connection->sock == http_max_sock) + { + http_max_sock = -1; + for (pgm_list_t* list = http_socks; list; list = list->next) + { + struct http_connection_t* c = (void*)list; + if (c->sock > http_max_sock) + http_max_sock = c->sock; + } + } + pgm_free (connection); +} + +/* non-blocking read an incoming HTTP request + */ + +static +void +http_read ( + struct http_connection_t* connection + ) +{ + for (;;) + { +/* grow buffer as needed */ + if (connection->bufoff + 1024 > connection->buflen) { + connection->buf = pgm_realloc (connection->buf, connection->buflen + 1024); + connection->buflen += 1024; + } + const ssize_t bytes_read = recv (connection->sock, &connection->buf[ connection->bufoff ], connection->buflen - connection->bufoff, 0); + if (bytes_read < 0) { + if (EINTR == errno || EAGAIN == errno) + return; +#ifndef _WIN32 + pgm_warn (_("HTTP client read: %s"), strerror (errno)); +#else + const int save_errno = WSAGetLastError(); + pgm_warn (_("HTTP client read: %s"), pgm_wsastrerror (save_errno)); +#endif + http_close (connection); + return; + } + +/* complete */ + if (strstr (connection->buf, "\r\n\r\n")) + break; + } + +/* process request, e.g. GET /index.html HTTP/1.1\r\n + */ + connection->buf[ connection->buflen - 1 ] = '\0'; + if (0 != memcmp (connection->buf, "GET ", strlen("GET "))) { +/* 501 (not implemented) */ + http_close (connection); + return; + } + + char* request_uri = connection->buf + strlen("GET "); + char* p = request_uri; + do { + if (*p == '?' || *p == ' ') { + *p = '\0'; + break; + } + } while (*(++p)); + + connection->status_code = 200; /* OK */ + connection->status_text = "OK"; + connection->content_type = "text/html"; + connection->bufoff = 0; + for (unsigned i = 0; i < PGM_N_ELEMENTS(http_directory); i++) + { + if (0 == strcmp (request_uri, http_directory[i].path)) + { + http_directory[i].callback (connection, request_uri); + goto complete; + } + } + default_callback (connection, request_uri); + +complete: + connection->state = HTTP_STATE_WRITE; + FD_CLR( connection->sock, &http_readfds ); + FD_SET( connection->sock, &http_writefds ); +} + +/* non-blocking write a HTTP response + */ + +static +void +http_write ( + struct http_connection_t* connection + ) +{ + do { + const ssize_t bytes_written = send (connection->sock, &connection->buf[ connection->bufoff ], connection->buflen - connection->bufoff, 0); + if (bytes_written < 0) { + if (EINTR == errno || EAGAIN == errno) + return; +#ifndef _WIN32 + pgm_warn (_("HTTP client write: %s"), strerror (errno)); +#else + const int save_errno = WSAGetLastError(); + pgm_warn (_("HTTP client write: %s"), pgm_wsastrerror (save_errno)); +#endif + http_close (connection); + return; + } + connection->bufoff += bytes_written; + } while (connection->bufoff < connection->buflen); + + if (0 == shutdown (connection->sock, SHUT_WR)) { + http_close (connection); + } else { + pgm_debug ("HTTP socket entering finwait state."); + connection->state = HTTP_STATE_FINWAIT; + FD_CLR( connection->sock, &http_writefds ); + FD_SET( connection->sock, &http_readfds ); + } +} + +/* read and discard pending data waiting for FIN + */ + +static +void +http_finwait ( + struct http_connection_t* connection + ) +{ + char buf[1024]; + const ssize_t bytes_read = read (connection->sock, buf, sizeof(buf)); + if (bytes_read < 0 && (EINTR == errno || EAGAIN == errno)) + return; + http_close (connection); +} + +static +void +http_process ( + struct http_connection_t* connection + ) +{ + switch (connection->state) { + case HTTP_STATE_READ: http_read (connection); break; + case HTTP_STATE_WRITE: http_write (connection); break; + case HTTP_STATE_FINWAIT: http_finwait (connection); break; + } +} + +static +void +http_set_status ( + struct http_connection_t* connection, + int status_code, + const char* status_text + ) +{ + connection->status_code = status_code; + connection->status_text = status_text; +} + +static +void +http_set_content_type ( + struct http_connection_t* connection, + const char* content_type + ) +{ + connection->content_type = content_type; +} + +/* finalise response buffer with headers and content */ + +static +void +http_set_static_response ( + struct http_connection_t* connection, + const char* content, + size_t content_length + ) +{ + pgm_string_t* response = pgm_string_new (NULL); + pgm_string_printf (response, "HTTP/1.0 %d %s\r\n" + "Server: OpenPGM HTTP Server %u.%u.%u\r\n" + "Last-Modified: Fri, 1 Jan 2010, 00:00:01 GMT\r\n" +#ifndef _MSC_VER + "Content-Length: %zd\r\n" +#else + "Content-Length: %d\r\n" +#endif + "Content-Type: %s\r\n" + "Connection: close\r\n" + "\r\n", + connection->status_code, + connection->status_text, + pgm_major_version, pgm_minor_version, pgm_micro_version, +#ifndef _MSC_VER + content_length, +#else + (int)content_length, +#endif + connection->content_type + ); + pgm_string_append (response, content); + if (connection->buflen) + pgm_free (connection->buf); + connection->buflen = response->len; + connection->buf = pgm_string_free (response, FALSE); +} + +static +void +http_set_response ( + struct http_connection_t* connection, + char* content, + size_t content_length + ) +{ + pgm_string_t* response = pgm_string_new (NULL); + pgm_string_printf (response, "HTTP/1.0 %d %s\r\n" + "Server: OpenPGM HTTP Server %u.%u.%u\r\n" +#ifndef _MSC_VER + "Content-Length: %zd\r\n" +#else + "Content-Length: %d\r\n" +#endif + "Content-Type: %s\r\n" + "Connection: close\r\n" + "\r\n", + connection->status_code, + connection->status_text, + pgm_major_version, pgm_minor_version, pgm_micro_version, +#ifndef _MSC_VER + content_length, +#else + (int)content_length, +#endif + connection->content_type + ); + pgm_string_append (response, content); + pgm_free (content); + if (connection->buflen) + pgm_free (connection->buf); + connection->buflen = response->len; + connection->buf = pgm_string_free (response, FALSE); +} + +/* Thread routine for processing HTTP requests + */ + +static +#ifndef _WIN32 +void* +#else +unsigned +__stdcall +#endif +http_routine ( + PGM_GNUC_UNUSED void* arg + ) +{ + const int notify_fd = pgm_notify_get_fd (&http_notify); + const int max_fd = MAX( notify_fd, http_sock ); + + FD_ZERO( &http_readfds ); + FD_ZERO( &http_writefds ); + FD_ZERO( &http_exceptfds ); + FD_SET( notify_fd, &http_readfds ); + FD_SET( http_sock, &http_readfds ); + + for (;;) + { + int fds = MAX( http_max_sock, max_fd ) + 1; + fd_set readfds = http_readfds, writefds = http_writefds, exceptfds = http_exceptfds; + + fds = select (fds, &readfds, &writefds, &exceptfds, NULL); +/* signal interrupt */ + if (PGM_UNLIKELY(fds < 0 && EINTR == errno)) + continue; +/* terminate */ + if (PGM_UNLIKELY(FD_ISSET( notify_fd, &readfds ))) + break; +/* new connection */ + if (FD_ISSET( http_sock, &readfds )) { + http_accept (http_sock); + continue; + } +/* existing connection */ + for (pgm_list_t* list = http_socks; list;) + { + struct http_connection_t* c = (void*)list; + list = list->next; + if ((FD_ISSET( c->sock, &readfds ) && HTTP_STATE_READ == c->state) || + (FD_ISSET( c->sock, &writefds ) && HTTP_STATE_WRITE == c->state) || + (FD_ISSET( c->sock, &exceptfds ))) + { + http_process (c); + } + } + } + +/* cleanup */ +#ifndef _WIN32 + return NULL; +#else + _endthread(); + return 0; +#endif /* WIN32 */ +} + +/* add xhtml doctype and head, populate with runtime values + */ + +typedef enum { + HTTP_TAB_GENERAL_INFORMATION, + HTTP_TAB_INTERFACES, + HTTP_TAB_TRANSPORTS, + HTTP_TAB_HISTOGRAMS +} http_tab_e; + +static +pgm_string_t* +http_create_response ( + const char* subtitle, + http_tab_e tab + ) +{ + pgm_assert (NULL != subtitle); + pgm_assert (tab == HTTP_TAB_GENERAL_INFORMATION || + tab == HTTP_TAB_INTERFACES || + tab == HTTP_TAB_TRANSPORTS || + tab == HTTP_TAB_HISTOGRAMS); + +/* surprising deficiency of GLib is no support of display locale time */ + char timestamp[100]; + time_t now; + time (&now); + const struct tm* time_ptr = localtime (&now); +#ifndef _WIN32 + strftime (timestamp, sizeof(timestamp), "%c", time_ptr); +#else + wchar_t wtimestamp[100]; + const size_t slen = strftime (timestamp, sizeof(timestamp), "%c", time_ptr); + const size_t wslen = MultiByteToWideChar (CP_ACP, 0, timestamp, slen, wtimestamp, 100); + WideCharToMultiByte (CP_UTF8, 0, wtimestamp, wslen + 1, timestamp, sizeof(timestamp), NULL, NULL); +#endif + + pgm_string_t* response = pgm_string_new (WWW_XHTML10_STRICT_DOCTYPE); + pgm_string_append_printf (response, "\n" + "%s - %s" + "" + "\n" + "" + "
" + "%s" + " | OpenPGM %u.%u.%u" + " | %s" + "
" + "
" + "General Information" + "Interfaces" + "Transports" +#ifdef CONFIG_HISTOGRAMS + "Histograms" +#endif + "
" + "
" + "
", + http_hostname, + subtitle, + http_hostname, + pgm_major_version, pgm_minor_version, pgm_micro_version, + timestamp, + tab == HTTP_TAB_GENERAL_INFORMATION ? "top" : "bottom", + tab == HTTP_TAB_INTERFACES ? "top" : "bottom", + tab == HTTP_TAB_TRANSPORTS ? "top" : "bottom" +#ifdef CONFIG_HISTOGRAMS + ,tab == HTTP_TAB_HISTOGRAMS ? "top" : "bottom" +#endif + ); + + return response; +} + +static +void +http_finalize_response ( + struct http_connection_t* connection, + pgm_string_t* response + ) +{ + pgm_string_append (response, "
" + "
" + "©2010 Miru" + "
" + "\n" + ""); + + char* buf = pgm_string_free (response, FALSE); + http_set_response (connection, buf, strlen (buf)); +} + +static +void +robots_callback ( + struct http_connection_t* connection, + PGM_GNUC_UNUSED const char* path + ) +{ + http_set_content_type (connection, "text/plain"); + http_set_static_response (connection, WWW_ROBOTS_TXT, strlen(WWW_ROBOTS_TXT)); +} + +static +void +css_callback ( + struct http_connection_t* connection, + PGM_GNUC_UNUSED const char* path + ) +{ + http_set_content_type (connection, "text/css"); + http_set_static_response (connection, WWW_BASE_CSS, strlen(WWW_BASE_CSS)); +} + +static +void +index_callback ( + struct http_connection_t* connection, + const char* path + ) +{ + if (strlen (path) > 1) { + default_callback (connection, path); + return; + } + pgm_rwlock_reader_lock (&pgm_sock_list_lock); + const unsigned transport_count = pgm_slist_length (pgm_sock_list); + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + + pgm_string_t* response = http_create_response ("OpenPGM", HTTP_TAB_GENERAL_INFORMATION); + pgm_string_append_printf (response, "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
host name:%s
user name:%s
IP address:%s
transports:%i
process ID:%i
\n", + http_hostname, + http_username, + http_address, + transport_count, + http_pid); + http_finalize_response (connection, response); +} + +static +void +interfaces_callback ( + struct http_connection_t* connection, + PGM_GNUC_UNUSED const char* path + ) +{ + pgm_string_t* response = http_create_response ("Interfaces", HTTP_TAB_INTERFACES); + pgm_string_append (response, "
");
+	struct pgm_ifaddrs_t *ifap, *ifa;
+	pgm_error_t* err = NULL;
+	if (!pgm_getifaddrs (&ifap, &err)) {
+		pgm_string_append_printf (response, "pgm_getifaddrs(): %s", (err && err->message) ? err->message : "(null)");
+		http_finalize_response (connection, response);
+		return;
+	}
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next)
+	{
+		int i = NULL == ifa->ifa_addr ? 0 : pgm_if_nametoindex (ifa->ifa_addr->sa_family, ifa->ifa_name);
+		char rname[IF_NAMESIZE * 2 + 3];
+		char b[IF_NAMESIZE * 2 + 3];
+
+		pgm_if_indextoname (i, rname);
+		sprintf (b, "%s (%s)", ifa->ifa_name, rname);
+
+		 if (NULL == ifa->ifa_addr ||
+		      (ifa->ifa_addr->sa_family != AF_INET &&
+		       ifa->ifa_addr->sa_family != AF_INET6) )
+		{
+			pgm_string_append_printf (response,
+				"#%d name %-15.15s ---- %-46.46s scope 0 status %s loop %s b/c %s m/c %s
\n", + i, + b, + "", + ifa->ifa_flags & IFF_UP ? "UP " : "DOWN", + ifa->ifa_flags & IFF_LOOPBACK ? "YES" : "NO ", + ifa->ifa_flags & IFF_BROADCAST ? "YES" : "NO ", + ifa->ifa_flags & IFF_MULTICAST ? "YES" : "NO " + ); + continue; + } + + char s[INET6_ADDRSTRLEN]; + getnameinfo (ifa->ifa_addr, pgm_sockaddr_len(ifa->ifa_addr), + s, sizeof(s), + NULL, 0, + NI_NUMERICHOST); + pgm_string_append_printf (response, + "#%d name %-15.15s IPv%i %-46.46s scope %u status %s loop %s b/c %s m/c %s
\n", + i, + b, + ifa->ifa_addr->sa_family == AF_INET ? 4 : 6, + s, + (unsigned)pgm_sockaddr_scope_id(ifa->ifa_addr), + ifa->ifa_flags & IFF_UP ? "UP " : "DOWN", + ifa->ifa_flags & IFF_LOOPBACK ? "YES" : "NO ", + ifa->ifa_flags & IFF_BROADCAST ? "YES" : "NO ", + ifa->ifa_flags & IFF_MULTICAST ? "YES" : "NO " + ); + } + pgm_freeifaddrs (ifap); + pgm_string_append (response, "
\n"); + http_finalize_response (connection, response); +} + +static +void +transports_callback ( + struct http_connection_t* connection, + PGM_GNUC_UNUSED const char* path + ) +{ + pgm_string_t* response = http_create_response ("Transports", HTTP_TAB_TRANSPORTS); + pgm_string_append (response, "
" + "\n" + "" + "" + "" + "" + "" + "" + ); + + if (pgm_sock_list) + { + pgm_rwlock_reader_lock (&pgm_sock_list_lock); + + pgm_slist_t* list = pgm_sock_list; + while (list) + { + pgm_slist_t* next = list->next; + pgm_sock_t* sock = list->data; + + char group_address[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&sock->send_gsr.gsr_group, pgm_sockaddr_len ((struct sockaddr*)&sock->send_gsr.gsr_group), + group_address, sizeof(group_address), + NULL, 0, + NI_NUMERICHOST); + char gsi[ PGM_GSISTRLEN ]; + pgm_gsi_print_r (&sock->tsi.gsi, gsi, sizeof(gsi)); + const uint16_t sport = ntohs (sock->tsi.sport); + const uint16_t dport = ntohs (sock->dport); + pgm_string_append_printf (response, "" + "" + "" + "" + "" + "", + group_address, + dport, + gsi, sport, + gsi, + gsi, sport, + sport); + list = next; + } + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + } + else + { +/* no transports */ + pgm_string_append (response, "" + "" + "" + ); + } + + pgm_string_append (response, "
Group addressDest portSource GSISource port
%s%i%s%u
This transport has no peers.
\n" + "
"); + http_finalize_response (connection, response); +} + +static +void +histograms_callback ( + struct http_connection_t* connection, + PGM_GNUC_UNUSED const char* path + ) +{ + pgm_string_t* response = http_create_response ("Histograms", HTTP_TAB_HISTOGRAMS); + pgm_histogram_write_html_graph_all (response); + http_finalize_response (connection, response); +} + +static +void +default_callback ( + struct http_connection_t* connection, + const char* path + ) +{ + pgm_tsi_t tsi; + const int count = sscanf (path, "/%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hu", + (unsigned char*)&tsi.gsi.identifier[0], + (unsigned char*)&tsi.gsi.identifier[1], + (unsigned char*)&tsi.gsi.identifier[2], + (unsigned char*)&tsi.gsi.identifier[3], + (unsigned char*)&tsi.gsi.identifier[4], + (unsigned char*)&tsi.gsi.identifier[5], + &tsi.sport); + tsi.sport = htons (tsi.sport); + if (count == 7) + { + int retval = http_tsi_response (connection, &tsi); + if (!retval) return; + } + + http_set_status (connection, 404, "Not Found"); + http_set_static_response (connection, WWW_404_HTML, strlen(WWW_404_HTML)); +} + +static +int +http_tsi_response ( + struct http_connection_t* connection, + pgm_tsi_t* tsi + ) +{ +/* first verify this is a valid TSI */ + pgm_rwlock_reader_lock (&pgm_sock_list_lock); + + pgm_sock_t* sock = NULL; + pgm_slist_t* list = pgm_sock_list; + while (list) + { + pgm_sock_t* list_sock = (pgm_sock_t*)list->data; + pgm_slist_t* next = list->next; + +/* check source */ + if (pgm_tsi_equal (tsi, &list_sock->tsi)) + { + sock = list_sock; + break; + } + +/* check receivers */ + pgm_rwlock_reader_lock (&list_sock->peers_lock); + pgm_peer_t* receiver = pgm_hashtable_lookup (list_sock->peers_hashtable, tsi); + if (receiver) { + int retval = http_receiver_response (connection, receiver); + pgm_rwlock_reader_unlock (&list_sock->peers_lock); + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + return retval; + } + pgm_rwlock_reader_unlock (&list_sock->peers_lock); + + list = next; + } + + if (!sock) { + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + return -1; + } + +/* transport now contains valid matching TSI */ + char gsi[ PGM_GSISTRLEN ]; + pgm_gsi_print_r (&sock->tsi.gsi, gsi, sizeof(gsi)); + + char title[ sizeof("Transport .00000") + PGM_GSISTRLEN ]; + sprintf (title, "Transport %s.%hu", + gsi, + ntohs (sock->tsi.sport)); + + char source_address[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&sock->send_gsr.gsr_source, pgm_sockaddr_len ((struct sockaddr*)&sock->send_gsr.gsr_source), + source_address, sizeof(source_address), + NULL, 0, + NI_NUMERICHOST); + + char group_address[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&sock->send_gsr.gsr_group, pgm_sockaddr_len ((struct sockaddr*)&sock->send_gsr.gsr_group), + group_address, sizeof(group_address), + NULL, 0, + NI_NUMERICHOST); + + const uint16_t dport = ntohs (sock->dport); + const uint16_t sport = ntohs (sock->tsi.sport); + + const pgm_time_t ihb_min = sock->spm_heartbeat_len ? sock->spm_heartbeat_interval[ 1 ] : 0; + const pgm_time_t ihb_max = sock->spm_heartbeat_len ? sock->spm_heartbeat_interval[ sock->spm_heartbeat_len - 1 ] : 0; + + char spm_path[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&sock->recv_gsr[0].gsr_source, pgm_sockaddr_len ((struct sockaddr*)&sock->recv_gsr[0].gsr_source), + spm_path, sizeof(spm_path), + NULL, 0, + NI_NUMERICHOST); + + pgm_string_t* response = http_create_response (title, HTTP_TAB_TRANSPORTS); + pgm_string_append_printf (response, "
" + "Transport: " + "%s.%hu" + "
", + gsi, sport); + +/* peers */ + + pgm_string_append (response, "
" + "\n" + "" + "" + "" + "" + "" + "" + "" + "" + ); + + if (sock->peers_list) + { + pgm_rwlock_reader_lock (&sock->peers_lock); + pgm_list_t* peers_list = sock->peers_list; + while (peers_list) { + pgm_list_t* next = peers_list->next; + http_each_receiver (peers_list->data, response); + peers_list = next; + } + pgm_rwlock_reader_unlock (&sock->peers_lock); + } + else + { +/* no peers */ + + pgm_string_append (response, "" + "" + "" + ); + + } + + pgm_string_append (response, "
Group addressDest portSource addressLast hopSource GSISource port
This transport has no peers.
\n" + "
"); + +/* source and configuration information */ + + pgm_string_append_printf (response, "
" + "\n" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "", + source_address, + group_address, + dport, + gsi, + sport); + +/* continue with source information */ + + pgm_string_append_printf (response, "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
Source address%s
Group address%s
Dest port%u
Source GSI%s
Source port%u
Ttl%u
Adv Mode%s
Late joindisable(2)
TXW_MAX_RTE%" GROUP_FORMAT "zd
TXW_SECS%" GROUP_FORMAT "u
TXW_ADV_SECS0
Ambient SPM interval%" GROUP_FORMAT PGM_TIME_FORMAT " ms
IHB_MIN%" GROUP_FORMAT PGM_TIME_FORMAT " ms
IHB_MAX%" GROUP_FORMAT PGM_TIME_FORMAT " ms
NAK_BO_IVL%" GROUP_FORMAT PGM_TIME_FORMAT " ms
FECdisabled(1)
Source Path Address%s
\n" + "
", + sock->hops, + 0 == sock->adv_mode ? "time(0)" : "data(1)", + sock->txw_max_rte, + sock->txw_secs, + pgm_to_msecs(sock->spm_ambient_interval), + ihb_min, + ihb_max, + pgm_to_msecs(sock->nak_bo_ivl), + spm_path); + +/* performance information */ + + const pgm_txw_t* window = sock->window; + pgm_string_append_printf (response, "\n

Performance information

" + "\n" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
Data bytes sent%" GROUP_FORMAT PRIu32 "
Data packets sent%" GROUP_FORMAT PRIu32 "
Bytes buffered%" GROUP_FORMAT PRIu32 "
Packets buffered%" GROUP_FORMAT PRIu32 "
Bytes sent%" GROUP_FORMAT PRIu32 "
Raw NAKs received%" GROUP_FORMAT PRIu32 "
Checksum errors%" GROUP_FORMAT PRIu32 "
Malformed NAKs%" GROUP_FORMAT PRIu32 "
Packets discarded%" GROUP_FORMAT PRIu32 "
Bytes retransmitted%" GROUP_FORMAT PRIu32 "
Packets retransmitted%" GROUP_FORMAT PRIu32 "
NAKs received%" GROUP_FORMAT PRIu32 "
NAKs ignored%" GROUP_FORMAT PRIu32 "
Transmission rate%" GROUP_FORMAT PRIu32 " bps
NNAK packets received%" GROUP_FORMAT PRIu32 "
NNAKs received%" GROUP_FORMAT PRIu32 "
Malformed NNAKs%" GROUP_FORMAT PRIu32 "
\n", + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT], + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT], + window ? pgm_txw_size (window) : 0, /* minus IP & any UDP header */ + window ? pgm_txw_length (window) : 0, + sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED], + sock->cumulative_stats[PGM_PC_SOURCE_CKSUM_ERRORS], + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS], + sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED], + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED], + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED], + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED], + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_IGNORED], + sock->cumulative_stats[PGM_PC_SOURCE_TRANSMISSION_CURRENT_RATE], + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED], + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED], + sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]); + + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + http_finalize_response (connection, response); + return 0; +} + +static +void +http_each_receiver ( + pgm_peer_t* peer, + pgm_string_t* response + ) +{ + char group_address[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&peer->group_nla, pgm_sockaddr_len ((struct sockaddr*)&peer->group_nla), + group_address, sizeof(group_address), + NULL, 0, + NI_NUMERICHOST); + + char source_address[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&peer->nla, pgm_sockaddr_len ((struct sockaddr*)&peer->nla), + source_address, sizeof(source_address), + NULL, 0, + NI_NUMERICHOST); + + char last_hop[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&peer->local_nla, pgm_sockaddr_len ((struct sockaddr*)&peer->local_nla), + last_hop, sizeof(last_hop), + NULL, 0, + NI_NUMERICHOST); + + char gsi[ PGM_GSISTRLEN + sizeof(".00000") ]; + pgm_gsi_print_r (&peer->tsi.gsi, gsi, sizeof(gsi)); + + const int sport = ntohs (peer->tsi.sport); + const int dport = ntohs (peer->sock->dport); /* by definition must be the same */ + pgm_string_append_printf (response, "" + "%s" + "%u" + "%s" + "%s" + "%s" + "%u" + "", + group_address, + dport, + source_address, + last_hop, + gsi, sport, gsi, + gsi, sport, sport + ); +} + +static +int +http_time_summary ( + const time_t* activity_time, + char* sz + ) +{ + time_t now_time = time (NULL); + + if (*activity_time > now_time) { + return sprintf (sz, "clock skew"); + } + + struct tm* activity_tm = localtime (activity_time); + + now_time -= *activity_time; + + if (now_time < (24 * 60 * 60)) + { + char hourmin[6]; + strftime (hourmin, sizeof(hourmin), "%H:%M", activity_tm); + + if (now_time < 60) { + return sprintf (sz, "%s (%li second%s ago)", + hourmin, now_time, now_time > 1 ? "s" : ""); + } + now_time /= 60; + if (now_time < 60) { + return sprintf (sz, "%s (%li minute%s ago)", + hourmin, now_time, now_time > 1 ? "s" : ""); + } + now_time /= 60; + return sprintf (sz, "%s (%li hour%s ago)", + hourmin, now_time, now_time > 1 ? "s" : ""); + } + else + { + char daymonth[32]; +#ifndef _WIN32 + strftime (daymonth, sizeof(daymonth), "%d %b", activity_tm); +#else + wchar_t wdaymonth[32]; + const size_t slen = strftime (daymonth, sizeof(daymonth), "%d %b", &activity_tm); + const size_t wslen = MultiByteToWideChar (CP_ACP, 0, daymonth, slen, wdaymonth, 32); + WideCharToMultiByte (CP_UTF8, 0, wdaymonth, wslen + 1, daymonth, sizeof(daymonth), NULL, NULL); +#endif + now_time /= 24; + if (now_time < 14) { + return sprintf (sz, "%s (%li day%s ago)", + daymonth, now_time, now_time > 1 ? "s" : ""); + } else { + return sprintf (sz, "%s", daymonth); + } + } +} + +static +int +http_receiver_response ( + struct http_connection_t* connection, + pgm_peer_t* peer + ) +{ + char gsi[ PGM_GSISTRLEN ]; + pgm_gsi_print_r (&peer->tsi.gsi, gsi, sizeof(gsi)); + char title[ sizeof("Peer .00000") + PGM_GSISTRLEN ]; + sprintf (title, "Peer %s.%u", + gsi, + ntohs (peer->tsi.sport)); + + char group_address[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&peer->group_nla, pgm_sockaddr_len ((struct sockaddr*)&peer->group_nla), + group_address, sizeof(group_address), + NULL, 0, + NI_NUMERICHOST); + + char source_address[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&peer->nla, pgm_sockaddr_len ((struct sockaddr*)&peer->nla), + source_address, sizeof(source_address), + NULL, 0, + NI_NUMERICHOST); + + char last_hop[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&peer->local_nla, pgm_sockaddr_len ((struct sockaddr*)&peer->local_nla), + last_hop, sizeof(last_hop), + NULL, 0, + NI_NUMERICHOST); + + const uint16_t sport = ntohs (peer->tsi.sport); + const uint16_t dport = ntohs (peer->sock->dport); /* by definition must be the same */ + const pgm_rxw_t* window = peer->window; + const uint32_t outstanding_naks = window->nak_backoff_queue.length + + window->wait_ncf_queue.length + + window->wait_data_queue.length; + + time_t last_activity_time; + pgm_time_since_epoch (&peer->last_packet, &last_activity_time); + + char last_activity[100]; + http_time_summary (&last_activity_time, last_activity); + + pgm_string_t* response = http_create_response (title, HTTP_TAB_TRANSPORTS); + pgm_string_append_printf (response, "
" + "Peer: " + "%s.%u" + "
", + gsi, sport); + + +/* peer information */ + pgm_string_append_printf (response, "
" + "\n" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "", + group_address, + dport, + source_address, + last_hop, + gsi, + sport); + + pgm_string_append_printf (response, "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
Group address%s
Dest port%u
Source address%s
Last hop%s
Source GSI%s
Source port%u
NAK_BO_IVL%" GROUP_FORMAT PGM_TIME_FORMAT " ms
NAK_RPT_IVL%" GROUP_FORMAT PGM_TIME_FORMAT " ms
NAK_NCF_RETRIES%" GROUP_FORMAT "u
NAK_RDATA_IVL%" GROUP_FORMAT PGM_TIME_FORMAT " ms
NAK_DATA_RETRIES%" GROUP_FORMAT "u
Send NAKsenabled(1)
Late joindisabled(2)
NAK TTL%u
Delivery orderordered(2)
Multicast NAKsdisabled(2)
\n" + "
", + pgm_to_msecs(peer->sock->nak_bo_ivl), + pgm_to_msecs(peer->sock->nak_rpt_ivl), + peer->sock->nak_ncf_retries, + pgm_to_msecs(peer->sock->nak_rdata_ivl), + peer->sock->nak_data_retries, + peer->sock->hops); + + pgm_string_append_printf (response, "\n

Performance information

" + "\n" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" /* detected missed packets */ + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
Data bytes received%" GROUP_FORMAT PRIu32 "
Data packets received%" GROUP_FORMAT PRIu32 "
NAK failures%" GROUP_FORMAT PRIu32 "
Bytes received%" GROUP_FORMAT PRIu32 "
Checksum errors%" GROUP_FORMAT PRIu32 "
Malformed SPMs%" GROUP_FORMAT PRIu32 "
Malformed ODATA%" GROUP_FORMAT PRIu32 "
Malformed RDATA%" GROUP_FORMAT PRIu32 "
Malformed NCFs%" GROUP_FORMAT PRIu32 "
Packets discarded%" GROUP_FORMAT PRIu32 "
Losses%" GROUP_FORMAT PRIu32 "
Bytes delivered to app%" GROUP_FORMAT PRIu32 "
Packets delivered to app%" GROUP_FORMAT PRIu32 "
Duplicate SPMs%" GROUP_FORMAT PRIu32 "
Duplicate ODATA/RDATA%" GROUP_FORMAT PRIu32 "
NAK packets sent%" GROUP_FORMAT PRIu32 "
NAKs sent%" GROUP_FORMAT PRIu32 "
NAKs retransmitted%" GROUP_FORMAT PRIu32 "
NAKs failed%" GROUP_FORMAT PRIu32 "
NAKs failed due to RXW advance%" GROUP_FORMAT PRIu32 "
NAKs failed due to NCF retries%" GROUP_FORMAT PRIu32 "
NAKs failed due to DATA retries%" GROUP_FORMAT PRIu32 "
NAK failures delivered to app%" GROUP_FORMAT PRIu32 "
NAKs suppressed%" GROUP_FORMAT PRIu32 "
Malformed NAKs%" GROUP_FORMAT PRIu32 "
Outstanding NAKs%" GROUP_FORMAT PRIu32 "
Last activity%s
NAK repair min time%" GROUP_FORMAT PRIu32 " μs
NAK repair mean time%" GROUP_FORMAT PRIu32 " μs
NAK repair max time%" GROUP_FORMAT PRIu32 " μs
NAK fail min time%" GROUP_FORMAT PRIu32 " μs
NAK fail mean time%" GROUP_FORMAT PRIu32 " μs
NAK fail max time%" GROUP_FORMAT PRIu32 " μs
NAK min retransmit count%" GROUP_FORMAT PRIu32 "
NAK mean retransmit count%" GROUP_FORMAT PRIu32 "
NAK max retransmit count%" GROUP_FORMAT PRIu32 "
\n", + peer->cumulative_stats[PGM_PC_RECEIVER_DATA_BYTES_RECEIVED], + peer->cumulative_stats[PGM_PC_RECEIVER_DATA_MSGS_RECEIVED], + peer->cumulative_stats[PGM_PC_RECEIVER_NAK_FAILURES], + peer->cumulative_stats[PGM_PC_RECEIVER_BYTES_RECEIVED], + peer->sock->cumulative_stats[PGM_PC_SOURCE_CKSUM_ERRORS], + peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS], + peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_ODATA], + peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_RDATA], + peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS], + peer->cumulative_stats[PGM_PC_RECEIVER_PACKETS_DISCARDED], + window->cumulative_losses, + window->bytes_delivered, + window->msgs_delivered, + peer->cumulative_stats[PGM_PC_RECEIVER_DUP_SPMS], + peer->cumulative_stats[PGM_PC_RECEIVER_DUP_DATAS], + peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT], + peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT], + peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_RETRANSMITTED], + peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_FAILED], + peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_RXW_ADVANCED], + peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_NCF_RETRIES_EXCEEDED], + peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_DATA_RETRIES_EXCEEDED], + peer->cumulative_stats[PGM_PC_RECEIVER_NAK_FAILURES_DELIVERED], + peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED], + peer->cumulative_stats[PGM_PC_RECEIVER_NAK_ERRORS], + outstanding_naks, + last_activity, + window->min_fill_time, + peer->cumulative_stats[PGM_PC_RECEIVER_NAK_SVC_TIME_MEAN], + window->max_fill_time, + peer->min_fail_time, + peer->cumulative_stats[PGM_PC_RECEIVER_NAK_FAIL_TIME_MEAN], + peer->max_fail_time, + window->min_nak_transmit_count, + peer->cumulative_stats[PGM_PC_RECEIVER_TRANSMIT_MEAN], + window->max_nak_transmit_count); + http_finalize_response (connection, response); + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/http_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/http_unittest.c new file mode 100644 index 0000000..32ba11b --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/http_unittest.c @@ -0,0 +1,186 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for the HTTP administration interface. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include + +#include "pgm/transport.h" + + +/* mock state */ +static const guint mock_pgm_major_version = 0; +static const guint mock_pgm_minor_version = 0; +static const guint mock_pgm_micro_version = 0; +static GStaticRWLock mock_pgm_transport_list_lock = G_STATIC_RW_LOCK_INIT; +static GSList* mock_pgm_transport_list = NULL; + +static +gboolean +mock_pgm_tsi_equal ( + gconstpointer v1, + gconstpointer v2 + ) +{ + return memcmp (v1, v2, sizeof(struct pgm_tsi_t)) == 0; +} + +static +void +mock_pgm_time_since_epoch ( + pgm_time_t* pgm_time_t_time, + time_t* time_t_time + ) +{ + *time_t_time = pgm_to_secs (*pgm_time_t_time + 0); +} + +static +void +mock_pgm_histogram_write_html_graph_all + ( + GString* string + ) +{ +} + + +/* mock functions for external references */ + +#define pgm_major_version mock_pgm_major_version +#define pgm_minor_version mock_pgm_minor_version +#define pgm_micro_version mock_pgm_micro_version +#define pgm_transport_list_lock mock_pgm_transport_list_lock +#define pgm_transport_list mock_pgm_transport_list +#define pgm_tsi_equal mock_pgm_tsi_equal +#define pgm_time_since_epoch mock_pgm_time_since_epoch +#define pgm_histogram_write_html_graph_all mock_pgm_histogram_write_html_graph_all + +#define HTTP_DEBUG +#include "http.c" + + +/* target: + * gboolean + * pgm_http_init ( + * guint16* http_port, + * GError** error + * ) + */ + +START_TEST (test_init_pass_001) +{ + GError* err = NULL; + fail_unless (TRUE == pgm_http_init (8080, &err)); + fail_unless (NULL == err); +} +END_TEST + +/* duplicate servers */ +START_TEST (test_init_fail_001) +{ + GError* err = NULL; + fail_unless (TRUE == pgm_http_init (8080, &err)); + fail_unless (FALSE == pgm_http_init (8080, &err)); +} +END_TEST + +/* target: + * gboolean + * pgm_http_shutdown (void) + */ + +START_TEST (test_shutdown_pass_001) +{ + GError* err = NULL; + fail_unless (TRUE == pgm_http_init (8080, &err)); + fail_unless (NULL == err); + fail_unless (TRUE == pgm_http_shutdown ()); +} +END_TEST + +/* repeatability + */ +START_TEST (test_shutdown_pass_002) +{ + GError* err = NULL; + fail_unless (TRUE == pgm_http_init (8080, &err)); + fail_unless (NULL == err); + fail_unless (TRUE == pgm_http_shutdown ()); + fail_unless (TRUE == pgm_http_init (8080, &err)); + fail_unless (NULL == err); + fail_unless (TRUE == pgm_http_shutdown ()); +} +END_TEST + +/* no running server */ +START_TEST (test_shutdown_fail_001) +{ + fail_unless (FALSE == pgm_http_shutdown ()); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_init = tcase_create ("init"); + suite_add_tcase (s, tc_init); + tcase_add_test (tc_init, test_init_pass_001); + tcase_add_test (tc_init, test_init_fail_001); + + TCase* tc_shutdown = tcase_create ("shutdown"); + suite_add_tcase (s, tc_shutdown); + tcase_add_test (tc_shutdown, test_shutdown_pass_001); + tcase_add_test (tc_shutdown, test_shutdown_pass_002); + tcase_add_test (tc_shutdown, test_shutdown_fail_001); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/if.c b/3rdparty/openpgm-svn-r1135/pgm/if.c new file mode 100644 index 0000000..d149608 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/if.c @@ -0,0 +1,1598 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * network interface handling. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#include +#include +#ifndef _WIN32 +# include +# include +# include /* _GNU_SOURCE for EAI_NODATA */ +#endif +#include +#include +#include + + +//#define IF_DEBUG + +/* temporary structure to contain interface name whilst address family + * has not been resolved. + */ +struct interface_req { + char ir_name[IF_NAMESIZE]; + unsigned int ir_flags; /* from SIOCGIFFLAGS */ + unsigned int ir_interface; /* interface index */ + struct sockaddr_storage ir_addr; /* interface address */ +}; + + +/* locals */ + +#ifndef _WIN32 +# define IF_DEFAULT_GROUP ((in_addr_t)0xefc00001) /* 239.192.0.1 */ +#else +# define IF_DEFAULT_GROUP ((u_long)0xefc00001) +#endif + +/* ff08::1 */ +#define IF6_DEFAULT_INIT { { { 0xff,8,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } +const struct in6_addr if6_default_group_addr = IF6_DEFAULT_INIT; + + +static inline bool is_in_net (const struct in_addr*restrict, const struct in_addr*restrict, const struct in_addr*restrict) PGM_GNUC_WARN_UNUSED_RESULT; +static inline bool is_in_net6 (const struct in6_addr*restrict, const struct in6_addr*restrict, const struct in6_addr*restrict) PGM_GNUC_WARN_UNUSED_RESULT; +static inline bool is_network_char (const int, const char) PGM_GNUC_CONST; +static const char* pgm_family_string (const int) PGM_GNUC_CONST; + + +/* recommended address space for multicast: + * rfc4607, rfc3180, rfc2365 + * + * avoid 5 high-order bit overlap. + * + * loopback: ffx1::/16 + * segment: ffx2::/16 + * glop: 238/8 + * mysterious admin: 239/8, ffx6::/16 + * site: 239.252-255/16, ffx5::/16 + * org: 239.192/14, ffx8::/16 + * + * internets: 224.0.1.0-238.255.255.255, ffxe::/16 + */ + + +/* dump all interfaces to console. + * + * note that interface indexes are only in regard to the link layer and hence + * no 1-1 mapping between adapter name to index back to address. + */ + +void +pgm_if_print_all (void) +{ + struct pgm_ifaddrs_t *ifap, *ifa; + + if (!pgm_getifaddrs (&ifap, NULL)) + return; + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) + { + const unsigned int i = NULL == ifa->ifa_addr ? 0 : pgm_if_nametoindex (ifa->ifa_addr->sa_family, ifa->ifa_name); + char rname[IF_NAMESIZE * 2 + 3]; + char b[IF_NAMESIZE * 2 + 3]; + + pgm_if_indextoname (i, rname); + sprintf (b, "%s (%s)", + ifa->ifa_name ? ifa->ifa_name : "(null)", rname); + + if (NULL == ifa->ifa_addr || + (ifa->ifa_addr->sa_family != AF_INET && + ifa->ifa_addr->sa_family != AF_INET6) ) + { + pgm_info (_("#%d name %-15.15s ---- %-46.46s scope 0 status %s loop %s b/c %s m/c %s"), + i, + b, + "", + ifa->ifa_flags & IFF_UP ? "UP " : "DOWN", + ifa->ifa_flags & IFF_LOOPBACK ? "YES" : "NO ", + ifa->ifa_flags & IFF_BROADCAST ? "YES" : "NO ", + ifa->ifa_flags & IFF_MULTICAST ? "YES" : "NO " + ); + continue; + } + + char s[INET6_ADDRSTRLEN]; + getnameinfo (ifa->ifa_addr, pgm_sockaddr_len(ifa->ifa_addr), + s, sizeof(s), + NULL, 0, + NI_NUMERICHOST); + pgm_info (_("#%d name %-15.15s IPv%i %-46.46s scope %u status %s loop %s b/c %s m/c %s"), + i, + b, + ifa->ifa_addr->sa_family == AF_INET ? 4 : 6, + s, + (unsigned)pgm_sockaddr_scope_id(ifa->ifa_addr), + ifa->ifa_flags & IFF_UP ? "UP " : "DOWN", + ifa->ifa_flags & IFF_LOOPBACK ? "YES" : "NO ", + ifa->ifa_flags & IFF_BROADCAST ? "YES" : "NO ", + ifa->ifa_flags & IFF_MULTICAST ? "YES" : "NO " + ); + } + + pgm_freeifaddrs (ifap); +} + +static inline +bool +is_in_net ( + const struct in_addr* restrict addr, /* host byte order */ + const struct in_addr* restrict netaddr, + const struct in_addr* restrict netmask + ) +{ + pgm_assert (NULL != addr); + pgm_assert (NULL != netaddr); + pgm_assert (NULL != netmask); + +#ifdef IF_DEBUG + const struct in_addr taddr = { .s_addr = htonl (addr->s_addr) }; + const struct in_addr tnetaddr = { .s_addr = htonl (netaddr->s_addr) }; + const struct in_addr tnetmask = { .s_addr = htonl (netmask->s_addr) }; + char saddr[INET_ADDRSTRLEN], snetaddr[INET_ADDRSTRLEN], snetmask[INET_ADDRSTRLEN]; + pgm_debug ("is_in_net (addr:%s netaddr:%s netmask:%s)", + pgm_inet_ntop (AF_INET, &taddr, saddr, sizeof(saddr)), + pgm_inet_ntop (AF_INET, &tnetaddr, snetaddr, sizeof(snetaddr)), + pgm_inet_ntop (AF_INET, &tnetmask, snetmask, sizeof(snetmask))); +#endif + + if ((addr->s_addr & netmask->s_addr) == (netaddr->s_addr & netmask->s_addr)) + return TRUE; + return FALSE; +} + +static +bool +is_in_net6 ( + const struct in6_addr* restrict addr, + const struct in6_addr* restrict netaddr, + const struct in6_addr* restrict netmask + ) +{ + pgm_assert (NULL != addr); + pgm_assert (NULL != netaddr); + pgm_assert (NULL != netmask); + +#ifdef IF_DEBUG + char saddr[INET6_ADDRSTRLEN], snetaddr[INET6_ADDRSTRLEN], snetmask[INET6_ADDRSTRLEN]; + pgm_debug ("is_in_net6 (addr:%s netaddr:%s netmask:%s)", + pgm_inet_ntop (AF_INET6, addr, saddr, sizeof(saddr)), + pgm_inet_ntop (AF_INET6, netaddr, snetaddr, sizeof(snetaddr)), + pgm_inet_ntop (AF_INET6, netmask, snetmask, sizeof(snetmask))); +#endif + + for (unsigned i = 0; i < 16; i++) + if ((addr->s6_addr[i] & netmask->s6_addr[i]) != (netaddr->s6_addr[i] & netmask->s6_addr[i])) + return FALSE; + return TRUE; +} + +/* parse interface entity into an interface-request structure. + * + * e.g. eth0 + * 1.2.3.4 + * 1.2 + * abcd:: + * [abcd::] + * + * + * + * special addresses should be ignored: + * + * local physical link: 169.254.0.0/16, fe80::/64 + * broadcast: 255.255.255.255 + * multicast: 224.0.0.0/4 (224.0.0.0 to 239.255.255.255), ff00::/8 + * + * We could use if_nametoindex() but we might as well check that the interface is + * actually UP and capable of multicast traffic. + * + * returns TRUE on success, FALSE on error and sets error appropriately. + */ + +static +bool +parse_interface ( + int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ + const char* restrict ifname, /* NULL terminated */ + struct interface_req* restrict ir, /* location to write interface details to */ + pgm_error_t** restrict error + ) +{ + bool check_inet_network = FALSE, check_inet6_network = FALSE; + bool check_addr = FALSE; + bool check_ifname = FALSE; + char literal[1024]; + struct in_addr in_addr; + struct in6_addr in6_addr; + struct pgm_ifaddrs_t *ifap, *ifa; + struct sockaddr_storage addr; + unsigned interface_matches = 0; + +/* pre-conditions */ + pgm_assert (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family); + pgm_assert (NULL != ifname); + pgm_assert (NULL != ir); + + pgm_debug ("parse_interface (family:%s ifname:%s%s%s ir:%p error:%p)", + pgm_family_string (family), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : "", + (const void*)ir, + (const void*)error); + +/* strip any square brackets for IPv6 early evaluation */ + if (AF_INET != family && + '[' == ifname[0]) + { + const size_t ifnamelen = strlen(ifname); + if (']' == ifname[ ifnamelen - 1 ]) { + strncpy (literal, ifname + 1, ifnamelen - 2); + literal[ ifnamelen - 2 ] = 0; + family = AF_INET6; /* force IPv6 evaluation */ + check_inet6_network = TRUE; /* may be a network IP or CIDR block */ + check_addr = TRUE; /* cannot be not a name */ + ifname = literal; + } + } + +/* network address: in_addr in host byte order */ + if (AF_INET6 != family && 0 == pgm_inet_network (ifname, &in_addr)) + { +#ifdef IF_DEBUG + struct in_addr t = { .s_addr = htonl (in_addr.s_addr) }; + pgm_debug ("IPv4 network address: %s", inet_ntoa (t)); +#endif + if (IN_MULTICAST(in_addr.s_addr)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_XDEV, + _("Expecting network interface address, found IPv4 multicast network %s%s%s"), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + return FALSE; + } + struct sockaddr_in s4; + memset (&s4, 0, sizeof(s4)); + s4.sin_family = AF_INET; + s4.sin_addr.s_addr = htonl (in_addr.s_addr); + memcpy (&addr, &s4, sizeof(s4)); + + check_inet_network = TRUE; + check_addr = TRUE; + } + if (AF_INET != family && 0 == pgm_inet6_network (ifname, &in6_addr)) + { + if (IN6_IS_ADDR_MULTICAST(&in6_addr)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_XDEV, + _("Expecting network interface address, found IPv6 multicast network %s%s%s"), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + return FALSE; + } + struct sockaddr_in6 s6; + memset (&s6, 0, sizeof(s6)); + s6.sin6_family = AF_INET6; + s6.sin6_addr = in6_addr; + memcpy (&addr, &s6, sizeof(s6)); + + check_inet6_network = TRUE; + check_addr = TRUE; + } + +/* numeric host with scope id */ + if (!check_addr) + { + struct addrinfo hints = { + .ai_family = family, + .ai_socktype = SOCK_STREAM, /* not really, SOCK_RAW */ + .ai_protocol = IPPROTO_TCP, /* not really, IPPROTO_PGM */ + .ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST /* AI_V4MAPPED is unhelpful */ + }, *res; + const int eai = getaddrinfo (ifname, NULL, &hints, &res); + switch (eai) { + case 0: + if (AF_INET == res->ai_family && + IN_MULTICAST(ntohl (((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr))) + { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_XDEV, + _("Expecting interface address, found IPv4 multicast address %s%s%s"), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + freeaddrinfo (res); + return FALSE; + } + else if (AF_INET6 == res->ai_family && + IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)res->ai_addr)->sin6_addr)) + { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_XDEV, + _("Expecting interface address, found IPv6 multicast address %s%s%s"), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + freeaddrinfo (res); + return FALSE; + } + + memcpy (&addr, res->ai_addr, pgm_sockaddr_len (res->ai_addr)); + freeaddrinfo (res); + check_addr = TRUE; + break; + +#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME + case EAI_NODATA: +#endif + case EAI_NONAME: + break; + + default: + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_eai_errno (eai, errno), + _("Numeric host resolution: %s"), + gai_strerror (eai)); + return FALSE; + } + } + +#ifndef _WIN32 +/* network name into network address, can be expensive with NSS network lookup + * + * Only Class A, B or C networks are supported, partitioned networks + * (i.e. network/26 or network/28) are not supported by this facility. + */ + if (!(check_inet_network || check_inet6_network)) + { + const struct netent* ne = getnetbyname (ifname); +/* ne::n_net in host byte order */ + + if (ne) { + switch (ne->n_addrtype) { + case AF_INET: + if (AF_INET6 == family) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("IP address family conflict when resolving network name %s%s%s, found AF_INET when AF_INET6 expected."), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + return FALSE; + } +/* ne->n_net in network order */ + in_addr.s_addr = ne->n_net; + if (IN_MULTICAST(in_addr.s_addr)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_XDEV, + _("Network name %s%s%s resolves to IPv4 mulicast address."), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + return FALSE; + } + check_inet_network = TRUE; + break; + case AF_INET6: +#ifndef CONFIG_HAVE_IP6_NETWORKS + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("Not configured for IPv6 network name support, %s%s%s is an IPv6 network name."), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + return FALSE; +#else + if (AF_INET == family) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("IP address family conflict when resolving network name %s%s%s, found AF_INET6 when AF_INET expected."), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + return FALSE; + } + if (IN6_IS_ADDR_MULTICAST(&ne->n_net)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_XDEV, + _("Network name resolves to IPv6 mulicast address %s%s%s"), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + return FALSE; + } + in6_addr = *(const struct in6_addr*)&ne->n_net; + check_inet6_network = TRUE; + break; +#endif + default: + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("Network name resolves to non-internet protocol address family %s%s%s"), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + return FALSE; + } + } + } +#endif /* _WIN32 */ + +/* hostname lookup with potential DNS delay or error */ + if (!check_addr) + { + struct addrinfo hints = { + .ai_family = family, + .ai_socktype = SOCK_STREAM, /* not really, SOCK_RAW */ + .ai_protocol = IPPROTO_TCP, /* not really, IPPROTO_PGM */ + .ai_flags = AI_ADDRCONFIG, /* AI_V4MAPPED is unhelpful */ + }, *res; + + const int eai = getaddrinfo (ifname, NULL, &hints, &res); + switch (eai) { + case 0: + if (AF_INET == res->ai_family && + IN_MULTICAST(ntohl (((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr))) + { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_XDEV, + _("Expecting interface address, found IPv4 multicast name %s%s%s"), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + freeaddrinfo (res); + return FALSE; + } + else if (AF_INET6 == res->ai_family && + IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)res->ai_addr)->sin6_addr)) + { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_XDEV, + _("Expecting interface address, found IPv6 multicast name %s%s%s"), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + freeaddrinfo (res); + return FALSE; + } + memcpy (&addr, res->ai_addr, pgm_sockaddr_len (res->ai_addr)); + freeaddrinfo (res); + check_addr = TRUE; + break; + +#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME + case EAI_NODATA: +#endif + case EAI_NONAME: + check_ifname = TRUE; + break; + + default: + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_eai_errno (eai, errno), + _("Internet host resolution: %s(%d)"), + gai_strerror (eai), eai); + return FALSE; + } + } + +/* iterate through interface list and match device name, ip or net address */ + if (!pgm_getifaddrs (&ifap, error)) { + pgm_prefix_error (error, + _("Enumerating network interfaces: ")); + return FALSE; + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) + { + if (NULL == ifa->ifa_addr) + continue; + + switch (ifa->ifa_addr->sa_family) { +/* ignore raw entries on Linux */ +#ifdef AF_PACKET + case AF_PACKET: + continue; +#endif + case AF_INET: + if (AF_INET6 == family) + continue; + break; + case AF_INET6: + if (AF_INET == family) + continue; + break; + default: + continue; + } + + const unsigned ifindex = pgm_if_nametoindex (ifa->ifa_addr->sa_family, ifa->ifa_name); + pgm_assert (0 != ifindex); + +/* check numeric host */ + if (check_addr && + (0 == pgm_sockaddr_cmp (ifa->ifa_addr, (const struct sockaddr*)&addr))) + { + strcpy (ir->ir_name, ifa->ifa_name); + ir->ir_flags = ifa->ifa_flags; + if (ir->ir_flags & IFF_LOOPBACK) + pgm_warn (_("Interface %s reports as a loopback device."), ir->ir_name); + if (!(ir->ir_flags & IFF_MULTICAST)) + pgm_warn (_("Interface %s reports as a non-multicast capable device."), ir->ir_name); + ir->ir_interface = ifindex; + memcpy (&ir->ir_addr, ifa->ifa_addr, pgm_sockaddr_len (ifa->ifa_addr)); + pgm_freeifaddrs (ifap); + return TRUE; + } + +/* check network address */ + if (check_inet_network && + AF_INET == ifa->ifa_addr->sa_family) + { + const struct in_addr ifaddr = { .s_addr = ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr) }; + const struct in_addr netmask = { .s_addr = ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr) }; + if (is_in_net (&ifaddr, &in_addr, &netmask)) { + strcpy (ir->ir_name, ifa->ifa_name); + ir->ir_flags = ifa->ifa_flags; + if (ir->ir_flags & IFF_LOOPBACK) { + pgm_warn (_("Skipping matching loopback network device %s."), ir->ir_name); + goto skip_inet_network; + } + if (!(ir->ir_flags & IFF_MULTICAST)) { + pgm_warn (_("Skipping matching non-multicast capable network device %s."), ir->ir_name); + goto skip_inet_network; + } + ir->ir_interface = ifindex; + memcpy (&ir->ir_addr, ifa->ifa_addr, pgm_sockaddr_len (ifa->ifa_addr)); + pgm_freeifaddrs (ifap); + return TRUE; + } + } + if (check_inet6_network && + AF_INET6 == ifa->ifa_addr->sa_family) + { + const struct in6_addr ifaddr = ((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr; + const struct in6_addr netmask = ((struct sockaddr_in6*)ifa->ifa_netmask)->sin6_addr; + if (is_in_net6 (&ifaddr, &in6_addr, &netmask)) { + strcpy (ir->ir_name, ifa->ifa_name); + ir->ir_flags = ifa->ifa_flags; + if (ir->ir_flags & IFF_LOOPBACK) { + pgm_warn (_("Skipping matching loopback network device %s."), ir->ir_name); + goto skip_inet_network; + } + if (!(ir->ir_flags & IFF_MULTICAST)) { + pgm_warn (_("Skipping matching non-multicast capable network device %s."), ir->ir_name); + goto skip_inet_network; + } + ir->ir_interface = ifindex; + memcpy (&ir->ir_addr, ifa->ifa_addr, pgm_sockaddr_len (ifa->ifa_addr)); + pgm_freeifaddrs (ifap); + return TRUE; + } + } +skip_inet_network: + +/* check interface name */ + if (check_ifname) + { + if (0 != strcmp (ifname, ifa->ifa_name)) + continue; + + ir->ir_flags = ifa->ifa_flags; +/* skip loopback and non-multicast capable devices */ + if ((ir->ir_flags & IFF_LOOPBACK) || !(ir->ir_flags & IFF_MULTICAST)) + continue; + +/* check for multiple interfaces */ + if (interface_matches++) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NOTUNIQ, + _("Network interface name not unique %s%s%s"), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + pgm_freeifaddrs (ifap); + return FALSE; + } + + ir->ir_interface = ifindex; + strcpy (ir->ir_name, ifa->ifa_name); + memcpy (&ir->ir_addr, ifa->ifa_addr, pgm_sockaddr_len (ifa->ifa_addr)); + continue; + } + + } + + if (0 == interface_matches) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("No matching non-loopback and multicast capable network interface %s%s%s"), + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + pgm_freeifaddrs (ifap); + return FALSE; + } + + pgm_freeifaddrs (ifap); + return TRUE; +} + +/* parse one multicast address, conflict resolution of multiple address families of DNS multicast names is + * deferred to libc. + * + * Zone indices are ignored as interface specification is already available. + * + * reserved addresses may flag warnings: + * + * 224.0.0.0/24 for local network control + * 224.0.1/24 for internetwork control + * 169.254.255.255, ff02::1 all local nodes on segment + * ff02::2 all routers + * ff05::1 all nodes + * ff0x::fb multicast DNS + * ff0x::108 NIS + * ff05::1:3 DHCP + * + * returns TRUE on success, FALSE on error and sets error appropriately. + */ + +static +bool +parse_group ( + const int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ + const char* restrict group, /* NULL terminated */ + struct sockaddr* restrict addr, /* pointer to sockaddr_storage for writing */ + pgm_error_t** restrict error + ) +{ +/* pre-conditions */ + pgm_assert (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family); + pgm_assert (NULL != group); + pgm_assert (NULL != addr); + + pgm_debug ("parse_group (family:%s group:%s%s%s addr:%p error:%p)", + pgm_family_string (family), + group ? "\"" : "", group ? group : "(null)", group ? "\"" : "", + (const void*)addr, + (const void*)error); + +/* strip any square brackets for early IPv6 literal evaluation */ + if (AF_INET != family && + '[' == group[0]) + { + const size_t grouplen = strlen(group); + if (']' == group[ grouplen - 1 ]) { + char literal[1024]; + strncpy (literal, group + 1, grouplen - 2); + literal[ grouplen - 2 ] = 0; + if (pgm_inet_pton (AF_INET6, literal, &((struct sockaddr_in6*)addr)->sin6_addr) && + IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr)) + { + addr->sa_family = AF_INET6; + ((struct sockaddr_in6*)addr)->sin6_port = 0; + ((struct sockaddr_in6*)addr)->sin6_flowinfo = 0; + ((struct sockaddr_in6*)addr)->sin6_scope_id = 0; + return TRUE; + } + } + } + +/* IPv4 address */ + if (AF_INET6 != family && + pgm_inet_pton (AF_INET, group, &((struct sockaddr_in*)addr)->sin_addr) && + IN_MULTICAST(ntohl (((struct sockaddr_in*)addr)->sin_addr.s_addr))) + { + addr->sa_family = AF_INET; + return TRUE; + } + if (AF_INET != family && + pgm_inet_pton (AF_INET6, group, &((struct sockaddr_in6*)addr)->sin6_addr) && + IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr)) + { + addr->sa_family = AF_INET6; + ((struct sockaddr_in6*)addr)->sin6_port = 0; + ((struct sockaddr_in6*)addr)->sin6_flowinfo = 0; + ((struct sockaddr_in6*)addr)->sin6_scope_id = 0; + return TRUE; + } + +#ifndef _WIN32 +/* NSS network */ + const struct netent* ne = getnetbyname (group); +/* ne::n_net in host byte order */ + if (ne) { + switch (ne->n_addrtype) { + case AF_INET: + if (AF_INET6 == family) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("IP address family conflict when resolving network name %s%s%s, found IPv4 when IPv6 expected."), + group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); + return FALSE; + } + if (IN_MULTICAST(ne->n_net)) { + addr->sa_family = AF_INET; + ((struct sockaddr_in*)addr)->sin_addr.s_addr = htonl (ne->n_net); + return TRUE; + } + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("IP address class conflict when resolving network name %s%s%s, expected IPv4 multicast."), + group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); + return FALSE; + case AF_INET6: +#ifndef CONFIG_HAVE_IP6_NETWORKS + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("Not configured for IPv6 network name support, %s%s%s is an IPv6 network name."), + group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); + return FALSE; +#else + if (AF_INET == family) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("IP address family conflict when resolving network name %s%s%s, found IPv6 when IPv4 expected."), + group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); + return FALSE; + } + if (IN6_IS_ADDR_MULTICAST(&ne->n_net)) { + addr->sa_family = AF_INET6; + ((struct sockaddr_in6*)addr)->sin6_addr = *(const struct in6_addr*)ne->n_net; + ((struct sockaddr_in6*)&addr)->sin6_port = 0; + ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; + ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; + return TRUE; + } + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("IP address class conflict when resolving network name %s%s%s, expected IPv6 multicast."), + group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); + return FALSE; +#endif /* CONFIG_HAVE_IP6_NETWORKS */ + default: + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("Network name resolves to non-internet protocol address family %s%s%s"), + group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); + return FALSE; + } + } +#endif /* _WIN32 */ + +/* lookup group through name service */ + struct addrinfo hints = { + .ai_family = family, + .ai_socktype = SOCK_STREAM, /* not really, SOCK_RAW */ + .ai_protocol = IPPROTO_TCP, /* not really, IPPROTO_PGM */ + .ai_flags = AI_ADDRCONFIG, /* AI_V4MAPPED is unhelpful */ + }, *res; + + const int eai = getaddrinfo (group, NULL, &hints, &res); + if (0 != eai) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + pgm_error_from_eai_errno (eai, errno), + _("Resolving receive group: %s"), + gai_strerror (eai)); + return FALSE; + } + + if ((AF_INET6 != family && IN_MULTICAST(ntohl (((struct sockaddr_in*)res->ai_addr)->sin_addr.s_addr))) || + (AF_INET != family && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)res->ai_addr)->sin6_addr))) + { + memcpy (addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo (res); + return TRUE; + } + + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_INVAL, + _("Unresolvable receive group %s%s%s"), + group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); + freeaddrinfo (res); + return FALSE; +} + +/* parse an interface entity from a network parameter. + * + * family can be unspecified - AF_UNSPEC, can return interfaces with the unspecified + * address family + * + * examples: "eth0" + * "hme0,hme1" + * "qe0,qe1,qe2" + * "qe0,qe2,qe2" => valid even though duplicate interface name + * + * returns TRUE on success with device_list containing double linked list of devices as + * sockaddr/idx pairs. returns FALSE on error, including multiple matching adapters. + * + * memory ownership of linked list is passed to caller and must be freed with pgm_free + * and the pgm_list_free* api. + */ + +static +bool +parse_interface_entity ( + int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ + const char* restrict entity, /* NULL terminated */ + pgm_list_t** restrict interface_list, /* */ + pgm_error_t** restrict error + ) +{ + struct interface_req* ir; + pgm_list_t* source_list = NULL; + +/* pre-conditions */ + pgm_assert (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family); + pgm_assert (NULL != interface_list); + pgm_assert (NULL == *interface_list); + pgm_assert (NULL != error); + + pgm_debug ("parse_interface_entity (family:%s entity:%s%s%s interface_list:%p error:%p)", + pgm_family_string (family), + entity ? "\"":"", entity ? entity : "(null)", entity ? "\"":"", + (const void*)interface_list, + (const void*)error); + +/* the empty entity, returns in_addr_any for both receive and send interfaces */ + if (NULL == entity) + { + ir = pgm_new0 (struct interface_req, 1); + ir->ir_addr.ss_family = family; + *interface_list = pgm_list_append (*interface_list, ir); + return TRUE; + } + +/* check interface name length limit */ + char** tokens = pgm_strsplit (entity, ",", 10); + int j = 0; + while (tokens && tokens[j]) + { + pgm_error_t* sub_error = NULL; + ir = pgm_new (struct interface_req, 1); + if (!parse_interface (family, tokens[j], ir, &sub_error)) + { +/* mark multiple interfaces for later decision based on group families */ + if (sub_error && PGM_ERROR_NOTUNIQ == sub_error->code) + { + ir->ir_addr.ss_family = AF_UNSPEC; + pgm_error_free (sub_error); + } +/* bail out on first interface with an error */ + else + { + pgm_propagate_error (error, sub_error); + pgm_free (ir); + pgm_strfreev (tokens); + while (source_list) { + pgm_free (source_list->data); + source_list = pgm_list_delete_link (source_list, source_list); + } + return FALSE; + } + } + + source_list = pgm_list_append (source_list, ir); + ++j; + } + + pgm_strfreev (tokens); + *interface_list = source_list; + return TRUE; +} + +/* parse a receive multicast group entity. can contain more than one multicast group to + * support asymmetric fan-out. + * + * if group is ambiguous, i.e. empty or a name mapping then the address family of the matching + * interface is queried. if the interface is also ambiguous, i.e. empty interface and receive group + * then the hostname will be used to determine the default node address family. if the hosts + * node name resolves both IPv4 and IPv6 address families then the first matching value is taken. + * + * e.g. "239.192.0.1" + * "239.192.0.100,239.192.0.101" + * + * unspecified address family interfaces are forced to AF_INET or AF_INET6. + * + * returns TRUE on success, returns FALSE on error and sets error appropriately. + */ + +static +bool +parse_receive_entity ( + int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ + const char* restrict entity, /* NULL terminated */ + pgm_list_t** restrict interface_list, /* */ + pgm_list_t** restrict recv_list, /* */ + pgm_error_t** restrict error + ) +{ +/* pre-conditions */ + pgm_assert (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family); + pgm_assert (NULL != recv_list); + pgm_assert (NULL == *recv_list); + pgm_assert (NULL != error); + + pgm_debug ("parse_receive_entity (family:%s entity:%s%s%s interface_list:%p recv_list:%p error:%p)", + pgm_family_string (family), + entity ? "\"":"", entity ? entity : "(null)", entity ? "\"":"", + (const void*)interface_list, + (const void*)recv_list, + (const void*)error); + + struct group_source_req* recv_gsr; + struct interface_req* primary_interface = (struct interface_req*)pgm_memdup ((*interface_list)->data, sizeof(struct interface_req)); + +/* the empty entity */ + if (NULL == entity) + { +/* default receive object */ + recv_gsr = pgm_new0 (struct group_source_req, 1); + recv_gsr->gsr_interface = primary_interface->ir_interface; + recv_gsr->gsr_group.ss_family = family; + +/* track IPv6 scope from any resolved interface */ + unsigned scope_id = 0; + +/* if using unspec default group check the interface for address family + */ + if (AF_UNSPEC == recv_gsr->gsr_group.ss_family) + { + if (AF_UNSPEC == primary_interface->ir_addr.ss_family) + { + struct sockaddr_storage addr; + if (!pgm_if_getnodeaddr (AF_UNSPEC, (struct sockaddr*)&addr, sizeof(addr), error)) + { + pgm_prefix_error (error, + _("Node primary address family cannot be determined: ")); + pgm_free (recv_gsr); + pgm_free (primary_interface); + return FALSE; + } + recv_gsr->gsr_group.ss_family = addr.ss_family; + scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&addr); + +/* was an interface actually specified */ + if (primary_interface->ir_name[0] != '\0') + { + struct interface_req ir; + if (!parse_interface (recv_gsr->gsr_group.ss_family, primary_interface->ir_name, &ir, error)) + { + pgm_prefix_error (error, + _("Unique address cannot be determined for interface %s%s%s: "), + primary_interface->ir_name ? "\"" : "", primary_interface->ir_name ? primary_interface->ir_name : "(null)", primary_interface->ir_name ? "\"" : ""); + pgm_free (recv_gsr); + pgm_free (primary_interface); + return FALSE; + } + + recv_gsr->gsr_interface = ir.ir_interface; + memcpy (&primary_interface->ir_addr, &ir.ir_addr, pgm_sockaddr_len ((struct sockaddr*)&ir.ir_addr)); + scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&ir.ir_addr); + } + } + else + { +/* use interface address family for multicast group */ + recv_gsr->gsr_group.ss_family = primary_interface->ir_addr.ss_family; + scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&primary_interface->ir_addr); + } + } + + + pgm_assert (AF_UNSPEC != recv_gsr->gsr_group.ss_family); + if (AF_UNSPEC != primary_interface->ir_addr.ss_family) + { + pgm_assert (recv_gsr->gsr_group.ss_family == primary_interface->ir_addr.ss_family); + } + else + { +/* check if we can now resolve the interface by address family of the receive group */ + if (primary_interface->ir_name[0] != '\0') + { + struct interface_req ir; + if (!parse_interface (recv_gsr->gsr_group.ss_family, primary_interface->ir_name, &ir, error)) + { + pgm_prefix_error (error, + _("Unique address cannot be determined for interface %s%s%s: "), + primary_interface->ir_name ? "\"" : "", primary_interface->ir_name ? primary_interface->ir_name : "(null)", primary_interface->ir_name ? "\"" : ""); + pgm_free (recv_gsr); + pgm_free (primary_interface); + return FALSE; + } + + recv_gsr->gsr_interface = ir.ir_interface; + scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&ir.ir_addr); + } + } + +/* copy default PGM multicast group */ + switch (recv_gsr->gsr_group.ss_family) { + case AF_INET6: + memcpy (&((struct sockaddr_in6*)&recv_gsr->gsr_group)->sin6_addr, + &if6_default_group_addr, + sizeof(if6_default_group_addr)); + ((struct sockaddr_in6*)&recv_gsr->gsr_group)->sin6_scope_id = scope_id; + break; + + case AF_INET: + ((struct sockaddr_in*)&recv_gsr->gsr_group)->sin_addr.s_addr = htonl(IF_DEFAULT_GROUP); + break; + + default: + pgm_assert_not_reached(); + } + +/* ASM: source = group */ + memcpy (&recv_gsr->gsr_source, &recv_gsr->gsr_group, pgm_sockaddr_len ((struct sockaddr*)&recv_gsr->gsr_group)); + *recv_list = pgm_list_append (*recv_list, recv_gsr); + pgm_free (primary_interface); + return TRUE; + } + +/* parse one or more multicast receive groups. + */ + + int j = 0; + char** tokens = pgm_strsplit (entity, ",", 10); + while (tokens && tokens[j]) + { +/* default receive object */ + recv_gsr = pgm_new0 (struct group_source_req, 1); + recv_gsr->gsr_interface = primary_interface->ir_interface; + recv_gsr->gsr_group.ss_family = family; + + if (AF_UNSPEC == recv_gsr->gsr_group.ss_family) + { + if (AF_UNSPEC == primary_interface->ir_addr.ss_family) + { + pgm_debug ("Address family of receive group cannot be determined from interface."); + } + else + { + recv_gsr->gsr_group.ss_family = primary_interface->ir_addr.ss_family; + ((struct sockaddr_in6*)&recv_gsr->gsr_group)->sin6_scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&primary_interface->ir_addr); + } + } + + if (!parse_group (recv_gsr->gsr_group.ss_family, tokens[j], (struct sockaddr*)&recv_gsr->gsr_group, error)) + { + pgm_prefix_error (error, + _("Unresolvable receive entity %s%s%s: "), + tokens[j] ? "\"" : "", tokens[j] ? tokens[j] : "(null)", tokens[j] ? "\"" : ""); + pgm_free (recv_gsr); + pgm_strfreev (tokens); + pgm_free (primary_interface); + return FALSE; + } + +/* check if we can now resolve the source interface by address family of the receive group */ + if (AF_UNSPEC == primary_interface->ir_addr.ss_family) + { + if (primary_interface->ir_name[0] != '\0') + { + struct interface_req ir; + if (!parse_interface (recv_gsr->gsr_group.ss_family, primary_interface->ir_name, &ir, error)) + { + pgm_prefix_error (error, + _("Unique address cannot be determined for interface %s%s%s: "), + primary_interface->ir_name ? "\"" : "", primary_interface->ir_name ? primary_interface->ir_name : "(null)", primary_interface->ir_name ? "\"" : ""); + pgm_free (recv_gsr); + pgm_free (primary_interface); + return FALSE; + } + + recv_gsr->gsr_interface = ir.ir_interface; + ((struct sockaddr_in6*)&recv_gsr->gsr_group)->sin6_scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&ir.ir_addr); + } + } + else + { +/* keep interface scope */ + ((struct sockaddr_in6*)&recv_gsr->gsr_group)->sin6_scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&primary_interface->ir_addr); + } + +/* ASM: source = group */ + memcpy (&recv_gsr->gsr_source, &recv_gsr->gsr_group, pgm_sockaddr_len ((struct sockaddr*)&recv_gsr->gsr_group)); + *recv_list = pgm_list_append (*recv_list, recv_gsr); + ++j; + } + + pgm_strfreev (tokens); + pgm_free (primary_interface); + return TRUE; +} + +static +bool +parse_send_entity ( + int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ + const char* restrict entity, /* null = empty entity */ + pgm_list_t** restrict interface_list, /* */ + pgm_list_t** restrict recv_list, /* */ + pgm_list_t** restrict send_list, /* */ + pgm_error_t** restrict error + ) +{ +/* pre-conditions */ + pgm_assert (AF_INET == family || AF_INET6 == family || AF_UNSPEC == family); + pgm_assert (NULL != recv_list); + pgm_assert (NULL != *recv_list); + pgm_assert (NULL != send_list); + pgm_assert (NULL == *send_list); + pgm_assert (NULL != error); + + pgm_debug ("parse_send_entity (family:%s entity:%s%s%s interface_list:%p recv_list:%p send_list:%p error:%p)", + pgm_family_string (family), + entity ? "\"":"", entity ? entity : "(null)", entity ? "\"":"", + (const void*)interface_list, + (const void*)recv_list, + (const void*)send_list, + (const void*)error); + + struct group_source_req* send_gsr; + const struct interface_req* primary_interface = (struct interface_req*)(*interface_list)->data; + + if (entity == NULL) + { + send_gsr = pgm_memdup ((*recv_list)->data, sizeof(struct group_source_req)); + *send_list = pgm_list_append (*send_list, send_gsr); + return TRUE; + } + +/* default send object */ + send_gsr = pgm_new0 (struct group_source_req, 1); + send_gsr->gsr_interface = primary_interface->ir_interface; + if (!parse_group (family, entity, (struct sockaddr*)&send_gsr->gsr_group, error)) + { + pgm_prefix_error (error, + _("Unresolvable send entity %s%s%s: "), + entity ? "\"":"", entity ? entity : "(null)", entity ? "\"":""); + pgm_free (send_gsr); + return FALSE; + } + +/* check if we can now resolve the source interface by address family of the send group */ + if (AF_UNSPEC == primary_interface->ir_addr.ss_family) + { + if (primary_interface->ir_name[0] != '\0') + { + struct interface_req ir; + if (!parse_interface (send_gsr->gsr_group.ss_family, primary_interface->ir_name, &ir, error)) + { + pgm_prefix_error (error, + _("Unique address cannot be determined for interface %s%s%s: "), + primary_interface->ir_name ? "\"":"", primary_interface->ir_name ? primary_interface->ir_name : "(null)", primary_interface->ir_name ? "\"":""); + pgm_free (send_gsr); + return FALSE; + } + + send_gsr->gsr_interface = ir.ir_interface; + ((struct sockaddr_in6*)&send_gsr->gsr_group)->sin6_scope_id = pgm_sockaddr_scope_id ((struct sockaddr*)&ir.ir_addr); + } + } + +/* ASM: source = group */ + memcpy (&send_gsr->gsr_source, &send_gsr->gsr_group, pgm_sockaddr_len ((struct sockaddr*)&send_gsr->gsr_group)); + *send_list = pgm_list_append (*send_list, send_gsr); + return TRUE; +} + +/* parse network parameter + * + * interface list; receive multicast group list; send multicast group + */ + +#define IS_HOSTNAME(x) ( /* RFC 952 */ \ + isalnum(x) || \ + ((x) == '-') || \ + ((x) == '.') \ + ) +#define IS_IP(x) ( \ + isdigit(x) || \ + ((x) == '.') || \ + ((x) == '/') \ + ) +#define IS_IP6(x) ( \ + isxdigit(x) || \ + ((x) == ':') || \ + ((x) == '/') || \ + ((x) == '.') || \ + ((x) == '[') || \ + ((x) == ']') \ + ) +/* e.g. fe80::1%eth0.620 vlan tag, + * fe80::1%eth0:0 IP alias + * fe80::1%qe0_0 Solaris link name + * + * The Linux kernel generally doesn't care too much, but everything else falls apart with + * random characters in interface names. Hyphen is a popular problematic character. + */ +#define IS_IP6_WITH_ZONE(x) ( \ + IS_IP6(x) || \ + ((x) == '%') || \ + isalpha(x) || \ + ((x) == '_') \ + ) +#define IS_NETPARAM(x) ( \ + ((x) == ',') || \ + ((x) == ';') \ + ) + +static inline +bool +is_network_char ( + const int family, + const char c + ) +{ + if (IS_HOSTNAME(c) || + (AF_INET == family && IS_IP(c)) || + ((AF_INET6 == family || AF_UNSPEC == family) && IS_IP6_WITH_ZONE(c)) || + IS_NETPARAM(c)) + return TRUE; + else + return FALSE; +} + +static +bool +network_parse ( + const char* restrict network, /* NULL terminated */ + int family, /* AF_UNSPEC | AF_INET | AF_INET6 */ + pgm_list_t** restrict recv_list, /* */ + pgm_list_t** restrict send_list, /* */ + pgm_error_t** restrict error + ) +{ + bool retval = FALSE; + const char *p = network; + const char *e = p + strlen(network); + enum { ENTITY_INTERFACE, ENTITY_RECEIVE, ENTITY_SEND, ENTITY_ERROR } ec = ENTITY_INTERFACE; + const char *b = p; /* begin of entity */ + pgm_list_t* source_list = NULL; + pgm_error_t* sub_error = NULL; + +/* pre-conditions */ + pgm_assert (NULL != network); + pgm_assert (AF_UNSPEC == family || AF_INET == family || AF_INET6 == family); + pgm_assert (NULL != recv_list); + pgm_assert (NULL != send_list); + + pgm_debug ("network_parse (network:%s%s%s family:%s recv_list:%p send_list:%p error:%p)", + network ? "\"" : "", network ? network : "(null)", network ? "\"" : "", + pgm_family_string (family), + (const void*)recv_list, + (const void*)send_list, + (const void*)error); + + while (p < e) + { + if (!is_network_char (family, *p)) + { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_INVAL, + _("'%c' is not a valid character."), + *p); + goto free_lists; + } + + if (*p == ';') /* end of entity */ + { + if (b == p) /* empty entity */ + { + switch (ec++) { + case ENTITY_INTERFACE: + retval = parse_interface_entity (family, NULL, &source_list, error); + break; + + case ENTITY_RECEIVE: + retval = parse_receive_entity (family, NULL, &source_list, recv_list, error); + break; + + case ENTITY_SEND: + retval = parse_send_entity (family, NULL, &source_list, recv_list, send_list, error); + break; + + default: + pgm_assert_not_reached(); + break; + } + + if (!retval) + goto free_lists; + + b = ++p; + continue; + } + +/* entity from b to p-1 */ + char entity[1024]; + strncpy (entity, b, sizeof(entity)); + entity[p - b] = 0; + + switch (ec++) { + case ENTITY_INTERFACE: + if (parse_interface_entity (family, entity, &source_list, &sub_error)) + break; + if (!(sub_error && PGM_ERROR_XDEV == sub_error->code)) + { +/* fall through on multicast */ + if (!(sub_error && PGM_ERROR_NOTUNIQ == sub_error->code)) + { + pgm_propagate_error (error, sub_error); + goto free_lists; + } + pgm_clear_error (&sub_error); +/* FIXME: too many interfaces */ + if (pgm_list_length (source_list) > 1) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_INVAL, + _("Send group list contains more than one entity.")); + goto free_lists; + } + break; + } + pgm_clear_error (&sub_error); + while (source_list) { + pgm_free (source_list->data); + source_list = pgm_list_delete_link (source_list, source_list); + } + if (!parse_interface_entity (family, NULL, &source_list, &sub_error) && + !(sub_error && PGM_ERROR_NOTUNIQ == sub_error->code)) + { + pgm_propagate_error (error, sub_error); + goto free_lists; + } + pgm_clear_error (&sub_error); + ec++; + + case ENTITY_RECEIVE: + if (!parse_receive_entity (family, entity, &source_list, recv_list, error)) + goto free_lists; + break; + + case ENTITY_SEND: + if (!parse_send_entity (family, entity, &source_list, recv_list, send_list, error)) + goto free_lists; + break; + + default: + pgm_assert_not_reached(); + break; + } + + b = ++p; + continue; + } + + p++; + } + + if (b < e) { + switch (ec++) { + case ENTITY_INTERFACE: + if (parse_interface_entity (family, b, &source_list, &sub_error)) + break; + if (!(sub_error && PGM_ERROR_XDEV == sub_error->code)) + { +/* fall through on multicast */ + if (!(sub_error && PGM_ERROR_NOTUNIQ == sub_error->code)) + { + pgm_propagate_error (error, sub_error); + goto free_lists; + } + pgm_clear_error (&sub_error); + +/* FIXME: too many interfaces */ + if (pgm_list_length (source_list) > 1) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_INVAL, + _("Send group list contains more than one entity.")); + goto free_lists; + } + break; + } + pgm_clear_error (&sub_error); + while (source_list) { + pgm_free (source_list->data); + source_list = pgm_list_delete_link (source_list, source_list); + } + if (!parse_interface_entity (family, NULL, &source_list, &sub_error) && + !(sub_error && PGM_ERROR_NOTUNIQ == sub_error->code)) + { + pgm_propagate_error (error, sub_error); + goto free_lists; + } + ec++; + + case ENTITY_RECEIVE: + if (!parse_receive_entity (family, b, &source_list, recv_list, error)) + goto free_lists; + break; + + case ENTITY_SEND: + if (!parse_send_entity (family, b, &source_list, recv_list, send_list, error)) + goto free_lists; + break; + + default: + pgm_assert_not_reached(); + break; + } + } + + while (ec <= ENTITY_SEND) + { + switch (ec++) { + case ENTITY_INTERFACE: + if (!parse_interface_entity (family, NULL, &source_list, error)) + goto free_lists; + break; + + case ENTITY_RECEIVE: + if (!parse_receive_entity (family, NULL, &source_list, recv_list, error)) + goto free_lists; + break; + + case ENTITY_SEND: + if (!parse_send_entity (family, NULL, &source_list, recv_list, send_list, error)) + goto free_lists; + break; + + default: + pgm_assert_not_reached(); + break; + } + } + + if (pgm_list_length (source_list) > 1) + goto free_lists; + +/* cleanup source interface list */ + while (source_list) { + pgm_free (source_list->data); + source_list = pgm_list_delete_link (source_list, source_list); + } + + return TRUE; + +free_lists: + while (source_list) { + pgm_free (source_list->data); + source_list = pgm_list_delete_link (source_list, source_list); + } + while (*recv_list) { + pgm_free ((*recv_list)->data); + *recv_list = pgm_list_delete_link (*recv_list, *recv_list); + } + while (*send_list) { + pgm_free ((*send_list)->data); + *send_list = pgm_list_delete_link (*send_list, *send_list); + } + return FALSE; +} + +/* create group_source_req as used by pgm_transport_create which specify port, address & interface. + * gsr_source is copied from gsr_group for ASM, caller needs to populate gsr_source for SSM. + * + * returns TRUE on success, returns FALSE on error and sets error appropriately. + */ + +bool +pgm_getaddrinfo ( + const char* restrict network, + const struct pgm_addrinfo_t* const restrict hints, + struct pgm_addrinfo_t** restrict res, + pgm_error_t** restrict error + ) +{ + struct pgm_addrinfo_t* ai; + const int family = hints ? hints->ai_family : AF_UNSPEC; + pgm_list_t* recv_list = NULL; /* */ + pgm_list_t* send_list = NULL; /* */ + + pgm_return_val_if_fail (NULL != network, FALSE); + pgm_return_val_if_fail (AF_UNSPEC == family || AF_INET == family || AF_INET6 == family, FALSE); + pgm_return_val_if_fail (NULL != res, FALSE); + + if (hints) { + pgm_debug ("pgm_getaddrinfo (network:%s%s%s hints: {family:%s} res:%p error:%p)", + network ? "\"" : "", network ? network : "(null)", network ? "\"" : "", + pgm_family_string (family), + (const void*)res, + (const void*)error); + } else { + pgm_debug ("pgm_getaddrinfo (network:%s%s%s hints:%p res:%p error:%p)", + network ? "\"" : "", network ? network : "(null)", network ? "\"" : "", + (const void*)hints, + (const void*)res, + (const void*)error); + } + + if (!network_parse (network, family, &recv_list, &send_list, error)) + return FALSE; + const size_t recv_list_len = pgm_list_length (recv_list); + const size_t send_list_len = pgm_list_length (send_list); + ai = pgm_malloc0 (sizeof(struct pgm_addrinfo_t) + + (recv_list_len + send_list_len) * sizeof(struct group_source_req)); + ai->ai_recv_addrs_len = recv_list_len; + ai->ai_recv_addrs = (void*)((char*)ai + sizeof(struct pgm_addrinfo_t)); + ai->ai_send_addrs_len = send_list_len; + ai->ai_send_addrs = (void*)((char*)ai->ai_recv_addrs + recv_list_len * sizeof(struct group_source_req)); + + size_t i = 0; + while (recv_list) { + memcpy (&ai->ai_recv_addrs[i++], recv_list->data, sizeof(struct group_source_req)); + pgm_free (recv_list->data); + recv_list = pgm_list_delete_link (recv_list, recv_list); + } + i = 0; + while (send_list) { + memcpy (&ai->ai_send_addrs[i++], send_list->data, sizeof(struct group_source_req)); + pgm_free (send_list->data); + send_list = pgm_list_delete_link (send_list, send_list); + } + *res = ai; + return TRUE; +} + +void +pgm_freeaddrinfo ( + struct pgm_addrinfo_t* res + ) +{ + pgm_free (res); +} + + +static +const char* +pgm_family_string ( + const int family + ) +{ + const char* c; + + switch (family) { + case AF_UNSPEC: c = "AF_UNSPEC"; break; + case AF_INET: c = "AF_INET"; break; + case AF_INET6: c = "AF_INET6"; break; + default: c = "(unknown)"; break; + } + + return c; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/if.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/if.c.c89.patch new file mode 100644 index 0000000..245479a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/if.c.c89.patch @@ -0,0 +1,376 @@ +--- if.c 2010-05-29 17:36:46.000000000 +0800 ++++ if.c89 2010-08-05 13:19:04.000000000 +0800 +@@ -102,8 +102,13 @@ + char b[IF_NAMESIZE * 2 + 3]; + + pgm_if_indextoname (i, rname); ++#ifdef _MSC_VER ++ _snprintf_s (b, sizeof(b), _TRUNCATE, "%s (%s)", ++ ifa->ifa_name ? ifa->ifa_name : "(null)", rname); ++#else + sprintf (b, "%s (%s)", + ifa->ifa_name ? ifa->ifa_name : "(null)", rname); ++#endif + + if (NULL == ifa->ifa_addr || + (ifa->ifa_addr->sa_family != AF_INET && +@@ -121,6 +126,7 @@ + continue; + } + ++ { + char s[INET6_ADDRSTRLEN]; + getnameinfo (ifa->ifa_addr, pgm_sockaddr_len(ifa->ifa_addr), + s, sizeof(s), +@@ -137,6 +143,7 @@ + ifa->ifa_flags & IFF_BROADCAST ? "YES" : "NO ", + ifa->ifa_flags & IFF_MULTICAST ? "YES" : "NO " + ); ++ } + } + + pgm_freeifaddrs (ifap); +@@ -190,9 +197,12 @@ + pgm_inet_ntop (AF_INET6, netmask, snetmask, sizeof(snetmask))); + #endif + +- for (unsigned i = 0; i < 16; i++) ++ { ++ unsigned i; ++ for (i = 0; i < 16; i++) + if ((addr->s6_addr[i] & netmask->s6_addr[i]) != (netaddr->s6_addr[i] & netmask->s6_addr[i])) + return FALSE; ++ } + return TRUE; + } + +@@ -254,8 +264,12 @@ + { + const size_t ifnamelen = strlen(ifname); + if (']' == ifname[ ifnamelen - 1 ]) { ++#ifdef _MSC_VER ++ strncpy_s (literal, sizeof(literal), ifname + 1, ifnamelen - 2); ++#else + strncpy (literal, ifname + 1, ifnamelen - 2); + literal[ ifnamelen - 2 ] = 0; ++#endif + family = AF_INET6; /* force IPv6 evaluation */ + check_inet6_network = TRUE; /* may be a network IP or CIDR block */ + check_addr = TRUE; /* cannot be not a name */ +@@ -278,11 +292,13 @@ + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + return FALSE; + } ++ { + struct sockaddr_in s4; + memset (&s4, 0, sizeof(s4)); + s4.sin_family = AF_INET; + s4.sin_addr.s_addr = htonl (in_addr.s_addr); + memcpy (&addr, &s4, sizeof(s4)); ++ } + + check_inet_network = TRUE; + check_addr = TRUE; +@@ -297,11 +313,13 @@ + ifname ? "\"" : "", ifname ? ifname : "(null)", ifname ? "\"" : ""); + return FALSE; + } ++ { + struct sockaddr_in6 s6; + memset (&s6, 0, sizeof(s6)); + s6.sin6_family = AF_INET6; + s6.sin6_addr = in6_addr; + memcpy (&addr, &s6, sizeof(s6)); ++ } + + check_inet6_network = TRUE; + check_addr = TRUE; +@@ -310,12 +328,13 @@ + /* numeric host with scope id */ + if (!check_addr) + { +- struct addrinfo hints = { +- .ai_family = family, +- .ai_socktype = SOCK_STREAM, /* not really, SOCK_RAW */ +- .ai_protocol = IPPROTO_TCP, /* not really, IPPROTO_PGM */ +- .ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST /* AI_V4MAPPED is unhelpful */ +- }, *res; ++ struct addrinfo hints, *res; ++ memset (&hints, 0, sizeof(hints)); ++ hints.ai_family = family; ++ hints.ai_socktype = SOCK_STREAM; /* not really, SOCK_RAW */ ++ hints.ai_protocol = IPPROTO_TCP; /* not really, IPPROTO_PGM */ ++ hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; /* AI_V4MAPPED is unhelpful */ ++ { + const int eai = getaddrinfo (ifname, NULL, &hints, &res); + switch (eai) { + case 0: +@@ -361,6 +380,7 @@ + gai_strerror (eai)); + return FALSE; + } ++ } + } + + #ifndef _WIN32 +@@ -441,13 +461,13 @@ + /* hostname lookup with potential DNS delay or error */ + if (!check_addr) + { +- struct addrinfo hints = { +- .ai_family = family, +- .ai_socktype = SOCK_STREAM, /* not really, SOCK_RAW */ +- .ai_protocol = IPPROTO_TCP, /* not really, IPPROTO_PGM */ +- .ai_flags = AI_ADDRCONFIG, /* AI_V4MAPPED is unhelpful */ +- }, *res; +- ++ struct addrinfo hints, *res; ++ memset (&hints, 0, sizeof(hints)); ++ hints.ai_family = family; ++ hints.ai_socktype = SOCK_STREAM; /* not really, SOCK_RAW */ ++ hints.ai_protocol = IPPROTO_TCP; /* not really, IPPROTO_PGM */ ++ hints.ai_flags = AI_ADDRCONFIG; /* AI_V4MAPPED is unhelpful */ ++ { + const int eai = getaddrinfo (ifname, NULL, &hints, &res); + switch (eai) { + case 0: +@@ -493,6 +513,7 @@ + gai_strerror (eai), eai); + return FALSE; + } ++ } + } + + /* iterate through interface list and match device name, ip or net address */ +@@ -525,6 +546,7 @@ + continue; + } + ++ { + const unsigned ifindex = pgm_if_nametoindex (ifa->ifa_addr->sa_family, ifa->ifa_name); + pgm_assert (0 != ifindex); + +@@ -532,7 +554,11 @@ + if (check_addr && + (0 == pgm_sockaddr_cmp (ifa->ifa_addr, (const struct sockaddr*)&addr))) + { ++#ifdef _MSC_VER ++ strcpy_s (ir->ir_name, IF_NAMESIZE, ifa->ifa_name); ++#else + strcpy (ir->ir_name, ifa->ifa_name); ++#endif + ir->ir_flags = ifa->ifa_flags; + if (ir->ir_flags & IFF_LOOPBACK) + pgm_warn (_("Interface %s reports as a loopback device."), ir->ir_name); +@@ -548,10 +574,15 @@ + if (check_inet_network && + AF_INET == ifa->ifa_addr->sa_family) + { +- const struct in_addr ifaddr = { .s_addr = ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr) }; +- const struct in_addr netmask = { .s_addr = ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr) }; ++ struct in_addr ifaddr, netmask; ++ ifaddr.s_addr = ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr); ++ netmask.s_addr = ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr); + if (is_in_net (&ifaddr, &in_addr, &netmask)) { ++#ifdef _MSC_VER ++ strcpy_s (ir->ir_name, IF_NAMESIZE, ifa->ifa_name); ++#else + strcpy (ir->ir_name, ifa->ifa_name); ++#endif + ir->ir_flags = ifa->ifa_flags; + if (ir->ir_flags & IFF_LOOPBACK) { + pgm_warn (_("Skipping matching loopback network device %s."), ir->ir_name); +@@ -573,7 +604,11 @@ + const struct in6_addr ifaddr = ((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr; + const struct in6_addr netmask = ((struct sockaddr_in6*)ifa->ifa_netmask)->sin6_addr; + if (is_in_net6 (&ifaddr, &in6_addr, &netmask)) { ++#ifdef _MSC_VER ++ strcpy_s (ir->ir_name, IF_NAMESIZE, ifa->ifa_name); ++#else + strcpy (ir->ir_name, ifa->ifa_name); ++#endif + ir->ir_flags = ifa->ifa_flags; + if (ir->ir_flags & IFF_LOOPBACK) { + pgm_warn (_("Skipping matching loopback network device %s."), ir->ir_name); +@@ -614,11 +649,15 @@ + } + + ir->ir_interface = ifindex; ++#ifdef _MSC_VER ++ strcpy_s (ir->ir_name, IF_NAMESIZE, ifa->ifa_name); ++#else + strcpy (ir->ir_name, ifa->ifa_name); ++#endif + memcpy (&ir->ir_addr, ifa->ifa_addr, pgm_sockaddr_len (ifa->ifa_addr)); + continue; + } +- ++ } + } + + if (0 == interface_matches) { +@@ -681,8 +720,12 @@ + const size_t grouplen = strlen(group); + if (']' == group[ grouplen - 1 ]) { + char literal[1024]; ++#ifdef _MSC_VER ++ strncpy_s (literal, sizeof(literal), group + 1, grouplen - 2); ++#else + strncpy (literal, group + 1, grouplen - 2); + literal[ grouplen - 2 ] = 0; ++#endif + if (pgm_inet_pton (AF_INET6, literal, &((struct sockaddr_in6*)addr)->sin6_addr) && + IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)addr)->sin6_addr)) + { +@@ -784,13 +827,14 @@ + #endif /* _WIN32 */ + + /* lookup group through name service */ +- struct addrinfo hints = { +- .ai_family = family, +- .ai_socktype = SOCK_STREAM, /* not really, SOCK_RAW */ +- .ai_protocol = IPPROTO_TCP, /* not really, IPPROTO_PGM */ +- .ai_flags = AI_ADDRCONFIG, /* AI_V4MAPPED is unhelpful */ +- }, *res; +- ++ { ++ struct addrinfo hints, *res; ++ memset (&hints, 0, sizeof(hints)); ++ hints.ai_family = family; ++ hints.ai_socktype = SOCK_STREAM; /* not really, SOCK_RAW */ ++ hints.ai_protocol = IPPROTO_TCP; /* not really, IPPROTO_PGM */ ++ hints.ai_flags = AI_ADDRCONFIG; /* AI_V4MAPPED is unhelpful */ ++ { + const int eai = getaddrinfo (group, NULL, &hints, &res); + if (0 != eai) { + pgm_set_error (error, +@@ -816,6 +860,8 @@ + group ? "\"" : "", group ? group : "(null)", group ? "\"" : ""); + freeaddrinfo (res); + return FALSE; ++ } ++ } + } + + /* parse an interface entity from a network parameter. +@@ -869,6 +915,7 @@ + } + + /* check interface name length limit */ ++ { + char** tokens = pgm_strsplit (entity, ",", 10); + int j = 0; + while (tokens && tokens[j]) +@@ -903,6 +950,7 @@ + + pgm_strfreev (tokens); + *interface_list = source_list; ++ } + return TRUE; + } + +@@ -945,6 +993,7 @@ + (const void*)recv_list, + (const void*)error); + ++ { + struct group_source_req* recv_gsr; + struct interface_req* primary_interface = (struct interface_req*)pgm_memdup ((*interface_list)->data, sizeof(struct interface_req)); + +@@ -957,6 +1006,7 @@ + recv_gsr->gsr_group.ss_family = family; + + /* track IPv6 scope from any resolved interface */ ++ { + unsigned scope_id = 0; + + /* if using unspec default group check the interface for address family +@@ -1053,11 +1103,13 @@ + *recv_list = pgm_list_append (*recv_list, recv_gsr); + pgm_free (primary_interface); + return TRUE; ++ } + } + + /* parse one or more multicast receive groups. + */ + ++ { + int j = 0; + char** tokens = pgm_strsplit (entity, ",", 10); + while (tokens && tokens[j]) +@@ -1126,6 +1178,8 @@ + pgm_strfreev (tokens); + pgm_free (primary_interface); + return TRUE; ++ } ++ } + } + + static +@@ -1155,6 +1209,7 @@ + (const void*)send_list, + (const void*)error); + ++ { + struct group_source_req* send_gsr; + const struct interface_req* primary_interface = (struct interface_req*)(*interface_list)->data; + +@@ -1201,6 +1256,7 @@ + memcpy (&send_gsr->gsr_source, &send_gsr->gsr_group, pgm_sockaddr_len ((struct sockaddr*)&send_gsr->gsr_group)); + *send_list = pgm_list_append (*send_list, send_gsr); + return TRUE; ++ } + } + + /* parse network parameter +@@ -1333,9 +1389,14 @@ + } + + /* entity from b to p-1 */ ++ { + char entity[1024]; ++#ifdef _MSC_VER ++ strncpy_s (entity, sizeof(entity), b, p - b); ++#else + strncpy (entity, b, sizeof(entity)); + entity[p - b] = 0; ++#endif + + switch (ec++) { + case ENTITY_INTERFACE: +@@ -1391,6 +1452,7 @@ + + b = ++p; + continue; ++ } + } + + p++; +@@ -1540,6 +1602,7 @@ + + if (!network_parse (network, family, &recv_list, &send_list, error)) + return FALSE; ++ { + const size_t recv_list_len = pgm_list_length (recv_list); + const size_t send_list_len = pgm_list_length (send_list); + ai = pgm_malloc0 (sizeof(struct pgm_addrinfo_t) + +@@ -1548,7 +1611,8 @@ + ai->ai_recv_addrs = (void*)((char*)ai + sizeof(struct pgm_addrinfo_t)); + ai->ai_send_addrs_len = send_list_len; + ai->ai_send_addrs = (void*)((char*)ai->ai_recv_addrs + recv_list_len * sizeof(struct group_source_req)); +- ++ ++ { + size_t i = 0; + while (recv_list) { + memcpy (&ai->ai_recv_addrs[i++], recv_list->data, sizeof(struct group_source_req)); +@@ -1563,6 +1627,8 @@ + } + *res = ai; + return TRUE; ++ } ++ } + } + + void diff --git a/3rdparty/openpgm-svn-r1135/pgm/if_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/if_unittest.c new file mode 100644 index 0000000..ada444a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/if_unittest.c @@ -0,0 +1,1497 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for network interface declaration parsing. + * + * CAUTION: Assumes host is IPv4 by default for AF_UNSPEC + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* IFF_UP */ +#ifndef _BSD_SOURCE +# define _BSD_SOURCE 1 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* mock state */ + +struct mock_host_t { + struct sockaddr_storage address; + char* canonical_hostname; + char* alias; +}; + +struct mock_network_t { + char* name; + struct sockaddr_storage number; + char** aliases; +}; + +struct mock_interface_t { + unsigned int index; + char* name; + unsigned int flags; + struct sockaddr_storage addr; + struct sockaddr_storage netmask; +}; + +static GList *mock_hosts = NULL, *mock_networks = NULL, *mock_interfaces = NULL; + +#define MOCK_HOSTNAME "kiku" +#define MOCK_HOSTNAME6 "ip6-kiku" /* ping6 doesn't work on fe80:: */ +#define MOCK_NETWORK "private" /* /etc/networks */ +#define MOCK_NETWORK6 "ip6-private" +#define MOCK_PGM_NETWORK "pgm-private" +#define MOCK_PGM_NETWORK6 "pgm-ip6-private" +#define MOCK_INTERFACE "eth0" +#define MOCK_INTERFACE_INDEX 2 +#define MOCK_ADDRESS "10.6.28.33" +#define MOCK_GROUP ((in_addr_t) 0xefc00001) /* 239.192.0.1 */ +#define MOCK_GROUP6_INIT { { { 0xff,8,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } /* ff08::1 */ +static const struct in6_addr mock_group6_addr = MOCK_GROUP6_INIT; +#define MOCK_ADDRESS6 "2002:dce8:d28e::33" +#define MOCK_ADDRESS6_INIT { { { 0x20,2,0xdc,0xe8,0xd2,0x8e,0,0,0,0,0,0,0,0,0,0x33 } } } +static const struct in6_addr mock_address6_addr = MOCK_ADDRESS6_INIT; + +static int mock_family = 0; +static char* mock_kiku = MOCK_HOSTNAME; +static char* mock_localhost = "localhost"; +static char* mock_invalid = "invalid.invalid"; /* RFC 2606 */ +static char* mock_toolong = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij12345"; /* 65 */ +static char* mock_hostname = NULL; + +struct pgm_ifaddrs_t; +struct pgm_error_t; + +bool mock_pgm_getifaddrs (struct pgm_ifaddrs_t**, struct pgm_error_t**); +void mock_pgm_freeifaddrs (struct pgm_ifaddrs_t*); +unsigned mock_pgm_if_nametoindex (const sa_family_t, const char*); +char* mock_if_indextoname (unsigned int, char*); +int mock_getnameinfo (const struct sockaddr*, socklen_t, char*, size_t, char*, size_t, int); +int mock_getaddrinfo (const char*, const char*, const struct addrinfo*, struct addrinfo**); +void mock_freeaddrinfo (struct addrinfo*); +int mock_gethostname (char*, size_t); +struct netent* mock_getnetbyname (const char*); +bool mock_pgm_if_getnodeaddr (const sa_family_t, struct sockaddr*, const socklen_t, struct pgm_error_t**); + +#define pgm_getifaddrs mock_pgm_getifaddrs +#define pgm_freeifaddrs mock_pgm_freeifaddrs +#define pgm_if_nametoindex mock_pgm_if_nametoindex +#define if_indextoname mock_if_indextoname +#define getnameinfo mock_getnameinfo +#define getaddrinfo mock_getaddrinfo +#define freeaddrinfo mock_freeaddrinfo +#define gethostname mock_gethostname +#define getnetbyname mock_getnetbyname +#define pgm_if_getnodeaddr mock_pgm_if_getnodeaddr + + +#define IF_DEBUG +#include "if.c" + + +static +gpointer +create_host ( + const char* address, + const char* canonical_hostname, + const char* alias + ) +{ + struct mock_host_t* new_host; + + g_assert (address); + g_assert (canonical_hostname); + + new_host = g_slice_alloc0 (sizeof(struct mock_host_t)); + g_assert (pgm_sockaddr_pton (address, (struct sockaddr*)&new_host->address)); + new_host->canonical_hostname = g_strdup (canonical_hostname); + new_host->alias = alias ? g_strdup (alias) : NULL; + + return new_host; +} + +static +gpointer +create_network ( + const char* name, + const char* number + ) +{ + struct mock_network_t* new_network; + + g_assert (name); + g_assert (number); + + new_network = g_slice_alloc0 (sizeof(struct mock_network_t)); + new_network->name = g_strdup (name); + g_assert (pgm_sockaddr_pton (number, (struct sockaddr*)&new_network->number)); + + return new_network; +} + +static +gpointer +create_interface ( + const unsigned index, + const char* name, + const char* flags + ) +{ + struct mock_interface_t* new_interface; + + g_assert (name); + g_assert (flags); + + new_interface = g_slice_alloc0 (sizeof(struct mock_interface_t)); + new_interface->index = index; + new_interface->name = g_strdup (name); + + struct sockaddr_in* sin = (gpointer)&new_interface->addr; + struct sockaddr_in6* sin6 = (gpointer)&new_interface->addr; + + gchar** tokens = g_strsplit (flags, ",", 0); + for (guint i = 0; tokens[i]; i++) + { + if (strcmp (tokens[i], "up") == 0) + new_interface->flags |= IFF_UP; + else if (strcmp (tokens[i], "down") == 0) + new_interface->flags |= 0; + else if (strcmp (tokens[i], "loop") == 0) + new_interface->flags |= IFF_LOOPBACK; + else if (strcmp (tokens[i], "broadcast") == 0) + new_interface->flags |= IFF_BROADCAST; + else if (strcmp (tokens[i], "multicast") == 0) + new_interface->flags |= IFF_MULTICAST; + else if (strncmp (tokens[i], "ip=", strlen("ip=")) == 0) { + const char* addr = tokens[i] + strlen("ip="); + g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->addr)); + } + else if (strncmp (tokens[i], "netmask=", strlen("netmask=")) == 0) { + const char* addr = tokens[i] + strlen("netmask="); + g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->netmask)); + } + else if (strncmp (tokens[i], "scope=", strlen("scope=")) == 0) { + const char* scope = tokens[i] + strlen("scope="); + g_assert (AF_INET6 == ((struct sockaddr*)&new_interface->addr)->sa_family); + ((struct sockaddr_in6*)&new_interface->addr)->sin6_scope_id = atoi (scope); + } + else + g_error ("parsing failed for flag %s%s%s", + tokens[i] ? "\"" : "", tokens[i] ? tokens[i] : "(null)", tokens[i] ? "\"" : ""); + } + + g_strfreev (tokens); + return new_interface; +} + +#define APPEND_HOST2(a,b,c) \ + do { \ + gpointer data = create_host ((a), (b), (c)); \ + g_assert (data); \ + mock_hosts = g_list_append (mock_hosts, data); \ + g_assert (mock_hosts); g_assert (mock_hosts->data); \ + } while (0) +#define APPEND_HOST(a,b) APPEND_HOST2((a),(b),NULL) +#define APPEND_NETWORK(a,b) \ + do { \ + gpointer data = create_network ((a), (b)); \ + g_assert (data); \ + mock_networks = g_list_append (mock_networks, data); \ + g_assert (mock_networks); g_assert (mock_networks->data); \ + } while (0) +#define APPEND_INTERFACE(a,b,c) \ + do { \ + gpointer data = create_interface ((a), (b), (c)); \ + g_assert (data); \ + mock_interfaces = g_list_append (mock_interfaces, data); \ + g_assert (mock_interfaces); g_assert (mock_interfaces->data); \ + } while (0) +static +void +mock_setup_net (void) +{ + mock_hostname = mock_kiku; + + APPEND_HOST ( "127.0.0.1", "localhost"); + APPEND_HOST2( "10.6.28.33", "kiku.hk.miru.hk", "kiku"); + APPEND_HOST2( "2002:dce8:d28e::33", "ip6-kiku", "kiku"); + APPEND_HOST2( "172.12.90.1", "mi-hee.ko.miru.hk", "mi-hee"); + APPEND_HOST2( "::1", "ip6-localhost", "ip6-loopback"); + APPEND_HOST ( "239.192.0.1", "PGM.MCAST.NET"); + APPEND_HOST ( "ff08::1", "IP6-PGM.MCAST.NET"); + + APPEND_NETWORK( "loopback", "127.0.0.0"); + APPEND_NETWORK( "private", "10.6.28.0"); + APPEND_NETWORK( "private2", "172.16.90.0"); + APPEND_NETWORK( "pgm-private", "239.192.0.1"); +#ifdef CONFIG_HAVE_IP6_NETWORKS + APPEND_NETWORK( "ip6-private", "2002:dce8:d28e:0:0:0"); + APPEND_NETWORK( "ip6-pgm-private","ff08::1"); +#endif + + APPEND_INTERFACE( 1, "lo", "up,loop"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast"); + APPEND_INTERFACE( 3, "eth1", "down,broadcast,multicast"); + APPEND_INTERFACE( 1, "lo", "up,loop,ip=127.0.0.1,netmask=255.0.0.0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=10.6.28.33,netmask=255.255.255.0"); + APPEND_INTERFACE( 1, "lo", "up,loop,ip=::1,netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,scope=0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=2002:dce8:d28e::33,netmask=ffff:ffff:ffff:ffff::0,scope=0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=fe80::214:5eff:febd:6dda,netmask=ffff:ffff:ffff:ffff::0,scope=2"); +} + +static +void +mock_teardown_net (void) +{ + GList* list; + + list = mock_hosts; + while (list) { + struct mock_host_t* host = list->data; + g_free (host->canonical_hostname); + if (host->alias) + g_free (host->alias); + g_slice_free1 (sizeof(struct mock_host_t), host); + list = list->next; + } + g_list_free (mock_hosts); + + list = mock_networks; + while (list) { + struct mock_network_t* network = list->data; + g_free (network->name); + g_slice_free1 (sizeof(struct mock_network_t), network); + list = list->next; + } + g_list_free (mock_networks); + + list = mock_interfaces; + while (list) { + struct mock_interface_t* interface = list->data; + g_free (interface->name); + g_slice_free1 (sizeof(struct mock_interface_t), interface); + list = list->next; + } + g_list_free (mock_interfaces); +} + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + +bool +mock_pgm_getifaddrs ( + struct pgm_ifaddrs_t** ifap, + pgm_error_t** err + ) +{ + if (NULL == ifap) { + return -1; + } + + g_debug ("mock_getifaddrs (ifap:%p err:%p)", (gpointer)ifap, (gpointer)err); + + GList* list = mock_interfaces; + int n = g_list_length (list); + struct pgm_ifaddrs_t* ifa = calloc (n, sizeof(struct pgm_ifaddrs_t)); + struct pgm_ifaddrs_t* ift = ifa; + while (list) { + struct mock_interface_t* interface = list->data; + ift->ifa_addr = (gpointer)&interface->addr; + ift->ifa_name = interface->name; + ift->ifa_flags = interface->flags; + ift->ifa_netmask = (gpointer)&interface->netmask; + list = list->next; + if (list) { + ift->ifa_next = ift + 1; + ift = ift->ifa_next; + } + } + + *ifap = ifa; + return TRUE; +} + +void +mock_pgm_freeifaddrs ( + struct pgm_ifaddrs_t* ifa + ) +{ + free (ifa); +} + +unsigned +mock_pgm_if_nametoindex ( + const sa_family_t iffamily, + const char* ifname + ) +{ + GList* list = mock_interfaces; + while (list) { + const struct mock_interface_t* interface = list->data; + if (0 == strcmp (ifname, interface->name)) + return interface->index; + list = list->next; + } + return 0; +} + +char* +mock_if_indextoname ( + unsigned ifindex, + char* ifname + ) +{ + GList* list = mock_interfaces; + while (list) { + const struct mock_interface_t* interface = list->data; + if (interface->index == ifindex) { + strcpy (ifname, interface->name); + return ifname; + } + list = list->next; + } + errno = ENXIO; + return NULL; +} + +int +mock_getnameinfo ( + const struct sockaddr* sa, + socklen_t salen, + char* host, + size_t hostlen, + char* serv, + size_t servlen, + int flags + ) +{ + if ((0 == hostlen && 0 == servlen) || + (NULL == host && NULL == serv)) + return EAI_NONAME; + + if (flags & NI_NUMERICHOST && flags & NI_NAMEREQD) + return EAI_BADFLAGS; + +/* pre-conditions */ + g_assert (NULL != host); + g_assert (hostlen > 0); + g_assert (NULL == serv); + g_assert (0 == servlen); + + const int sa_family = sa->sa_family; + + if (AF_INET == sa_family) + g_assert (sizeof(struct sockaddr_in) == salen); + else { + g_assert (AF_INET6 == sa_family); + g_assert (sizeof(struct sockaddr_in6) == salen); + } + + if (!(flags & NI_NUMERICHOST)) + { + GList* list = mock_hosts; + while (list) { + const struct mock_host_t* _host = list->data; + const int host_family = ((struct sockaddr*)&_host->address)->sa_family; + const size_t host_len = AF_INET == host_family ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); + + if (host_family == sa_family && + host_len == salen && + 0 == memcmp (sa, &_host->address, salen)) + { + if (hostlen < (1 + strlen(_host->canonical_hostname))) + return EAI_OVERFLOW; + strncpy (host, _host->canonical_hostname, hostlen); + return 0; + } + list = list->next; + } + + if (flags & NI_NAMEREQD) + return EAI_NONAME; + } + + if (AF_INET == sa_family) + pgm_inet_ntop (sa_family, &((const struct sockaddr_in*)sa)->sin_addr, host, hostlen); + else { + const unsigned scope = ((const struct sockaddr_in6*)sa)->sin6_scope_id; + pgm_inet_ntop (sa_family, &((const struct sockaddr_in6*)sa)->sin6_addr, host, hostlen); + if (scope) { + char buffer[1+IF_NAMESIZE]; + strcat (host, "%"); + strcat (host, mock_if_indextoname (scope, buffer)); + } + } + return 0; +} + +int +mock_getaddrinfo ( + const char* node, + const char* service, + const struct addrinfo* hints, + struct addrinfo** res + ) +{ + const int ai_flags = hints ? hints->ai_flags : (AI_V4MAPPED | AI_ADDRCONFIG); + const int ai_family = hints ? hints->ai_family : AF_UNSPEC; + GList* list; + struct sockaddr_storage addr; + + if (NULL == node && NULL == service) + return EAI_NONAME; + +/* pre-conditions */ + g_assert (NULL != node); + g_assert (NULL == service); + g_assert (!(ai_flags & AI_CANONNAME)); + g_assert (!(ai_flags & AI_NUMERICSERV)); + g_assert (!(ai_flags & AI_V4MAPPED)); + + g_message ("mock_getaddrinfo (node:%s%s%s service:%s%s%s hints:%p res:%p)", + node ? "\"" : "", node ? node : "(null)", node ? "\"" : "", + service ? "\"" : "", service ? service : "(null)", service ? "\"" : "", + (gpointer)hints, + (gpointer)res); + + gboolean has_ip4_config; + gboolean has_ip6_config; + + if (hints && hints->ai_flags & AI_ADDRCONFIG) + { + has_ip4_config = has_ip6_config = FALSE; + list = mock_interfaces; + while (list) { + const struct mock_interface_t* interface = list->data; + if (AF_INET == ((struct sockaddr*)&interface->addr)->sa_family) + has_ip4_config = TRUE; + else if (AF_INET6 == ((struct sockaddr*)&interface->addr)->sa_family) + has_ip6_config = TRUE; + if (has_ip4_config && has_ip6_config) + break; + list = list->next; + } + } else { + has_ip4_config = has_ip6_config = TRUE; + } + + if (ai_flags & AI_NUMERICHOST) { + pgm_sockaddr_pton (node, (struct sockaddr*)&addr); + } + list = mock_hosts; + while (list) { + struct mock_host_t* host = list->data; + const int host_family = ((struct sockaddr*)&host->address)->sa_family; + if (((strcmp (host->canonical_hostname, node) == 0) || + (host->alias && strcmp (host->alias, node) == 0) || + (ai_flags & AI_NUMERICHOST && + 0 == pgm_sockaddr_cmp ((struct sockaddr*)&addr, (struct sockaddr*)&host->address))) + && + (host_family == ai_family || AF_UNSPEC == ai_family) && + ((AF_INET == host_family && has_ip4_config) || (AF_INET6 == host_family && has_ip6_config))) + { + struct addrinfo* ai = malloc (sizeof(struct addrinfo)); + memset (ai, 0, sizeof(struct addrinfo)); + ai->ai_family = host_family; + ai->ai_addrlen = AF_INET == host_family ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); + ai->ai_addr = (gpointer)&host->address; + *res = ai; + return 0; + } + list = list->next; + } + return EAI_NONAME; +} + +void +mock_freeaddrinfo ( + struct addrinfo* res + ) +{ + free (res); +} + +int +mock_gethostname ( + char* name, + size_t len + ) +{ + if (NULL == name) { + errno = EFAULT; + return -1; + } + if (len < 0) { + errno = EINVAL; + return -1; + } + if (len < (1 + strlen (mock_hostname))) { + errno = ENAMETOOLONG; + return -1; + } +/* force an error */ + if (mock_hostname == mock_toolong) { + errno = ENAMETOOLONG; + return -1; + } + strncpy (name, mock_hostname, len); + if (len > 0) + name[len - 1] = '\0'; + return 0; +} + +struct netent* +mock_getnetbyname ( + const char* name + ) +{ + static struct netent ne; + GList* list = mock_networks; + + if (NULL == name) + return NULL; + + while (list) { + const struct mock_network_t* network = list->data; + if (strcmp (network->name, name) == 0) { + ne.n_name = network->name; + ne.n_aliases = network->aliases; + ne.n_addrtype = AF_INET; + ne.n_net = g_ntohl (((struct sockaddr_in*)&network->number)->sin_addr.s_addr); + return ≠ + } + list = list->next; + } + return NULL; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_if_getnodeaddr ( + const sa_family_t family, + struct sockaddr* addr, + const socklen_t cnt, + pgm_error_t** error + ) +{ + switch (family) { + case AF_UNSPEC: + case AF_INET: + ((struct sockaddr*)addr)->sa_family = AF_INET; + ((struct sockaddr_in*)addr)->sin_addr.s_addr = inet_addr(MOCK_ADDRESS); + break; + case AF_INET6: + ((struct sockaddr*)addr)->sa_family = AF_INET6; + ((struct sockaddr_in6*)addr)->sin6_addr = mock_address6_addr; + break; + default: + g_assert_not_reached(); + } + return TRUE; +} + +/* following tests will use AF_UNSPEC address family */ + +static +void +mock_setup_unspec (void) +{ + mock_family = AF_UNSPEC; +} + +/* following tests will use AF_INET address family */ + +static +void +mock_setup_ip4 (void) +{ + mock_family = AF_INET; +} + +/* following tests will use AF_INET6 address family */ + +static +void +mock_setup_ip6 (void) +{ + mock_family = AF_INET6; +} + + +/* return 0 if gsr multicast group does not match the default PGM group for + * the address family, return -1 on no match. + */ + +static +gboolean +match_default_group ( + const int ai_family, + const struct group_source_req* gsr + ) +{ + const struct sockaddr_in sa_default = { + .sin_family = AF_INET, + .sin_addr.s_addr = g_htonl (MOCK_GROUP) + }; + const struct sockaddr_in6 sa6_default = { + .sin6_family = AF_INET6, + .sin6_addr = MOCK_GROUP6_INIT + }; + gboolean is_match = FALSE; + + switch (ai_family) { + case AF_UNSPEC: + case AF_INET: + is_match = (0 == pgm_sockaddr_cmp ((struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&sa_default)); + if (!is_match) { + char addr1[INET6_ADDRSTRLEN], addr2[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&gsr->gsr_group, addr1, sizeof(addr1)); + pgm_sockaddr_ntop ((struct sockaddr*)&sa_default, addr2, sizeof(addr2)); + g_message ("FALSE == cmp(%s%s%s, default-group %s%s%s)", + addr1 ? "\"" : "", addr1 ? addr1 : "(null)", addr1 ? "\"" : "", + addr2 ? "\"" : "", addr2 ? addr2 : "(null)", addr2 ? "\"" : ""); + } + break; + case AF_INET6: + is_match = (0 == pgm_sockaddr_cmp ((struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&sa6_default)); + if (!is_match) { + char addr1[INET6_ADDRSTRLEN], addr2[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&gsr->gsr_group, addr1, sizeof(addr1)); + pgm_sockaddr_ntop ((struct sockaddr*)&sa6_default, addr2, sizeof(addr2)); + g_message ("FALSE == cmp(%s%s%s, default-group %s%s%s)", + addr1 ? "\"" : "", addr1 ? addr1 : "(null)", addr1 ? "\"" : "", + addr2 ? "\"" : "", addr2 ? addr2 : "(null)", addr2 ? "\"" : ""); + } + default: + break; + } + return is_match; +} + +/* return 0 if gsr source inteface does not match the INADDR_ANY reserved + * address, return -1 on no match. + */ + +static +int +match_default_source ( + const int ai_family, + const struct group_source_req* gsr + ) +{ + if (0 != gsr->gsr_interface) + return FALSE; + +/* ASM: source == group */ + return (0 == pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&gsr->gsr_source)); +} + +/* return 0 if gsr source interface does not match the hosts default interface, + * return -1 on mismatch + */ + +static +int +match_default_interface ( + const int ai_family, + const struct group_source_req* gsr + ) +{ + if (MOCK_INTERFACE_INDEX != gsr->gsr_interface) + return FALSE; + +/* ASM: source == group */ + return (0 == pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&gsr->gsr_source)); +} + +/* target: + * bool + * pgm_getaddrinfo ( + * const char* s, + * const struct pgm_addrinfo_t* const hints, + * struct pgm_addrinfo_t** res, + * pgm_error_t** err + * ) + */ + +struct test_case_t { + const char* ip4; + const char* ip6; +}; + +#define IP4_AND_IP6(x) x, x + +static const struct test_case_t cases_001[] = { + { IP4_AND_IP6("") }, + { IP4_AND_IP6(";") }, + { IP4_AND_IP6(";;") }, + { "239.192.0.1", "ff08::1" }, + { "239.192.0.1", "[ff08::1]" }, + { ";239.192.0.1", ";ff08::1" }, + { ";239.192.0.1", ";[ff08::1]" }, + { ";239.192.0.1;239.192.0.1", ";ff08::1;ff08::1" }, + { ";239.192.0.1;239.192.0.1", ";[ff08::1];[ff08::1]" }, + { "PGM.MCAST.NET", "IP6-PGM.MCAST.NET" }, + { ";PGM.MCAST.NET", ";IP6-PGM.MCAST.NET" }, + { ";PGM.MCAST.NET;PGM.MCAST.NET", ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, + { ";239.192.0.1;PGM.MCAST.NET", ";ff08::1;IP6-PGM.MCAST.NET" }, + { ";239.192.0.1;PGM.MCAST.NET", ";[ff08::1];IP6-PGM.MCAST.NET" }, + { ";PGM.MCAST.NET;239.192.0.1", ";IP6-PGM.MCAST.NET;ff08::1" }, + { ";PGM.MCAST.NET;239.192.0.1", ";IP6-PGM.MCAST.NET;[ff08::1]" }, + { "pgm-private", /* ‡ */ "pgm-ip6-private" }, + { ";pgm-private", /* ‡ */ ";pgm-ip6-private" }, + { ";pgm-private;pgm-private", /* ‡ */ ";pgm-ip6-private;pgm-ip6-private" }, + { ";PGM.MCAST.NET;pgm-private", /* ‡ */ ";IP6-PGM.MCAST.NET;pgm-ip6-private" }, + { ";pgm-private;PGM.MCAST.NET", /* ‡ */ ";pgm-ip6-private;IP6-PGM.MCAST.NET" }, + { ";239.192.0.1;pgm-private", /* ‡ */ ";ff08::1;pgm-ip6-private" }, + { ";239.192.0.1;pgm-private", /* ‡ */ ";[ff08::1];pgm-ip6-private" }, + { ";pgm-private;239.192.0.1", /* ‡ */ ";pgm-ip6-private;ff08::1" }, + { ";pgm-private;239.192.0.1", /* ‡ */ ";pgm-ip6-private;[ff08::1]" }, +}; + +START_TEST (test_parse_transport_pass_001) +{ + fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); + + const char* s = (mock_family == AF_INET6) ? cases_001[_i].ip6 : cases_001[_i].ip4; + struct pgm_addrinfo_t hints = { + .ai_family = mock_family + }, *res = NULL; + pgm_error_t* err = NULL; + + g_message ("%i: test_parse_transport_001(%s, %s%s%s)", + _i, + (mock_family == AF_INET6) ? "AF_INET6" : ( (mock_family == AF_INET) ? "AF_INET" : "AF_UNSPEC" ), + s ? "\"" : "", s ? s : "(null)", s ? "\"" : ""); + +/* ‡ Linux does not support IPv6 /etc/networks so IPv6 entries appear as 255.255.255.255 and + * pgm_if_parse_transport will fail. + */ +#ifndef CONFIG_HAVE_IP6_NETWORKS + if (NULL != strstr (s, MOCK_NETWORK6) || NULL != strstr (s, MOCK_PGM_NETWORK6)) + { + g_message ("IPv6 exception, /etc/networks not supported on this platform."); + return; + } +#endif + + gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); + if (!retval) { + g_message ("pgm_getaddrinfo: %s", + (err && err->message) ? err->message : "(null)"); + } + fail_unless (TRUE == retval, "pgm_getaddrinfo failed"); + fail_if (NULL == res, "no result"); + fail_unless (NULL == err, "error raised"); + + fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); + fail_unless (match_default_group (mock_family, &res->ai_recv_addrs[0]), "receive address not match default group"); + fail_unless (match_default_source (mock_family, &res->ai_recv_addrs[0]), "receive address not match default source"); + fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); + fail_unless (match_default_group (mock_family, &res->ai_send_addrs[0]), "send address not match default group"); + fail_unless (match_default_source (mock_family, &res->ai_send_addrs[0]), "send address not match default source"); +} +END_TEST + +/* interface name + * + * pre-condition: interface defined to match running host + * ipv4 and ipv6 hostnames are different, otherwise "" tests might go unexpected. + */ + +static const struct test_case_t cases_002[] = { + { MOCK_INTERFACE, /* † */ MOCK_INTERFACE }, + { MOCK_INTERFACE ";", /* † */ MOCK_INTERFACE ";" }, + { MOCK_INTERFACE ";;", /* † */ MOCK_INTERFACE ";;" }, + { MOCK_INTERFACE ";239.192.0.1", /* † */ MOCK_INTERFACE ";ff08::1" }, + { MOCK_INTERFACE ";239.192.0.1", /* † */ MOCK_INTERFACE ";[ff08::1]" }, + { MOCK_INTERFACE ";239.192.0.1;239.192.0.1", /* † */ MOCK_INTERFACE ";ff08::1;ff08::1" }, + { MOCK_INTERFACE ";239.192.0.1;239.192.0.1", /* † */ MOCK_INTERFACE ";[ff08::1];[ff08::1]" }, + { MOCK_INTERFACE ";PGM.MCAST.NET", /* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET" }, + { MOCK_INTERFACE ";PGM.MCAST.NET;PGM.MCAST.NET",/* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, + { MOCK_INTERFACE ";239.192.0.1;PGM.MCAST.NET", /* † */ MOCK_INTERFACE ";ff08::1;IP6-PGM.MCAST.NET" }, + { MOCK_INTERFACE ";239.192.0.1;PGM.MCAST.NET", /* † */ MOCK_INTERFACE ";[ff08::1];IP6-PGM.MCAST.NET" }, + { MOCK_INTERFACE ";PGM.MCAST.NET;239.192.0.1", /* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET;ff08::1" }, + { MOCK_INTERFACE ";PGM.MCAST.NET;239.192.0.1", /* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET;[ff08::1]" }, + { MOCK_INTERFACE ";pgm-private", /* ‡ */ MOCK_INTERFACE ";pgm-ip6-private" }, + { MOCK_INTERFACE ";pgm-private;pgm-private", /* ‡ */ MOCK_INTERFACE ";pgm-ip6-private;pgm-ip6-private" }, + { MOCK_ADDRESS, MOCK_ADDRESS6 }, + { MOCK_ADDRESS, "[" MOCK_ADDRESS6 "]" }, + { MOCK_ADDRESS ";", MOCK_ADDRESS6 ";" }, + { MOCK_ADDRESS ";", "[" MOCK_ADDRESS6 "];" }, + { MOCK_ADDRESS ";;", MOCK_ADDRESS6 ";;" }, + { MOCK_ADDRESS ";;", "[" MOCK_ADDRESS6 "];;" }, + { MOCK_ADDRESS ";239.192.0.1", MOCK_ADDRESS6 ";ff08::1" }, + { MOCK_ADDRESS ";239.192.0.1", "[" MOCK_ADDRESS6 "];[ff08::1]" }, + { MOCK_ADDRESS ";239.192.0.1;239.192.0.1", MOCK_ADDRESS6 ";ff08::1;ff08::1" }, + { MOCK_ADDRESS ";239.192.0.1;239.192.0.1", "[" MOCK_ADDRESS6 "];[ff08::1];[ff08::1]" }, + { MOCK_ADDRESS ";PGM.MCAST.NET", MOCK_ADDRESS6 ";IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS ";PGM.MCAST.NET", "[" MOCK_ADDRESS6 "];IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS ";PGM.MCAST.NET;PGM.MCAST.NET", MOCK_ADDRESS6 ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS ";PGM.MCAST.NET;PGM.MCAST.NET", "[" MOCK_ADDRESS6 "];IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS ";239.192.0.1;PGM.MCAST.NET", MOCK_ADDRESS6 ";ff08::1;IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS ";239.192.0.1;PGM.MCAST.NET", "[" MOCK_ADDRESS6 "];[ff08::1];IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS ";PGM.MCAST.NET;239.192.0.1", MOCK_ADDRESS6 ";IP6-PGM.MCAST.NET;ff08::1" }, + { MOCK_ADDRESS ";PGM.MCAST.NET;239.192.0.1", "[" MOCK_ADDRESS6 "];IP6-PGM.MCAST.NET;[ff08::1]" }, + { MOCK_ADDRESS ";pgm-private", MOCK_ADDRESS6 ";pgm-ip6-private" }, + { MOCK_ADDRESS ";pgm-private", "[" MOCK_ADDRESS6 "];pgm-ip6-private" }, + { MOCK_ADDRESS ";pgm-private;pgm-private", MOCK_ADDRESS6 ";pgm-ip6-private;pgm-ip6-private" }, + { MOCK_ADDRESS ";pgm-private;pgm-private", "[" MOCK_ADDRESS6 "];pgm-ip6-private;pgm-ip6-private" }, + { MOCK_NETWORK, /* ‡ */ MOCK_NETWORK6 }, + { MOCK_NETWORK ";", /* ‡ */ MOCK_NETWORK6 ";" }, + { MOCK_NETWORK ";;", /* ‡ */ MOCK_NETWORK6 ";;" }, + { MOCK_NETWORK ";239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";ff08::1" }, + { MOCK_NETWORK ";239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";[ff08::1]" }, + { MOCK_NETWORK ";239.192.0.1;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";ff08::1;ff08::1" }, + { MOCK_NETWORK ";239.192.0.1;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";[ff08::1];[ff08::1]" }, + { MOCK_NETWORK ";PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET" }, + { MOCK_NETWORK ";PGM.MCAST.NET;PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, + { MOCK_NETWORK ";239.192.0.1;PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";ff08::1;IP6-PGM.MCAST.NET" }, + { MOCK_NETWORK ";239.192.0.1;PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";[ff08::1];IP6-PGM.MCAST.NET" }, + { MOCK_NETWORK ";PGM.MCAST.NET;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET;ff08::1" }, + { MOCK_NETWORK ";PGM.MCAST.NET;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET;[ff08::1]" }, + { MOCK_NETWORK ";pgm-private", /* ‡ */ MOCK_NETWORK6 ";pgm-ip6-private" }, + { MOCK_NETWORK ";pgm-private;pgm-private", /* ‡ */ MOCK_NETWORK6 ";pgm-ip6-private;pgm-ip6-private" }, + { MOCK_HOSTNAME, MOCK_HOSTNAME6 }, + { MOCK_HOSTNAME ";", MOCK_HOSTNAME6 ";" }, + { MOCK_HOSTNAME ";;", MOCK_HOSTNAME6 ";;" }, + { MOCK_HOSTNAME ";239.192.0.1", MOCK_HOSTNAME6 ";ff08::1" }, + { MOCK_HOSTNAME ";239.192.0.1", MOCK_HOSTNAME6 ";[ff08::1]" }, + { MOCK_HOSTNAME ";239.192.0.1;239.192.0.1", MOCK_HOSTNAME6 ";ff08::1;ff08::1" }, + { MOCK_HOSTNAME ";239.192.0.1;239.192.0.1", MOCK_HOSTNAME6 ";[ff08::1];[ff08::1]" }, + { MOCK_HOSTNAME ";PGM.MCAST.NET", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET" }, + { MOCK_HOSTNAME ";PGM.MCAST.NET;PGM.MCAST.NET", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, + { MOCK_HOSTNAME ";239.192.0.1;PGM.MCAST.NET", MOCK_HOSTNAME6 ";ff08::1;IP6-PGM.MCAST.NET" }, + { MOCK_HOSTNAME ";239.192.0.1;PGM.MCAST.NET", MOCK_HOSTNAME6 ";[ff08::1];IP6-PGM.MCAST.NET" }, + { MOCK_HOSTNAME ";PGM.MCAST.NET;239.192.0.1", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET;ff08::1" }, + { MOCK_HOSTNAME ";PGM.MCAST.NET;239.192.0.1", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET;[ff08::1]" }, + { MOCK_HOSTNAME ";pgm-private", MOCK_HOSTNAME6 ";pgm-ip6-private" }, + { MOCK_HOSTNAME ";pgm-private;pgm-private", MOCK_HOSTNAME6 ";pgm-ip6-private;pgm-ip6-private" }, +}; + +START_TEST (test_parse_transport_pass_002) +{ + fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); + + const char* s = (mock_family == AF_INET6) ? cases_002[_i].ip6 : cases_002[_i].ip4; + struct pgm_addrinfo_t hints = { + .ai_family = mock_family + }, *res = NULL; + pgm_error_t* err = NULL; + + g_message ("%i: test_parse_transport_002(%s, %s%s%s)", + _i, + (mock_family == AF_INET6) ? "AF_INET6" : ( (mock_family == AF_INET) ? "AF_INET" : "AF_UNSPEC" ), + s ? "\"" : "", s ? s : "(null)", s ? "\"" : ""); + +/* ‡ Linux does not support IPv6 /etc/networks so IPv6 entries appear as 255.255.255.255 and + * pgm_if_parse_transport will fail. + */ +#ifndef CONFIG_HAVE_IP6_NETWORKS + if (NULL != strstr (s, MOCK_NETWORK6) || NULL != strstr (s, MOCK_PGM_NETWORK6)) + { + g_message ("IPv6 exception, /etc/networks not supported on this platform."); + return; + } +#endif + +/* † Multiple scoped IPv6 interfaces match a simple interface name network parameter and so + * pgm-if_parse_transport will fail finding multiple matching interfaces + */ + if (AF_INET6 == mock_family && 0 == strncmp (s, MOCK_INTERFACE, strlen (MOCK_INTERFACE))) + { + g_message ("IPv6 exception, multiple scoped addresses on one interface"); + fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); + fail_unless (NULL == res, "unexpected result"); + fail_if (NULL == err, "error not raised"); + fail_unless (PGM_ERROR_NOTUNIQ == err->code, "interfaces not found unique"); + return; + } + + fail_unless (TRUE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); + fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); + fail_unless (match_default_group (mock_family, &res->ai_recv_addrs[0]), "receive address not match default group"); + fail_unless (match_default_interface (mock_family, &res->ai_recv_addrs[0]), "receive address not match default interface"); + fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); + fail_unless (match_default_group (mock_family, &res->ai_send_addrs[0]), "send address not match default group"); + fail_unless (match_default_interface (mock_family, &res->ai_send_addrs[0]), "send address not match default interface"); +} +END_TEST + +/* network to node address in bits, 8-32 + * + * e.g. 127.0.0.1/16 + */ + +static const struct test_case_t cases_003[] = { + { MOCK_ADDRESS "/24", MOCK_ADDRESS6 "/64" }, + { MOCK_ADDRESS "/24;", MOCK_ADDRESS6 "/64;" }, + { MOCK_ADDRESS "/24;;", MOCK_ADDRESS6 "/64;;" }, + { MOCK_ADDRESS "/24;239.192.0.1", MOCK_ADDRESS6 "/64;ff08::1" }, + { MOCK_ADDRESS "/24;239.192.0.1", MOCK_ADDRESS6 "/64;[ff08::1]" }, + { MOCK_ADDRESS "/24;239.192.0.1;239.192.0.1", MOCK_ADDRESS6 "/64;ff08::1;ff08::1" }, + { MOCK_ADDRESS "/24;239.192.0.1;239.192.0.1", MOCK_ADDRESS6 "/64;[ff08::1];[ff08::1]" }, + { MOCK_ADDRESS "/24;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS "/24;PGM.MCAST.NET;PGM.MCAST.NET",MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS "/24;239.192.0.1;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;ff08::1;IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS "/24;239.192.0.1;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;[ff08::1];IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS "/24;PGM.MCAST.NET;239.192.0.1", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;ff08::1" }, + { MOCK_ADDRESS "/24;PGM.MCAST.NET;239.192.0.1", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;[ff08::1]" }, + { MOCK_ADDRESS "/24;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS "/24;PGM.MCAST.NET;PGM.MCAST.NET",MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, + { MOCK_ADDRESS "/24;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private" }, + { MOCK_ADDRESS "/24;pgm-private;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;pgm-ip6-private" }, + { MOCK_ADDRESS "/24;239.192.0.1;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;ff08::1;pgm-ip6-private" }, + { MOCK_ADDRESS "/24;239.192.0.1;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;[ff08::1];pgm-ip6-private" }, + { MOCK_ADDRESS "/24;pgm-private;239.192.0.1", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;ff08::1" }, + { MOCK_ADDRESS "/24;pgm-private;239.192.0.1", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;[ff08::1]" }, + { MOCK_ADDRESS "/24;PGM.MCAST.NET;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;pgm-ip6-private" }, + { MOCK_ADDRESS "/24;pgm-private;PGM.MCAST.NET", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;IP6-PGM.MCAST.NET" }, +}; + +START_TEST (test_parse_transport_pass_003) +{ + fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); + + const char* s = (mock_family == AF_INET6) ? cases_003[_i].ip6 : cases_003[_i].ip4; + struct pgm_addrinfo_t hints = { + .ai_family = mock_family + }, *res = NULL; + pgm_error_t* err = NULL; + + g_message ("%i: test_parse_transport_003(%s, %s%s%s)", + _i, + (mock_family == AF_INET6) ? "AF_INET6" : ( (mock_family == AF_INET) ? "AF_INET" : "AF_UNSPEC" ), + s ? "\"" : "", s ? s : "(null)", s ? "\"" : ""); + +/* ‡ Linux does not support IPv6 /etc/networks so IPv6 entries appear as 255.255.255.255 and + * pgm_if_parse_transport will fail. + */ +#ifndef CONFIG_HAVE_IP6_NETWORKS + if (NULL != strstr (s, MOCK_NETWORK6) || NULL != strstr (s, MOCK_PGM_NETWORK6)) + { + g_message ("IPv6 exception, /etc/networks not supported on this platform."); + return; + } +#endif + + gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); + if (!retval) { + g_message ("pgm_getaddrinfo: %s", + (err && err->message) ? err->message : "(null)"); + } + fail_unless (TRUE == retval, "pgm_getaddrinfo failed"); + fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); + fail_unless (match_default_group (mock_family, &res->ai_recv_addrs[0]), "receive address not match default group"); + fail_unless (match_default_interface (mock_family, &res->ai_recv_addrs[0]), "receive address not match default interface"); + fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); + fail_unless (match_default_group (mock_family, &res->ai_send_addrs[0]), "send address not match default group"); + fail_unless (match_default_interface (mock_family, &res->ai_send_addrs[0]), "send address not match default interface"); +} +END_TEST + +/* asymmetric groups + */ + +START_TEST (test_parse_transport_pass_004) +{ + fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); + + const char* s = (mock_family == AF_INET6) ? ";ff08::1;ff08::2" + /* AF_INET */: ";239.192.56.1;239.192.56.2"; + struct pgm_addrinfo_t hints = { + .ai_family = mock_family + }, *res = NULL; + pgm_error_t* err = NULL; + struct sockaddr_storage addr; + + fail_unless (TRUE == pgm_getaddrinfo (s, &hints, &res, &err), "get_transport_info failed"); + fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); + fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); + if (mock_family == AF_INET6) + { + inet_pton (AF_INET6, "ff08::1", &((struct sockaddr_in6*)&addr)->sin6_addr); + ((struct sockaddr*)&addr)->sa_family = mock_family; + ((struct sockaddr_in6*)&addr)->sin6_port = 0; + ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; + ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; + fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); + inet_pton (AF_INET6, "ff08::2", &((struct sockaddr_in6*)&addr)->sin6_addr); + ((struct sockaddr*)&addr)->sa_family = mock_family; + ((struct sockaddr_in6*)&addr)->sin6_port = 0; + ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; + ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; + fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); + } else { + inet_pton (AF_INET, "239.192.56.1", &((struct sockaddr_in*)&addr)->sin_addr); + ((struct sockaddr*)&addr)->sa_family = AF_INET; + fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); + inet_pton (AF_INET, "239.192.56.2", &((struct sockaddr_in*)&addr)->sin_addr); + ((struct sockaddr*)&addr)->sa_family = AF_INET; + fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); + } + fail_unless (match_default_source (mock_family, &res->ai_recv_addrs[0]), "source not match"); + fail_unless (match_default_source (mock_family, &res->ai_send_addrs[0]), "source not match"); +} +END_TEST + +/* multiple receive groups and asymmetric sending + */ + +START_TEST (test_parse_transport_pass_005) +{ + fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); + + const char* s = (mock_family == AF_INET6) ? ";ff08::1,ff08::2;ff08::3" + /* AF_INET */: ";239.192.56.1,239.192.56.2;239.192.56.3"; + struct pgm_addrinfo_t hints = { + .ai_family = mock_family + }, *res = NULL; + pgm_error_t* err = NULL; + struct sockaddr_storage addr; + + fail_unless (TRUE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); + fail_unless (2 == res->ai_recv_addrs_len, "not exactly one receive address"); + fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); + if (mock_family == AF_INET6) + { + inet_pton (AF_INET6, "ff08::1", &((struct sockaddr_in6*)&addr)->sin6_addr); + ((struct sockaddr*)&addr)->sa_family = mock_family; + ((struct sockaddr_in6*)&addr)->sin6_port = 0; + ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; + ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; + fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); + inet_pton (AF_INET6, "ff08::2", &((struct sockaddr_in6*)&addr)->sin6_addr); + ((struct sockaddr*)&addr)->sa_family = mock_family; + ((struct sockaddr_in6*)&addr)->sin6_port = 0; + ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; + ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; + fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[1].gsr_group, (struct sockaddr*)&addr), "group not match"); + inet_pton (AF_INET6, "ff08::3", &((struct sockaddr_in6*)&addr)->sin6_addr); + ((struct sockaddr*)&addr)->sa_family = mock_family; + ((struct sockaddr_in6*)&addr)->sin6_port = 0; + ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; + ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; + fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); + } else { + inet_pton (AF_INET, "239.192.56.1", &((struct sockaddr_in*)&addr)->sin_addr); + ((struct sockaddr*)&addr)->sa_family = AF_INET; + fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); + inet_pton (AF_INET, "239.192.56.2", &((struct sockaddr_in*)&addr)->sin_addr); + ((struct sockaddr*)&addr)->sa_family = AF_INET; + fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[1].gsr_group, (struct sockaddr*)&addr), "group not match"); + inet_pton (AF_INET, "239.192.56.3", &((struct sockaddr_in*)&addr)->sin_addr); + ((struct sockaddr*)&addr)->sa_family = AF_INET; + fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); + } + fail_unless (match_default_source (mock_family, &res->ai_recv_addrs[0]), "source not match"); + fail_unless (match_default_source (mock_family, &res->ai_send_addrs[0]), "source not match"); +} +END_TEST + + +/* too many interfaces + */ +START_TEST (test_parse_transport_fail_001) +{ + const char* s = "eth0,lo;;;"; + struct pgm_addrinfo_t hints = { + .ai_family = AF_UNSPEC + }, *res = NULL; + pgm_error_t* err = NULL; + + fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); + fail_unless (NULL == res, "unexpected result"); +} +END_TEST + +/* invalid characters, or simply just bogus + */ +START_TEST (test_parse_transport_fail_002) +{ + const char* s = "!@#$%^&*()"; + struct pgm_addrinfo_t hints = { + .ai_family = AF_UNSPEC + }, *res = NULL; + pgm_error_t* err = NULL; + + fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); + fail_unless (NULL == res, "unexpected result"); +} +END_TEST + +/* too many groups + */ +START_TEST (test_parse_transport_fail_003) +{ + const char* s = ";239.192.0.1,239.192.0.2,239.192.0.3,239.192.0.4,239.192.0.5,239.192.0.6,239.192.0.7,239.192.0.8,239.192.0.9,239.192.0.10,239.192.0.11,239.192.0.12,239.192.0.13,239.192.0.14,239.192.0.15,239.192.0.16,239.192.0.17,239.192.0.18,239.192.0.19,239.192.0.20;239.192.0.21"; + struct pgm_addrinfo_t hints = { + .ai_family = AF_UNSPEC + }, *res = NULL; + pgm_error_t* err = NULL; + + fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); + fail_unless (NULL == res, "unexpected result"); +} +END_TEST + +/* too many receiver groups in asymmetric pairing + */ +START_TEST (test_parse_transport_fail_004) +{ + const char* s = ";239.192.0.1,239.192.0.2,239.192.0.3,239.192.0.4,239.192.0.5,239.192.0.6,239.192.0.7,239.192.0.8,239.192.0.9,239.192.0.10,239.192.0.11,239.192.0.12,239.192.0.13,239.192.0.14,239.192.0.15,239.192.0.16,239.192.0.17,239.192.0.18,239.192.0.19,239.192.0.20,239.192.0.21;239.192.0.22"; + struct pgm_addrinfo_t hints = { + .ai_family = AF_UNSPEC + }, *res = NULL; + pgm_error_t* err = NULL; + + fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); + fail_unless (NULL == res, "unexpected result"); +} +END_TEST + +/* null string + */ +START_TEST (test_parse_transport_fail_005) +{ + const char* s = NULL; + struct pgm_addrinfo_t hints = { + .ai_family = AF_UNSPEC + }, *res = NULL; + pgm_error_t* err = NULL; + + fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); + fail_unless (NULL == res, "unexpected result"); +} +END_TEST + +/* invalid address family + */ +START_TEST (test_parse_transport_fail_006) +{ + const char* s = ";"; + struct pgm_addrinfo_t hints = { + .ai_family = AF_IPX + }, *res = NULL; + pgm_error_t* err = NULL; + + fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); + fail_unless (NULL == res, "unexpected result"); +} +END_TEST + +/* invalid transport info pointer + */ +START_TEST (test_parse_transport_fail_007) +{ + const char* s = ";"; + pgm_error_t* err = NULL; + + fail_unless (FALSE == pgm_getaddrinfo (s, NULL, NULL, &err), "pgm_getaddrinfo failed"); +} +END_TEST + +/* invalid interface + */ +START_TEST (test_parse_transport_fail_008) +{ + const char* s = "qe0;"; + struct pgm_addrinfo_t hints = { + .ai_family = AF_UNSPEC + }, *res = NULL; + pgm_error_t* err = NULL; + + gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); + if (!retval) { + g_message ("pgm_getaddrinfo: %s", err ? err->message : "(null)"); + } + fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); + fail_unless (NULL == res, "unexpected result"); +} +END_TEST + +/* non-existing interface IP address + */ +START_TEST (test_parse_transport_fail_009) +{ + const char* s = "172.16.90.1;"; + struct pgm_addrinfo_t hints = { + .ai_family = AF_UNSPEC + }, *res = NULL; + pgm_error_t* err = NULL; + + gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); + if (!retval) { + g_message ("pgm_getaddrinfo: %s", + (err && err->message) ? err->message : "(null)"); + } + fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); + fail_unless (NULL == res, "unexpected result"); +} +END_TEST + +/* non-existing network name address + */ +START_TEST (test_parse_transport_fail_010) +{ + const char* s = "private2;"; + struct pgm_addrinfo_t hints = { + .ai_family = AF_UNSPEC + }, *res = NULL; + pgm_error_t* err = NULL; + + gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); + if (!retval) { + g_message ("pgm_getaddrinfo: %s", + (err && err->message) ? err->message : "(null)"); + } + fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); + fail_unless (NULL == res, "unexpected result"); +} +END_TEST + +/* non-existing host name interface + */ +START_TEST (test_parse_transport_fail_011) +{ + const char* s = "mi-hee.ko.miru.hk;"; + struct pgm_addrinfo_t hints = { + .ai_family = AF_UNSPEC + }, *res = NULL; + pgm_error_t* err = NULL; + + gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); + if (!retval) { + g_message ("pgm_getaddrinfo: %s", + (err && err->message) ? err->message : "(null)"); + } + fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); + fail_unless (NULL == res, "unexpected result"); +} +END_TEST + +/* target: + * pgm_if_print_all (void) + */ + +START_TEST (test_print_all_pass_001) +{ + pgm_if_print_all (); +} +END_TEST + + +/* target: + * bool + * is_in_net ( + * const struct in_addr* addr, -- in host byte order + * const struct in_addr* netaddr, + * const struct in_addr* netmask + * ) + */ + +struct test_case_net_t { + const char* addr; + const char* netaddr; + const char* netmask; + const gboolean answer; +}; + +static const struct test_case_net_t cases_004[] = { + { "127.0.0.1", "127.0.0.1", "255.0.0.0", TRUE }, + { "127.0.0.1", "127.0.0.1", "255.255.0.0", TRUE }, + { "127.0.0.1", "127.0.0.1", "255.255.255.0", TRUE }, + { "127.0.0.1", "127.0.0.1", "255.255.255.255", TRUE }, + { "127.0.0.1", "127.0.0.0", "255.0.0.0", TRUE }, + { "127.0.0.1", "127.0.0.0", "255.255.0.0", TRUE }, + { "127.0.0.1", "127.0.0.0", "255.255.255.0", TRUE }, + { "127.0.0.1", "127.0.0.0", "255.255.255.255", FALSE }, + { "172.15.1.1", "172.16.0.0", "255.240.0.0", FALSE }, + { "172.16.1.1", "172.16.0.0", "255.240.0.0", TRUE }, + { "172.18.1.1", "172.16.0.0", "255.240.0.0", TRUE }, + { "172.31.1.1", "172.16.0.0", "255.240.0.0", TRUE }, + { "172.32.1.1", "172.16.0.0", "255.240.0.0", FALSE }, +}; + +START_TEST (test_is_in_net_pass_001) +{ + struct in_addr addr, netaddr, netmask; + fail_unless (pgm_inet_pton (AF_INET, cases_004[_i].addr, &addr)); + fail_unless (pgm_inet_pton (AF_INET, cases_004[_i].netaddr, &netaddr)); + fail_unless (pgm_inet_pton (AF_INET, cases_004[_i].netmask, &netmask)); + const gboolean answer = cases_004[_i].answer; + + addr.s_addr = g_ntohl (addr.s_addr); + netaddr.s_addr = g_ntohl (netaddr.s_addr); + netmask.s_addr = g_ntohl (netmask.s_addr); + gboolean result = is_in_net (&addr, &netaddr, &netmask); + + g_message ("result %s (%s)", + result ? "TRUE" : "FALSE", + answer ? "TRUE" : "FALSE"); + + fail_unless (answer == result); +} +END_TEST + +static const struct test_case_net_t cases_005[] = { + { "::1", "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", TRUE }, + { "fe80::203:baff:fe4e:6cc8", "fe80::", "ffff:0000:0000:0000:0000:0000:0000:0000", TRUE }, + { "2002:dec8:d28e::36", "2002:dec8:d28e::", "ffff:ffff:ffff:0000:0000:0000:0000:0000", TRUE }, + { "2002:dec8:d28e::36", "2002:dafa:939:0::", "ffff:ffff:ffff:ffff:0000:0000:0000:0000", FALSE }, +}; + +START_TEST (test_is_in_net6_pass_001) +{ + struct in6_addr addr, netaddr, netmask; + fail_unless (pgm_inet_pton (AF_INET6, cases_005[_i].addr, &addr)); + fail_unless (pgm_inet_pton (AF_INET6, cases_005[_i].netaddr, &netaddr)); + fail_unless (pgm_inet_pton (AF_INET6, cases_005[_i].netmask, &netmask)); + const gboolean answer = cases_005[_i].answer; + + gboolean result = is_in_net6 (&addr, &netaddr, &netmask); + + g_message ("result %s (%s)", + result ? "TRUE" : "FALSE", + answer ? "TRUE" : "FALSE"); + + fail_unless (answer == result); +} +END_TEST + + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_is_in_net = tcase_create ("is_in_net"); + suite_add_tcase (s, tc_is_in_net); + tcase_add_checked_fixture (tc_is_in_net, mock_setup_net, mock_teardown_net); + tcase_add_checked_fixture (tc_is_in_net, mock_setup_unspec, NULL); + tcase_add_loop_test (tc_is_in_net, test_is_in_net_pass_001, 0, G_N_ELEMENTS(cases_004)); + + TCase* tc_is_in_net6 = tcase_create ("is_in_net6"); + suite_add_tcase (s, tc_is_in_net6); + tcase_add_checked_fixture (tc_is_in_net6, mock_setup_net, mock_teardown_net); + tcase_add_checked_fixture (tc_is_in_net6, mock_setup_unspec, NULL); + tcase_add_loop_test (tc_is_in_net6, test_is_in_net6_pass_001, 0, G_N_ELEMENTS(cases_005)); + +/* three variations of all parse-transport tests, one for each valid + * address family value: AF_UNSPEC, AF_INET, AF_INET6. + */ + +/* unspecified address family, ai_family == AF_UNSPEC */ + TCase* tc_parse_transport_unspec = tcase_create ("parse_transport/unspec"); + suite_add_tcase (s, tc_parse_transport_unspec); + tcase_add_checked_fixture (tc_parse_transport_unspec, mock_setup_net, mock_teardown_net); + tcase_add_checked_fixture (tc_parse_transport_unspec, mock_setup_unspec, NULL); + tcase_add_loop_test (tc_parse_transport_unspec, test_parse_transport_pass_001, 0, G_N_ELEMENTS(cases_001)); + tcase_add_loop_test (tc_parse_transport_unspec, test_parse_transport_pass_002, 0, G_N_ELEMENTS(cases_002)); + tcase_add_loop_test (tc_parse_transport_unspec, test_parse_transport_pass_003, 0, G_N_ELEMENTS(cases_003)); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_pass_004); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_pass_005); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_001); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_002); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_003); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_004); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_005); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_006); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_007); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_008); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_009); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_010); + tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_011); + +/* IP version 4, ai_family = AF_INET */ + TCase* tc_parse_transport_ip4 = tcase_create ("parse_transport/af_inet"); + suite_add_tcase (s, tc_parse_transport_ip4); + tcase_add_checked_fixture (tc_parse_transport_ip4, mock_setup_net, mock_teardown_net); + tcase_add_checked_fixture (tc_parse_transport_ip4, mock_setup_ip4, NULL); + tcase_add_loop_test (tc_parse_transport_ip4, test_parse_transport_pass_001, 0, G_N_ELEMENTS(cases_001)); + tcase_add_loop_test (tc_parse_transport_ip4, test_parse_transport_pass_002, 0, G_N_ELEMENTS(cases_002)); + tcase_add_loop_test (tc_parse_transport_ip4, test_parse_transport_pass_003, 0, G_N_ELEMENTS(cases_003)); + tcase_add_test (tc_parse_transport_ip4, test_parse_transport_pass_004); + tcase_add_test (tc_parse_transport_ip4, test_parse_transport_pass_005); + +/* IP version 6, ai_family = AF_INET6 */ + TCase* tc_parse_transport_ip6 = tcase_create ("parse_transport/af_inet6"); + suite_add_tcase (s, tc_parse_transport_ip6); + tcase_add_checked_fixture (tc_parse_transport_ip6, mock_setup_net, mock_teardown_net); + tcase_add_checked_fixture (tc_parse_transport_ip6, mock_setup_ip6, NULL); + tcase_add_loop_test (tc_parse_transport_ip6, test_parse_transport_pass_001, 0, G_N_ELEMENTS(cases_001)); + tcase_add_loop_test (tc_parse_transport_ip6, test_parse_transport_pass_002, 0, G_N_ELEMENTS(cases_002)); + tcase_add_loop_test (tc_parse_transport_ip6, test_parse_transport_pass_003, 0, G_N_ELEMENTS(cases_003)); + tcase_add_test (tc_parse_transport_ip6, test_parse_transport_pass_004); + tcase_add_test (tc_parse_transport_ip6, test_parse_transport_pass_005); + + TCase* tc_print_all = tcase_create ("print-all"); + tcase_add_checked_fixture (tc_print_all, mock_setup_net, mock_teardown_net); + suite_add_tcase (s, tc_print_all); + tcase_add_test (tc_print_all, test_print_all_pass_001); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/checksum.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/checksum.h new file mode 100644 index 0000000..67f71a6 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/checksum.h @@ -0,0 +1,75 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM checksum routines + * + * Copyright (c) 2006-2008 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_CHECKSUM_H__ +#define __PGM_IMPL_CHECKSUM_H__ + +#include + +PGM_BEGIN_DECLS + +uint16_t pgm_inet_checksum (const void*, uint16_t, uint16_t); +uint16_t pgm_csum_fold (uint32_t) PGM_GNUC_CONST; +uint32_t pgm_csum_block_add (uint32_t, uint32_t, const uint16_t) PGM_GNUC_CONST; +uint32_t pgm_compat_csum_partial (const void*, uint16_t, uint32_t); +uint32_t pgm_compat_csum_partial_copy (const void*restrict, void*restrict, uint16_t, uint32_t); + +static inline uint32_t add32_with_carry (uint32_t, uint32_t) PGM_GNUC_CONST; + +#if defined(__x86_64__) || defined(__i386__) || defined(__i386) || defined(__amd64) +static inline uint32_t add32_with_carry (uint32_t a, uint32_t b) +{ + asm("addl %2, %0 \n\t" + "adcl $0, %0" + : "=r" (a) /* output operands */ + : "0" (a), "r" (b)); /* input operands */ + return a; +} +#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv9) +static inline uint32_t add32_with_carry (uint32_t a, uint32_t b) +{ + asm("addcc %2, %0, %0 \n\t" + "addx %0, %%g0, %0" + : "=r" (a) /* output operands */ + : "0" (a), "r" (b) /* input operands */ + : "cc"); /* list of clobbered registers */ + return a; +} +#else +static inline uint32_t add32_with_carry (uint32_t a, uint32_t b) +{ + a += b; + a = (a >> 16) + (a & 0xffff); + return a; +} +#endif + +# define pgm_csum_partial pgm_compat_csum_partial +# define pgm_csum_partial_copy pgm_compat_csum_partial_copy + +PGM_END_DECLS + +#endif /* __PGM_IMPL_CHECKSUM_H__ */ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/engine.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/engine.h new file mode 100644 index 0000000..eeacbe7 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/engine.h @@ -0,0 +1,43 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM engine. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_ENGINE_H__ +#define __PGM_IMPL_ENGINE_H__ + +#ifdef _WIN32 +# include +# include +#endif +#include + +PGM_BEGIN_DECLS + +#ifdef _WIN32 +extern LPFN_WSARECVMSG pgm_WSARecvMsg; +#endif + +#ifdef PGM_DEBUG +extern unsigned pgm_loss_rate; +#endif + +PGM_END_DECLS + +#endif /* __PGM_IMPL_ENGINE_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/features.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/features.h new file mode 100644 index 0000000..a8dadf7 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/features.h @@ -0,0 +1,42 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Compiler feature flags. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_FEATURES_H__ +#define __PGM_IMPL_FEATURES_H__ + +#if defined(_POSIX_C_SOURCE) || defined(__POSIX_VISIBLE) +# if (_POSIX_C_SOURCE - 0) >= 200112L || (__POSIX_VISIBLE - 0) >= 200112L +# define CONFIG_HAVE_FTIME 1 +# define CONFIG_HAVE_GETTIMEOFDAY 1 +# endif +# if (_POSIX_C_SOURCE - 0) >= 199309L || (__POSIX_VISIBLE - 0) >= 199309L +# define CONFIG_HAVE_CLOCK_GETTIME 1 +# endif +#endif +#if defined(_WIN32) +# define CONFIG_HAVE_FTIME +#endif + +#endif /* __PGM_IMPL_FEATURES_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/fixed.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/fixed.h new file mode 100644 index 0000000..f864989 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/fixed.h @@ -0,0 +1,156 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * 8-bit and 16-bit shift fixed point math + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_FIXED_H__ +#define __PGM_IMPL_FIXED_H__ + +#include + +PGM_BEGIN_DECLS + +static inline uint_fast32_t pgm_fp8 (unsigned) PGM_GNUC_CONST; +static inline uint_fast32_t pgm_fp16 (unsigned) PGM_GNUC_CONST; +static inline unsigned pgm_fp8tou (uint_fast32_t) PGM_GNUC_CONST; +static inline unsigned pgm_fp16tou (uint_fast32_t) PGM_GNUC_CONST; +static inline uint_fast32_t pgm_fp8mul (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST; +static inline uint_fast32_t pgm_fp16mul (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST; +static inline uint_fast32_t pgm_fp8div (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST; +static inline uint_fast32_t pgm_fp16div (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST; +static inline uint_fast32_t pgm_fp16pow (uint_fast32_t, uint_fast32_t) PGM_GNUC_CONST; + +static inline +uint_fast32_t +pgm_fp8 ( + unsigned v + ) +{ + return (uint32_t)(v << 8); +} + +static inline +uint_fast32_t +pgm_fp16 ( + unsigned v + ) +{ + return (uint_fast32_t)(v << 16); +} + +static inline +unsigned +pgm_fp8tou ( + uint_fast32_t f + ) +{ + return (f + (1 << 7)) >> 8; +} + +static inline +unsigned +pgm_fp16tou ( + uint_fast32_t f + ) +{ + return (f + (1 << 15)) >> 16; +} + +static inline +uint_fast32_t +pgm_fp8mul ( + uint_fast32_t a, + uint_fast32_t b + ) +{ + return ( a * b + 128 ) >> 8; +} + +static inline +uint_fast32_t +pgm_fp16mul ( + uint_fast32_t a, + uint_fast32_t b + ) +{ + return ( a * b + 32768 ) >> 16; +} + +static inline +uint_fast32_t +pgm_fp8div ( + uint_fast32_t a, + uint_fast32_t b + ) +{ + return ( ( (a << 9) / b ) + 1 ) / 2; +} + +static inline +uint_fast32_t +pgm_fp16div ( + uint_fast32_t a, + uint_fast32_t b + ) +{ + return ( ( (a << 17) / b ) + 1 ) / 2; +} + +static inline +uint_fast32_t +pgm_fp16pow ( + uint_fast32_t x, + uint_fast32_t y + ) +{ + uint_fast32_t result = pgm_fp16 (1); +#if defined(__STDC_VERSION__) && (__STDC_VERSION >= 199901L) +/* C99 version */ + for (uint_fast32_t i = x; + y; + y >>= 1) + { + if (y & 1) + result = (result * i + 32768) >> 16; + i = (i * i + 32768) >> 16; + } +#else +/* C89 version */ + { + uint_fast32_t i; + for (i = x; + y; + y >>= 1) + { + if (y & 1) + result = (result * i + 32768) >> 16; + i = (i * i + 32768) >> 16; + } + } +#endif + return result; +} + +PGM_END_DECLS + +#endif /* __PGM_IMPL_FIXED_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/framework.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/framework.h new file mode 100644 index 0000000..951ad26 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/framework.h @@ -0,0 +1,76 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Framework collection. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_FRAMEWORK_H__ +#define __PGM_IMPL_FRAMEWORK_H__ + +#define __PGM_IMPL_FRAMEWORK_H_INSIDE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef __PGM_IMPL_FRAMEWORK_H_INSIDE__ + +#endif /* __PGM_IMPL_FRAMEWORK_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/galois.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/galois.h new file mode 100644 index 0000000..e90e66b --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/galois.h @@ -0,0 +1,153 @@ +/* + * Galois field maths. + * + * Copyright (c) 2006-2008 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_GALOIS_H__ +#define __PGM_IMPL_GALOIS_H__ + +#include + +PGM_BEGIN_DECLS + +/* 8 bit wide galois field integer: GF(2⁸) */ +#ifdef _MSC_VER +typedef uint8_t pgm_gf8_t; +#else +typedef uint8_t __attribute__((__may_alias__)) pgm_gf8_t; +#endif + +/* E denotes the encoding symbol length in bytes. + * S denotes the symbol size in units of m-bit elements. When m = 8, + * then S and E are equal. + */ +#define PGM_GF_ELEMENT_BYTES sizeof(pgm_gf8_t) + +/* m defines the length of the elements in the finite field, in bits. + * m belongs to {2..16}. + */ +#define PGM_GF_ELEMENT_BITS ( 8 * PGM_GF_ELEMENT_BYTES ) + +/* q defines the number of elements in the finite field. + */ +#define PGM_GF_NO_ELEMENTS ( 1 << PGM_GF_ELEMENT_BITS ) +#define PGM_GF_MAX ( PGM_GF_NO_ELEMENTS - 1 ) + + +extern const pgm_gf8_t pgm_gflog[PGM_GF_NO_ELEMENTS]; +extern const pgm_gf8_t pgm_gfantilog[PGM_GF_NO_ELEMENTS]; + +#ifdef CONFIG_GALOIS_MUL_LUT +extern const pgm_gf8_t pgm_gftable[PGM_GF_NO_ELEMENTS * PGM_GF_NO_ELEMENTS]; +#endif + +/* In a finite field with characteristic 2, addition and subtraction are + * identical, and are accomplished using the XOR operator. + */ +static inline +pgm_gf8_t +pgm_gfadd ( + pgm_gf8_t a, + pgm_gf8_t b + ) +{ + return a ^ b; +} + +static inline +pgm_gf8_t +pgm_gfadd_equals ( + pgm_gf8_t a, + pgm_gf8_t b + ) +{ + return a ^= b; +} + +static inline +pgm_gf8_t +pgm_gfsub ( + pgm_gf8_t a, + pgm_gf8_t b + ) +{ + return pgm_gfadd (a, b); +} + +static inline +pgm_gf8_t +pgm_gfsub_equals ( + pgm_gf8_t a, + pgm_gf8_t b + ) +{ + return pgm_gfadd_equals (a, b); +} + +static inline +pgm_gf8_t +pgm_gfmul ( + pgm_gf8_t a, + pgm_gf8_t b + ) +{ + if (PGM_UNLIKELY( !(a && b) )) { + return 0; + } + +#ifdef CONFIG_GALOIS_MUL_LUT + return pgm_gftable[ (uint16_t)a << 8 | (uint16_t)b ]; +#else + unsigned sum = pgm_gflog[ a ] + pgm_gflog[ b ]; + return sum >= PGM_GF_MAX ? pgm_gfantilog[ sum - PGM_GF_MAX ] : pgm_gfantilog[ sum ]; +#endif +} + +static inline +pgm_gf8_t +pgm_gfdiv ( + pgm_gf8_t a, + pgm_gf8_t b + ) +{ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +/* C99 version */ + if (PGM_UNLIKELY( !a )) { + return 0; + } + + const int sum = pgm_gflog[ a ] - pgm_gflog[ b ]; + return sum < 0 ? pgm_gfantilog[ sum + PGM_GF_MAX ] : pgm_gfantilog[ sum ]; +#else +/* C89 version */ + const int sum = pgm_gflog[ a ] - pgm_gflog[ b ]; + if (PGM_UNLIKELY( !a )) { + return 0; + } + + return sum < 0 ? pgm_gfantilog[ sum + PGM_GF_MAX ] : pgm_gfantilog[ sum ]; +#endif +} + +PGM_END_DECLS + +#endif /* __PGM_IMPL_GALOIS_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/getifaddrs.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/getifaddrs.h new file mode 100644 index 0000000..eddb37a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/getifaddrs.h @@ -0,0 +1,76 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable getifaddrs + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_GETIFADDRS_H__ +#define __PGM_IMPL_GETIFADDRS_H__ + +#ifndef _WIN32 +# include +# include +# include +#else +# include +#endif + +struct pgm_ifaddrs_t; + +#include +#include + +PGM_BEGIN_DECLS + +#ifndef IF_NAMESIZE +# ifdef IFNAMSIZ +# define IF_NAMESIZE IFNAMSIZ +# elif defined(MAX_INTERFACE_NAME_LEN) +# define IF_NAMESIZE MAX_INTERFACE_NAME_LEN +# elif defined(_WIN32) +/* 40 for UUID, 256 for device path */ +# define IF_NAMESIZE 256 +# else +# define IF_NAMESIZE 16 +# endif +#endif + +struct pgm_ifaddrs_t +{ + struct pgm_ifaddrs_t* ifa_next; /* Pointer to the next structure. */ + + char* ifa_name; /* Name of this network interface. */ + unsigned int ifa_flags; /* Flags as from SIOCGIFFLAGS ioctl. */ + +#ifdef ifa_addr +# undef ifa_addr +#endif + struct sockaddr* ifa_addr; /* Network address of this interface. */ + struct sockaddr* ifa_netmask; /* Netmask of this interface. */ +}; + +bool pgm_getifaddrs (struct pgm_ifaddrs_t**restrict, pgm_error_t**restrict); +void pgm_freeifaddrs (struct pgm_ifaddrs_t*); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_GETIFADDRS_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/getnodeaddr.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/getnodeaddr.h new file mode 100644 index 0000000..befcf35 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/getnodeaddr.h @@ -0,0 +1,41 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable function to return node IP address. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_GETNODEADDR_H__ +#define __PGM_IMPL_GETNODEADDR_H__ + +#ifndef _WIN32 +# include +#endif +#include +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL bool pgm_if_getnodeaddr (const sa_family_t, struct sockaddr*restrict, const socklen_t, pgm_error_t**restrict); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_GETNODEADDR_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/hashtable.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/hashtable.h new file mode 100644 index 0000000..4271cb6 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/hashtable.h @@ -0,0 +1,58 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable hash table. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_HASHTABLE_H__ +#define __PGM_IMPL_HASHTABLE_H__ + +#include + +PGM_BEGIN_DECLS + +typedef struct pgm_hashtable_t pgm_hashtable_t; +typedef uint_fast32_t pgm_hash_t; + +typedef pgm_hash_t (*pgm_hashfunc_t) (const void*); +typedef bool (*pgm_equalfunc_t) (const void*restrict, const void*restrict); + +PGM_GNUC_INTERNAL pgm_hashtable_t* pgm_hashtable_new (pgm_hashfunc_t, pgm_equalfunc_t); +PGM_GNUC_INTERNAL void pgm_hashtable_destroy (pgm_hashtable_t*); +PGM_GNUC_INTERNAL void pgm_hashtable_insert (pgm_hashtable_t*restrict, const void*restrict, void*restrict); +PGM_GNUC_INTERNAL bool pgm_hashtable_remove (pgm_hashtable_t*restrict, const void*restrict); +PGM_GNUC_INTERNAL void pgm_hashtable_remove_all (pgm_hashtable_t*); +PGM_GNUC_INTERNAL void* pgm_hashtable_lookup (const pgm_hashtable_t*restrict, const void*restrict); +PGM_GNUC_INTERNAL void* pgm_hashtable_lookup_extended (const pgm_hashtable_t*restrict, const void*restrict, void*restrict); +PGM_GNUC_INTERNAL void pgm_hashtable_unref (pgm_hashtable_t*); + +/* Hash Functions + */ + +PGM_GNUC_INTERNAL bool pgm_str_equal (const void*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL pgm_hash_t pgm_str_hash (const void*) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_int_equal (const void*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL pgm_hash_t pgm_int_hash (const void*) PGM_GNUC_WARN_UNUSED_RESULT; + +PGM_END_DECLS + +#endif /* __PGM_IMPL_HASHTABLE_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/histogram.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/histogram.h new file mode 100644 index 0000000..92ddeb9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/histogram.h @@ -0,0 +1,129 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * histograms. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_HISTOGRAM_H__ +#define __PGM_IMPL_HISTOGRAM_H__ + +#include +#include +#include +#include + +PGM_BEGIN_DECLS + +typedef int pgm_sample_t; +typedef int pgm_count_t; + +struct pgm_sample_set_t { + pgm_count_t* counts; + unsigned counts_len; + int64_t sum; + int64_t square_sum; +}; + +typedef struct pgm_sample_set_t pgm_sample_set_t; + +struct pgm_histogram_t { + const char* restrict histogram_name; + unsigned bucket_count; + pgm_sample_t declared_min; + pgm_sample_t declared_max; + pgm_sample_t* restrict ranges; + pgm_sample_set_t sample; + bool is_registered; + pgm_slist_t histograms_link; +}; + +typedef struct pgm_histogram_t pgm_histogram_t; + +#define PGM_HISTOGRAM_DEFINE(name, minimum, maximum, count) \ + static pgm_count_t counts[ (count) ]; \ + static pgm_sample_t ranges[ (count) + 1 ]; \ + static pgm_histogram_t counter = { \ + .histogram_name = (name), \ + .bucket_count = (count), \ + .declared_min = (minimum), \ + .declared_max = (maximum), \ + .ranges = ranges, \ + .sample = { \ + .counts = counts, \ + .counts_len = (count), \ + .sum = 0, \ + .square_sum = 0 \ + }, \ + .is_registered = FALSE \ + } + +#ifdef CONFIG_HISTOGRAMS + +# define PGM_HISTOGRAM_TIMES(name, sample) do { \ + PGM_HISTOGRAM_DEFINE(name, pgm_msecs(1), pgm_secs(10), 50); \ + if (!counter.is_registered) { \ + memset (counts, 0, sizeof(counts)); \ + memset (ranges, 0, sizeof(ranges)); \ + pgm_histogram_init (&counter); \ + } \ + pgm_histogram_add_time (&counter, sample); \ + } while (0) + +# define PGM_HISTOGRAM_COUNTS(name, sample) do { \ + PGM_HISTOGRAM_DEFINE(name, 1, 1000000, 50); \ + if (!counter.is_registered) { \ + memset (counts, 0, sizeof(counts)); \ + memset (ranges, 0, sizeof(ranges)); \ + pgm_histogram_init (&counter); \ + } \ + pgm_histogram_add (&counter, (sample)); \ + } while (0) + +#else /* !CONFIG_HISTOGRAMS */ + +# define PGM_HISTOGRAM_TIMES(name, sample) +# define PGM_HISTOGRAM_COUNTS(name, sample) + +#endif /* !CONFIG_HISTOGRAMS */ + + +extern pgm_slist_t* pgm_histograms; + +void pgm_histogram_init (pgm_histogram_t*); +void pgm_histogram_add (pgm_histogram_t*, int); +void pgm_histogram_write_html_graph_all (pgm_string_t*); + +static inline +void +pgm_histogram_add_time ( + pgm_histogram_t*const histogram, + pgm_time_t sample_time + ) +{ + pgm_histogram_add (histogram, (int)pgm_to_msecs (sample_time)); +} + +PGM_END_DECLS + +#endif /* __PGM_IMPL_HISTOGRAM_H__ */ + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/i18n.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/i18n.h new file mode 100644 index 0000000..c97f3de --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/i18n.h @@ -0,0 +1,32 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * i18n & l10n support + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_I18N_H__ +#define __PGM_IMPL_I18N_H__ + +#ifdef CONFIG_HAVE_GETTEXT +# include +# define _(String) dgettext (GETTEXT_PACKAGE, String) +#else +# define _(String) (String) +#endif + +#endif /* __PGM_IMPL_I18N_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/indextoaddr.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/indextoaddr.h new file mode 100644 index 0000000..df2b2ef --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/indextoaddr.h @@ -0,0 +1,41 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable interface index to socket address function. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_INDEXTOADDR_H__ +#define __PGM_IMPL_INDEXTOADDR_H__ + +#ifndef _WIN32 +# include +#endif +#include +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL bool pgm_if_indextoaddr (const unsigned, const sa_family_t, const uint32_t, struct sockaddr*restrict, pgm_error_t**restrict); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_INDEXTOADDR_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/indextoname.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/indextoname.h new file mode 100644 index 0000000..d5d7964 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/indextoname.h @@ -0,0 +1,37 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Windows interface index to interface name function. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_INDEXTONAME_H__ +#define __PGM_IMPL_INDEXTONAME_H__ + +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL char* pgm_if_indextoname (unsigned, char*); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_INDEXTONAME_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/inet_network.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/inet_network.h new file mode 100644 index 0000000..64c43fb --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/inet_network.h @@ -0,0 +1,41 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable implementations of inet_network and inet_network6. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_INET_NETWORK_H__ +#define __PGM_IMPL_INET_NETWORK_H__ + +#ifndef _WIN32 +# include +#endif +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL int pgm_inet_network (const char*restrict, struct in_addr*restrict); +PGM_GNUC_INTERNAL int pgm_inet6_network (const char*restrict, struct in6_addr*restrict); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_INET_NETWORK_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/ip.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/ip.h new file mode 100644 index 0000000..2db402e --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/ip.h @@ -0,0 +1,150 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Internet header for protocol version 4, RFC 791. + * + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_IP_H__ +#define __PGM_IMPL_IP_H__ + +#ifndef _WIN32 +# include +# include +#endif +#include + +PGM_BEGIN_DECLS + +/* Byte alignment for packet memory maps. + * NB: Solaris and OpenSolaris don't support #pragma pack(push) even on x86. + */ +#if defined( __GNUC__ ) && !defined( sun ) +# pragma pack(push) +#endif +#pragma pack(1) + +/* RFC 791 */ + +/* nb: first four bytes are forced bitfields for win32 "feature" */ +struct pgm_ip +{ +#if (defined( sun ) && defined( _BIT_FIELDS_LTOH )) || (!defined( sun ) && __BYTE_ORDER == __LITTLE_ENDIAN) + unsigned ip_hl:4; /* header length */ + unsigned ip_v:4; /* version */ +#else + unsigned ip_v:4; /* version */ + unsigned ip_hl:4; /* header length */ +#endif + unsigned ip_tos:8; /* type of service */ + unsigned ip_len:16; /* total length */ + uint16_t ip_id; /* identification */ + uint16_t ip_off; /* fragment offset field */ + uint8_t ip_ttl; /* time to live */ + uint8_t ip_p; /* protocol */ + uint16_t ip_sum; /* checksum */ + struct in_addr ip_src, ip_dst; /* source and dest address */ +}; + +PGM_STATIC_ASSERT(sizeof(struct pgm_ip) == 20); + +/* RFC 2460 */ +#ifdef ip6_vfc +# undef ip6_vfc +#endif +#ifdef ip6_plen +# undef ip6_plen +#endif +#ifdef ip6_nxt +# undef ip6_nxt +#endif +#ifdef ip6_hops +# undef ip6_hops +#endif +struct pgm_ip6_hdr +{ + uint32_t ip6_vfc; /* version:4, traffic class:8, flow label:20 */ + uint16_t ip6_plen; /* payload length: packet length - 40 */ + uint8_t ip6_nxt; /* next header type */ + uint8_t ip6_hops; /* hop limit */ + struct in6_addr ip6_src, ip6_dst; /* source and dest address */ +}; + +PGM_STATIC_ASSERT(sizeof(struct pgm_ip6_hdr) == 40); + +#define PGM_IPOPT_EOL 0 /* end of option list */ +#define PGM_IPOPT_NOP 1 /* no operation */ +#define PGM_IPOPT_RR 7 /* record packet route */ +#define PGM_IPOPT_TS 68 /* timestamp */ +#define PGM_IPOPT_SECURITY 130 /* provide s, c, h, tcc */ +#define PGM_IPOPT_LSRR 131 /* loose source route */ +#define PGM_IPOPT_ESO 133 +#define PGM_IPOPT_CIPSO 134 +#define PGM_IPOPT_SATID 136 /* satnet id */ +#define PGM_IPOPT_SSRR 137 /* strict source route */ +#define PGM_IPOPT_RA 148 /* router alert */ + +/* RFC 768 */ +struct pgm_udphdr +{ + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + uint16_t uh_ulen; /* udp length */ + uint16_t uh_sum; /* udp checksum */ +}; + +PGM_STATIC_ASSERT(sizeof(struct pgm_udphdr) == 8); + +#if defined( __GNUC__ ) && !defined( sun ) +# pragma pack(pop) +#else +# pragma pack() +#endif + +PGM_END_DECLS + +#endif /* __PGM_IMPL_IP_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/list.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/list.h new file mode 100644 index 0000000..91a3ed3 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/list.h @@ -0,0 +1,43 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable doubly-linked list. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_LIST_H__ +#define __PGM_IMPL_LIST_H__ + +#include +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL pgm_list_t* pgm_list_append (pgm_list_t*restrict, void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL pgm_list_t* pgm_list_prepend_link (pgm_list_t*restrict, pgm_list_t*restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL pgm_list_t* pgm_list_remove_link (pgm_list_t*, pgm_list_t*) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL pgm_list_t* pgm_list_delete_link (pgm_list_t*, pgm_list_t*) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL pgm_list_t* pgm_list_last (pgm_list_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL unsigned pgm_list_length (pgm_list_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; + +PGM_END_DECLS + +#endif /* __PGM_IMPL_LIST_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/math.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/math.h new file mode 100644 index 0000000..00eb808 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/math.h @@ -0,0 +1,86 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Shared math routines. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_MATH_H__ +#define __PGM_IMPL_MATH_H__ + +#include + +PGM_BEGIN_DECLS + +/* fast log base 2 of power of 2 + */ + +static inline unsigned pgm_power2_log2 (unsigned) PGM_GNUC_CONST; + +static inline +unsigned +pgm_power2_log2 ( + unsigned v + ) +{ + static const unsigned int b[] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 }; + unsigned int r = (v & b[0]) != 0; +#if defined(__STDC_VERSION__) && (__STDC_VERSION >= 199901L) +/* C99 version */ + for (unsigned i = 4; i > 0; i--) { + r |= ((v & b[i]) != 0) << i; + } +#else +/* C89 version */ + { + unsigned i; + for (i = 4; i > 0; i--) { + r |= ((v & b[i]) != 0) << i; + } + } +#endif + return r; +} + +/* nearest power of 2 + */ + +static inline size_t pgm_nearest_power (size_t, size_t) PGM_GNUC_CONST; + +static inline +size_t +pgm_nearest_power ( + size_t b, + size_t v + ) +{ + if (v > (SIZE_MAX/2)) + return SIZE_MAX; + while (b < v) + b <<= 1; + return b; +} + +unsigned pgm_spaced_primes_closest (unsigned) PGM_GNUC_PURE; + +PGM_END_DECLS + +#endif /* __PGM_IMPL_MATH_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/md5.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/md5.h new file mode 100644 index 0000000..b28ab7d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/md5.h @@ -0,0 +1,61 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * MD5 hashing algorithm. + * + * MD5 original source GNU C Library: + * Includes functions to compute MD5 message digest of files or memory blocks + * according to the definition of MD5 in RFC 1321 from April 1992. + * + * Copyright (C) 1995, 1996, 2001, 2003 Free Software Foundation, Inc. + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this file; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_MD5_H__ +#define __PGM_IMPL_MD5_H__ + +struct pgm_md5_t; + +#include + +PGM_BEGIN_DECLS + +struct pgm_md5_t +{ + uint32_t A; + uint32_t B; + uint32_t C; + uint32_t D; + + uint32_t total[2]; + uint32_t buflen; + char buffer[128] +#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) + __attribute__ ((__aligned__ (__alignof__ (uint32_t)))) +#endif + ; +}; + +PGM_GNUC_INTERNAL void pgm_md5_init_ctx (struct pgm_md5_t*); +PGM_GNUC_INTERNAL void pgm_md5_process_bytes (struct pgm_md5_t*restrict, const void*restrict, size_t); +PGM_GNUC_INTERNAL void* pgm_md5_finish_ctx (struct pgm_md5_t*, void*); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_MD5_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/mem.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/mem.h new file mode 100644 index 0000000..9377ced --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/mem.h @@ -0,0 +1,34 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable fail fast memory allocation. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_MEM_H__ +#define __PGM_IMPL_MEM_H__ + +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL void pgm_mem_init (void); +PGM_GNUC_INTERNAL void pgm_mem_shutdown (void); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_MEM_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/messages.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/messages.h new file mode 100644 index 0000000..e7065b0 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/messages.h @@ -0,0 +1,352 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * basic message reporting. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_MESSAGES_H__ +#define __PGM_IMPL_MESSAGES_H__ + +#include +#include +#include +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL void pgm__log (const int, const char*, ...) PGM_GNUC_PRINTF (2, 3); +PGM_GNUC_INTERNAL void pgm__logv (const int, const char*, va_list) PGM_GNUC_PRINTF (2, 0); + +#ifdef CONFIG_HAVE_ISO_VARARGS + +/* debug trace level only valid in debug mode */ +# ifdef PGM_DEBUG +# define pgm_debug(...) \ + do { \ + if (pgm_min_log_level == PGM_LOG_LEVEL_DEBUG) \ + pgm__log (PGM_LOG_LEVEL_DEBUG, __VA_ARGS__); \ + } while (0) +# else +# define pgm_debug(...) while (0) +# endif /* !PGM_DEBUG */ + +# define pgm_trace(r,...) \ + do { \ + if (pgm_min_log_level <= PGM_LOG_LEVEL_TRACE && pgm_log_mask & (r)) \ + pgm__log (PGM_LOG_LEVEL_TRACE, __VA_ARGS__); \ + } while (0) +# define pgm_minor(...) \ + do { \ + if (pgm_min_log_level <= PGM_LOG_LEVEL_MINOR) \ + pgm__log (PGM_LOG_LEVEL_MINOR, __VA_ARGS__); \ + } while (0) +# define pgm_info(...) \ + do { \ + if (pgm_min_log_level <= PGM_LOG_LEVEL_NORMAL) \ + pgm__log (PGM_LOG_LEVEL_NORMAL, __VA_ARGS__); \ + } while (0) +# define pgm_warn(...) \ + do { \ + if (pgm_min_log_level <= PGM_LOG_LEVEL_WARNING) \ + pgm__log (PGM_LOG_LEVEL_WARNING, __VA_ARGS__); \ + } while (0) +# define pgm_error(...) \ + do { \ + if (pgm_min_log_level <= PGM_LOG_LEVEL_ERROR) \ + pgm__log (PGM_LOG_LEVEL_ERROR, __VA_ARGS__); \ + } while (0) +# define pgm_fatal(...) \ + do { \ + pgm__log (PGM_LOG_LEVEL_FATAL, __VA_ARGS__); \ + } while (0) + +#elif defined(CONFIG_HAVE_GNUC_VARARGS) + +# ifdef PGM_DEBUG +# define pgm_debug(f...) \ + do { \ + if (pgm_min_log_level == PGM_LOG_LEVEL_DEBUG) \ + pgm__log (PGM_LOG_LEVEL_DEBUG, f); \ + } while (0) +# else +# define pgm_debug(f...) while (0) +# endif /* !PGM_DEBUG */ + +# define pgm_trace(r,f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_TRACE && pgm_log_mask & (r)) \ + pgm__log (PGM_LOG_LEVEL_TRACE, f) +# define pgm_minor(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_MINOR) pgm__log (PGM_LOG_LEVEL_MINOR, f) +# define pgm_info(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_NORMAL) pgm__log (PGM_LOG_LEVEL_NORMAL, f) +# define pgm_warn(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_WARNING) pgm__log (PGM_LOG_LEVEL_WARNING, f) +# define pgm_error(f...) if (pgm_min_log_level <= PGM_LOG_LEVEL_ERROR) pgm__log (PGM_LOG_LEVEL_ERROR, f) +# define pgm_fatal(f...) pgm__log (PGM_LOG_LEVEL_FATAL, f) + +#else /* no varargs macros */ + +/* declare for GCC attributes */ +static inline void pgm_debug (const char*, ...) PGM_GNUC_PRINTF (1, 2); +static inline void pgm_trace (const int, const char*, ...) PGM_GNUC_PRINTF (2, 3); +static inline void pgm_minor (const char*, ...) PGM_GNUC_PRINTF (1, 2); +static inline void pgm_info (const char*, ...) PGM_GNUC_PRINTF (1, 2); +static inline void pgm_warn (const char*, ...) PGM_GNUC_PRINTF (1, 2); +static inline void pgm_error (const char*, ...) PGM_GNUC_PRINTF (1, 2); +static inline void pgm_fatal (const char*, ...) PGM_GNUC_PRINTF (1, 2); + +static inline void pgm_debug (const char* format, ...) { + if (PGM_LOG_LEVEL_DEBUG == pgm_min_log_level) { + va_list args; + va_start (args, format); + pgm__logv (PGM_LOG_LEVEL_DEBUG, format, args); + va_end (args); + } +} + +static inline void pgm_trace (const int role, const char* format, ...) { + if (PGM_LOG_LEVEL_TRACE >= pgm_min_log_level && pgm_log_mask & role) { + va_list args; + va_start (args, format); + pgm__logv (PGM_LOG_LEVEL_TRACE, format, args); + va_end (args); + } +} + +static inline void pgm_minor (const char* format, ...) { + if (PGM_LOG_LEVEL_MINOR >= pgm_min_log_level) { + va_list args; + va_start (args, format); + pgm__logv (PGM_LOG_LEVEL_MINOR, format, args); + va_end (args); + } +} + +static inline void pgm_info (const char* format, ...) { + if (PGM_LOG_LEVEL_NORMAL >= pgm_min_log_level) { + va_list args; + va_start (args, format); + pgm__logv (PGM_LOG_LEVEL_NORMAL, format, args); + va_end (args); + } +} + +static inline void pgm_warn (const char* format, ...) { + if (PGM_LOG_LEVEL_WARNING >= pgm_min_log_level) { + va_list args; + va_start (args, format); + pgm__logv (PGM_LOG_LEVEL_WARNING, format, args); + va_end (args); + } +} + +static inline void pgm_error (const char* format, ...) { + if (PGM_LOG_LEVEL_ERROR >= pgm_min_log_level) { + va_list args; + va_start (args, format); + pgm__logv (PGM_LOG_LEVEL_WARNING, format, args); + va_end (args); + } +} + +static inline void pgm_fatal (const char* format, ...) { + va_list args; + va_start (args, format); + pgm__logv (PGM_LOG_LEVEL_FATAL, format, args); + va_end (args); +} + +#endif /* varargs */ + +#define pgm_warn_if_reached() \ + do { \ + pgm_warn ("file %s: line %d (%s): code should not be reached", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } while (0) +#define pgm_warn_if_fail(expr) \ + do { \ + if (PGM_LIKELY (expr)); \ + else \ + pgm_warn ("file %s: line %d (%s): runtime check failed: (%s)", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \ + } while (0) + + +#ifdef PGM_DISABLE_ASSERT + +# define pgm_assert(expr) while (0) +# define pgm_assert_not_reached() while (0) +# define pgm_assert_cmpint(n1, cmp, n2) while (0) +# define pgm_assert_cmpuint(n1, cmp, n2) while (0) + +#elif defined(__GNUC__) + +# define pgm_assert(expr) \ + do { \ + if (PGM_LIKELY(expr)); \ + else { \ + pgm_fatal ("file %s: line %d (%s): assertion failed: (%s)", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \ + abort (); \ + } \ + } while (0) +# define pgm_assert_not_reached() \ + do { \ + pgm_fatal ("file %s: line %d (%s): should not be reached", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + abort (); \ + } while (0) +# define pgm_assert_cmpint(n1, cmp, n2) \ + do { \ + const int _n1 = (n1), _n2 = (n2); \ + if (PGM_LIKELY(_n1 cmp _n2)); \ + else { \ + pgm_fatal ("file %s: line %d (%s): assertion failed (%s): (%u %s %u)", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \ + abort (); \ + } \ + } while (0) +# define pgm_assert_cmpuint(n1, cmp, n2) \ + do { \ + const unsigned _n1 = (n1), _n2 = (n2); \ + if (PGM_LIKELY(_n1 cmp _n2)); \ + else { \ + pgm_fatal ("file %s: line %d (%s): assertion failed (%s): (%u %s %u)", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \ + abort (); \ + } \ + } while (0) + +#else + +# define pgm_assert(expr) \ + do { \ + if (PGM_LIKELY(expr)); \ + else { \ + pgm_fatal ("file %s: line %d: assertion failed: (%s)", \ + __FILE__, __LINE__, #expr); \ + abort (); \ + } \ + } while (0) +# define pgm_assert_not_reached() \ + do { \ + pgm_fatal ("file %s: line %d: assertion failed: (%s)", \ + __FILE__, __LINE__); \ + abort (); \ + } while (0) +# define pgm_assert_cmpint(n1, cmp, n2) \ + do { \ + const int _n1 = (n1), _n2 = (n2); \ + if (PGM_LIKELY(_n1 cmp _n2)); \ + else { \ + pgm_fatal ("file %s: line %d: assertion failed (%s): (%u %s %u)", \ + __FILE__, __LINE__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \ + abort (); \ + } \ + } while (0) +# define pgm_assert_cmpuint(n1, cmp, n2) \ + do { \ + const unsigned _n1 = (n1), _n2 = (n2); \ + if (PGM_LIKELY(_n1 cmp _n2)); \ + else { \ + pgm_fatal ("file %s: line %d: assertion failed (%s): (%u %s %u)", \ + __FILE__, __LINE__, #n1 " " #cmp " " #n2, _n1, #cmp, _n2); \ + abort (); \ + } \ + } while (0) + +#endif /* !PGM_DISABLE_ASSERT */ + +#ifdef PGM_DISABLE_CHECKS + +# define pgm_return_if_fail(expr) while (0) +# define pgm_return_val_if_fail(expr, val) while (0) +# define pgm_return_if_reached() return +# define pgm_return_val_if_reached(val) return (val) + +#elif defined(__GNUC__) + +# define pgm_return_if_fail(expr) \ + do { \ + if (PGM_LIKELY(expr)); \ + else { \ + pgm_warn ("file %s: line %d (%s): assertion `%s' failed", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \ + return; \ + } \ + } while (0) +# define pgm_return_val_if_fail(expr, val) \ + do { \ + if (PGM_LIKELY(expr)); \ + else { \ + pgm_warn ("file %s: line %d (%s): assertion `%s' failed", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \ + return (val); \ + } \ + } while (0) +# define pgm_return_if_reached() \ + do { \ + pgm_warn ("file %s: line %d (%s): should not be reached", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + return; \ + } while (0) +# define pgm_return_val_if_reached(val) \ + do { \ + pgm_warn ("file %s: line %d (%s): should not be reached", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + return (val); \ + } while (0) + +#else + +# define pgm_return_if_fail(expr) \ + do { \ + if (PGM_LIKELY(expr)); \ + else { \ + pgm_warn ("file %s: line %d: assertion `%s' failed", \ + __FILE__, __LINE__, #expr); \ + return; \ + } \ + } while (0) +# define pgm_return_val_if_fail(expr, val) \ + do { \ + if (PGM_LIKELY(expr)); \ + else { \ + pgm_warn ("file %s: line %d: assertion `%s' failed", \ + __FILE__, __LINE__, #expr); \ + return (val); \ + } \ + } while (0) +# define pgm_return_if_reached() \ + do { \ + pgm_warn ("file %s: line %d): should not be reached", \ + __FILE__, __LINE__); \ + return; \ + } while (0) +# define pgm_return_val_if_reached(val) \ + do { \ + pgm_warn ("file %s: line %d: should not be reached", \ + __FILE__, __LINE__); \ + return (val); \ + } while (0) + +#endif /* !PGM_DISABLE_CHECKS */ + +PGM_END_DECLS + +#endif /* __PGM_IMPL_MESSAGES_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/nametoindex.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/nametoindex.h new file mode 100644 index 0000000..a25bd89 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/nametoindex.h @@ -0,0 +1,40 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Windows interface name to interface index function. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_NAMETOINDEX_H__ +#define __PGM_IMPL_NAMETOINDEX_H__ + +#ifndef _WIN32 +# include +#endif +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL unsigned pgm_if_nametoindex (const sa_family_t, const char*); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_NAMETOINDEX_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/net.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/net.h new file mode 100644 index 0000000..fd30c1c --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/net.h @@ -0,0 +1,53 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * network send wrapper. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_NET_H__ +#define __PGM_IMPL_NET_H__ + +#ifndef _WIN32 +# include +#endif +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL ssize_t pgm_sendto_hops (pgm_sock_t*restrict, bool, bool, int, const void*restrict, size_t, const struct sockaddr*restrict, socklen_t); +PGM_GNUC_INTERNAL int pgm_set_nonblocking (int fd[2]); + +static inline +ssize_t +pgm_sendto ( + pgm_sock_t*restrict sock, + bool use_rate_limit, + bool use_router_alert, + const void*restrict buf, + size_t len, + const struct sockaddr*restrict to, + socklen_t tolen + ) +{ + return pgm_sendto_hops (sock, use_rate_limit, use_router_alert, -1, buf, len, to, tolen); +} + +PGM_END_DECLS + +#endif /* __PGM_IMPL_NET_H__ */ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/notify.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/notify.h new file mode 100644 index 0000000..47f9e1c --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/notify.h @@ -0,0 +1,305 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Low kernel overhead event notify mechanism, or standard pipes. + * + * Copyright (c) 2008 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_NOTIFY_H__ +#define __PGM_IMPL_NOTIFY_H__ + +typedef struct pgm_notify_t pgm_notify_t; + +#ifndef _WIN32 +# include +# include +# ifdef CONFIG_HAVE_EVENTFD +# include +# endif +#else /* _WIN32 */ +# include +# include +#endif +#include +#include + +PGM_BEGIN_DECLS + +struct pgm_notify_t { +#if defined(CONFIG_HAVE_EVENTFD) + int eventfd; +#elif !defined(_WIN32) + int pipefd[2]; +#else + SOCKET s[2]; +#endif /* _WIN32 */ +}; + +#if defined(CONFIG_HAVE_EVENTFD) +# define PGM_NOTIFY_INIT { -1 } +#elif !defined(_WIN32) +# define PGM_NOTIFY_INIT { { -1, -1 } } +#else +# define PGM_NOTIFY_INIT { { INVALID_SOCKET, INVALID_SOCKET } } +#endif + + +static inline +bool +pgm_notify_is_valid ( + pgm_notify_t* notify + ) +{ + if (PGM_UNLIKELY(NULL == notify)) + return FALSE; +#if defined(CONFIG_HAVE_EVENTFD) + if (PGM_UNLIKELY(-1 == notify->eventfd)) + return FALSE; +#elif !defined(_WIN32) + if (PGM_UNLIKELY(-1 == notify->pipefd[0] || -1 == notify->pipefd[1])) + return FALSE; +#else + if (PGM_UNLIKELY(INVALID_SOCKET == notify->s[0] || INVALID_SOCKET == notify->s[1])) + return FALSE; +#endif /* _WIN32 */ + return TRUE; +} + +static inline +int +pgm_notify_init ( + pgm_notify_t* notify + ) +{ +#if defined(CONFIG_HAVE_EVENTFD) + pgm_assert (NULL != notify); + notify->eventfd = -1; + int retval = eventfd (0, 0); + if (-1 == retval) + return retval; + notify->eventfd = retval; + const int fd_flags = fcntl (notify->eventfd, F_GETFL); + if (-1 != fd_flags) + retval = fcntl (notify->eventfd, F_SETFL, fd_flags | O_NONBLOCK); + return 0; +#elif !defined(_WIN32) + pgm_assert (NULL != notify); + notify->pipefd[0] = notify->pipefd[1] = -1; + int retval = pipe (notify->pipefd); + pgm_assert (0 == retval); +/* set non-blocking */ +/* write-end */ + int fd_flags = fcntl (notify->pipefd[1], F_GETFL); + if (fd_flags != -1) + retval = fcntl (notify->pipefd[1], F_SETFL, fd_flags | O_NONBLOCK); + pgm_assert (notify->pipefd[1]); +/* read-end */ + fd_flags = fcntl (notify->pipefd[0], F_GETFL); + if (fd_flags != -1) + retval = fcntl (notify->pipefd[0], F_SETFL, fd_flags | O_NONBLOCK); + pgm_assert (notify->pipefd[0]); + return retval; +#else +/* use loopback sockets to simulate a pipe suitable for win32/select() */ + struct sockaddr_in addr; + SOCKET listener; + int sockerr; + int addrlen = sizeof (addr); + const unsigned long one = 1; + + pgm_assert (NULL != notify); + notify->s[0] = notify->s[1] = INVALID_SOCKET; + + listener = socket (AF_INET, SOCK_STREAM, 0); + pgm_assert (listener != INVALID_SOCKET); + + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr ("127.0.0.1"); + pgm_assert (addr.sin_addr.s_addr != INADDR_NONE); + + sockerr = bind (listener, (const struct sockaddr*)&addr, sizeof (addr)); + pgm_assert (sockerr != SOCKET_ERROR); + + sockerr = getsockname (listener, (struct sockaddr*)&addr, &addrlen); + pgm_assert (sockerr != SOCKET_ERROR); + +// Listen for incoming connections. + sockerr = listen (listener, 1); + pgm_assert (sockerr != SOCKET_ERROR); + +// Create the socket. + notify->s[1] = WSASocket (AF_INET, SOCK_STREAM, 0, NULL, 0, 0); + pgm_assert (notify->s[1] != INVALID_SOCKET); + +// Connect to the remote peer. + sockerr = connect (notify->s[1], (struct sockaddr*)&addr, addrlen); + pgm_assert (sockerr != SOCKET_ERROR); + +// Accept connection. + notify->s[0] = accept (listener, NULL, NULL); + pgm_assert (notify->s[0] != INVALID_SOCKET); + +// Set read-end to non-blocking mode +#pragma warning( disable : 4090 ) + sockerr = ioctlsocket (notify->s[0], FIONBIO, &one); +#pragma warning( default : 4090 ) + pgm_assert (sockerr != SOCKET_ERROR); + +// We don't need the listening socket anymore. Close it. + sockerr = closesocket (listener); + pgm_assert (sockerr != SOCKET_ERROR); + + return 0; +#endif +} + +static inline +int +pgm_notify_destroy ( + pgm_notify_t* notify + ) +{ + pgm_assert (NULL != notify); + +#if defined(CONFIG_HAVE_EVENTFD) + if (-1 != notify->eventfd) { + close (notify->eventfd); + notify->eventfd = -1; + } +#elif !defined(_WIN32) + if (-1 != notify->pipefd[0]) { + close (notify->pipefd[0]); + notify->pipefd[0] = -1; + } + if (-1 != notify->pipefd[1]) { + close (notify->pipefd[1]); + notify->pipefd[1] = -1; + } +#else + if (INVALID_SOCKET != notify->s[0]) { + closesocket (notify->s[0]); + notify->s[0] = INVALID_SOCKET; + } + if (INVALID_SOCKET != notify->s[1]) { + closesocket (notify->s[1]); + notify->s[1] = INVALID_SOCKET; + } +#endif + return 0; +} + +static inline +int +pgm_notify_send ( + pgm_notify_t* notify + ) +{ +#if defined(CONFIG_HAVE_EVENTFD) + uint64_t u = 1; + pgm_assert (NULL != notify); + pgm_assert (-1 != notify->eventfd); + ssize_t s = write (notify->eventfd, &u, sizeof(u)); + return (s == sizeof(u)); +#elif !defined(_WIN32) + const char one = '1'; + pgm_assert (NULL != notify); + pgm_assert (-1 != notify->pipefd[1]); + return (1 == write (notify->pipefd[1], &one, sizeof(one))); +#else + const char one = '1'; + pgm_assert (NULL != notify); + pgm_assert (INVALID_SOCKET != notify->s[1]); + return (1 == send (notify->s[1], &one, sizeof(one), 0)); +#endif +} + +static inline +int +pgm_notify_read ( + pgm_notify_t* notify + ) +{ +#if defined(CONFIG_HAVE_EVENTFD) + uint64_t u; + pgm_assert (NULL != notify); + pgm_assert (-1 != notify->eventfd); + return (sizeof(u) == read (notify->eventfd, &u, sizeof(u))); +#elif !defined(_WIN32) + char buf; + pgm_assert (NULL != notify); + pgm_assert (-1 != notify->pipefd[0]); + return (sizeof(buf) == read (notify->pipefd[0], &buf, sizeof(buf))); +#else + char buf; + pgm_assert (NULL != notify); + pgm_assert (INVALID_SOCKET != notify->s[0]); + return (sizeof(buf) == recv (notify->s[0], &buf, sizeof(buf), 0)); +#endif +} + +static inline +void +pgm_notify_clear ( + pgm_notify_t* notify + ) +{ +#if defined(CONFIG_HAVE_EVENTFD) + uint64_t u; + pgm_assert (NULL != notify); + pgm_assert (-1 != notify->eventfd); + while (sizeof(u) == read (notify->eventfd, &u, sizeof(u))); +#elif !defined(_WIN32) + char buf; + pgm_assert (NULL != notify); + pgm_assert (-1 != notify->pipefd[0]); + while (sizeof(buf) == read (notify->pipefd[0], &buf, sizeof(buf))); +#else + char buf; + pgm_assert (NULL != notify); + pgm_assert (INVALID_SOCKET != notify->s[0]); + while (sizeof(buf) == recv (notify->s[0], &buf, sizeof(buf), 0)); +#endif +} + +static inline +int +pgm_notify_get_fd ( + pgm_notify_t* notify + ) +{ + pgm_assert (NULL != notify); + +#if defined(CONFIG_HAVE_EVENTFD) + pgm_assert (-1 != notify->eventfd); + return notify->eventfd; +#elif !defined(_WIN32) + pgm_assert (-1 != notify->pipefd[0]); + return notify->pipefd[0]; +#else + pgm_assert (INVALID_SOCKET != notify->s[0]); + return notify->s[0]; +#endif +} + +PGM_END_DECLS + +#endif /* __PGM_IMPL_NOTIFY_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/packet_parse.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/packet_parse.h new file mode 100644 index 0000000..4416e21 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/packet_parse.h @@ -0,0 +1,45 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM packet formats, RFC 3208. + * + * Copyright (c) 2006 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_PACKET_PARSE_H__ +#define __PGM_IMPL_PACKET_PARSE_H__ + +#ifndef _WIN32 +# include +#endif +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL bool pgm_parse_raw (struct pgm_sk_buff_t*const restrict, struct sockaddr*const restrict, pgm_error_t**restrict); +PGM_GNUC_INTERNAL bool pgm_parse_udp_encap (struct pgm_sk_buff_t*const restrict, pgm_error_t**restrict); +PGM_GNUC_INTERNAL bool pgm_verify_spm (const struct pgm_sk_buff_t* const); +PGM_GNUC_INTERNAL bool pgm_verify_spmr (const struct pgm_sk_buff_t* const); +PGM_GNUC_INTERNAL bool pgm_verify_nak (const struct pgm_sk_buff_t* const); +PGM_GNUC_INTERNAL bool pgm_verify_nnak (const struct pgm_sk_buff_t* const); +PGM_GNUC_INTERNAL bool pgm_verify_ncf (const struct pgm_sk_buff_t* const); +PGM_GNUC_INTERNAL bool pgm_verify_poll (const struct pgm_sk_buff_t* const); +PGM_GNUC_INTERNAL bool pgm_verify_polr (const struct pgm_sk_buff_t* const); +PGM_GNUC_INTERNAL bool pgm_verify_ack (const struct pgm_sk_buff_t* const); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_PACKET_PARSE_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/packet_test.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/packet_test.h new file mode 100644 index 0000000..1b39006 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/packet_test.h @@ -0,0 +1,40 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM packet formats, RFC 3208. + * + * Copyright (c) 2006 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_PACKET_TEST_H__ +#define __PGM_IMPL_PACKET_TEST_H__ + +#ifndef _WIN32 +# include +#endif +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL bool pgm_print_packet (const void*, size_t); +PGM_GNUC_INTERNAL const char* pgm_type_string (uint8_t) PGM_GNUC_WARN_UNUSED_RESULT PGM_GNUC_CONST; +PGM_GNUC_INTERNAL const char* pgm_udpport_string (uint16_t) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL const char* pgm_gethostbyaddr (const struct in_addr*) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_ipopt_print (const void*, size_t); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_PACKET_TEST_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB.h new file mode 100644 index 0000000..6f80271 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB.h @@ -0,0 +1,28 @@ +/* + * Note: this file originally auto-generated by mib2c using + * : mib2c.notify.conf,v 5.3 2004/04/15 12:29:19 dts12 Exp $ + */ + +#ifndef __PGM_IMPL_MIB_H__ +#define __PGM_IMPL_MIB_H__ + +#include + +PGM_BEGIN_DECLS + +/* function declarations */ +PGM_GNUC_INTERNAL bool pgm_mib_init (pgm_error_t**); + +PGM_GNUC_INTERNAL int send_pgmStart_trap(void); +PGM_GNUC_INTERNAL int send_pgmStop_trap(void); +PGM_GNUC_INTERNAL int send_pgmNewSourceTrap_trap(void); +PGM_GNUC_INTERNAL int send_pgmClosedSourceTrap_trap(void); +PGM_GNUC_INTERNAL int send_pgmNewReceiverTrap_trap(void); +PGM_GNUC_INTERNAL int send_pgmClosedReceiverTrap_trap(void); +PGM_GNUC_INTERNAL int send_pgmNakFailuresTrap_trap(void); +PGM_GNUC_INTERNAL int send_pgmNewDlrSourceTrap_trap(void); +PGM_GNUC_INTERNAL int send_pgmClosedDlrSourceTrap_trap(void); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_MIB_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB_columns.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB_columns.h new file mode 100644 index 0000000..545e519 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB_columns.h @@ -0,0 +1,372 @@ +/* + * Note: this file originally auto-generated by mib2c using + * : mib2c.column_defines.conf,v 5.1 2002/05/08 05:42:47 hardaker Exp $ + */ +#ifndef PGMMIB_COLUMNS_H +#define PGMMIB_COLUMNS_H + +/* column number definitions for table pgmNeIfConfigTable */ + #define COLUMN_PGMNEIFCONFIGINDEX 1 + #define COLUMN_PGMNEIFPGMENABLE 2 + #define COLUMN_PGMNEIFNAKRPTINTERVAL 3 + #define COLUMN_PGMNEIFNAKRPTRATE 4 + #define COLUMN_PGMNEIFNAKRDATAINTERVAL 5 + #define COLUMN_PGMNEIFNAKELIMINATEINTERVAL 6 + +/* column number definitions for table pgmNeIfPerformanceTable */ + #define COLUMN_PGMNEIFPERFORMANCEINDEX 1 + #define COLUMN_PGMNEIFREXMITSTATES 2 + #define COLUMN_PGMNEIFREXMITTIMEDOUT 3 + #define COLUMN_PGMNEIFINSPMS 4 + #define COLUMN_PGMNEIFOUTSPMS 5 + #define COLUMN_PGMNEIFINPARITYSPMS 6 + #define COLUMN_PGMNEIFOUTPARITYSPMS 7 + #define COLUMN_PGMNEIFINRDATA 8 + #define COLUMN_PGMNEIFOUTRDATA 9 + #define COLUMN_PGMNEIFINPARITYRDATA 10 + #define COLUMN_PGMNEIFOUTPARITYRDATA 11 + #define COLUMN_PGMNEIFINRDATANOSESSIONERRORS 12 + #define COLUMN_PGMNEIFUNIQUENAKS 13 + #define COLUMN_PGMNEIFINNAKS 14 + #define COLUMN_PGMNEIFOUTNAKS 15 + #define COLUMN_PGMNEIFUNIQUEPARITYNAKS 16 + #define COLUMN_PGMNEIFINPARITYNAKS 17 + #define COLUMN_PGMNEIFOUTPARITYNAKS 18 + #define COLUMN_PGMNEIFINNAKNOSESSIONERRORS 19 + #define COLUMN_PGMNEIFINNAKSEQERRORS 20 + #define COLUMN_PGMNEIFINPARITYNAKTGERRORS 21 + #define COLUMN_PGMNEIFINNNAKS 22 + #define COLUMN_PGMNEIFOUTNNAKS 23 + #define COLUMN_PGMNEIFINPARITYNNAKS 24 + #define COLUMN_PGMNEIFOUTPARITYNNAKS 25 + #define COLUMN_PGMNEIFINNNAKNOSESSIONERRORS 26 + #define COLUMN_PGMNEIFINNCFS 27 + #define COLUMN_PGMNEIFOUTNCFS 28 + #define COLUMN_PGMNEIFINPARITYNCFS 29 + #define COLUMN_PGMNEIFOUTPARITYNCFS 30 + #define COLUMN_PGMNEIFINNCFNOSESSIONERRORS 31 + #define COLUMN_PGMNEIFINREDIRECTNCFS 32 + #define COLUMN_PGMNEIFMALFORMED 33 + #define COLUMN_PGMNEIFSPMFROMSOURCE 34 + #define COLUMN_PGMNEIFSPMBADSQN 35 + #define COLUMN_PGMNEIFSPMERROR 36 + #define COLUMN_PGMNEIFPOLLRANDOMIGNORE 37 + #define COLUMN_PGMNEIFPOLLTSISTATEERROR 38 + #define COLUMN_PGMNEIFPOLLPARENTERROR 39 + #define COLUMN_PGMNEIFPOLLTYPEERROR 40 + #define COLUMN_PGMNEIFPOLLERROR 41 + #define COLUMN_PGMNEIFPOLLSUCCESS 42 + #define COLUMN_PGMNEIFPOLLORIGINATED 43 + #define COLUMN_PGMNEIFPOLRNOSTATE 44 + #define COLUMN_PGMNEIFPOLRERROR 45 + #define COLUMN_PGMNEIFPOLRPARITYERROR 46 + #define COLUMN_PGMNEIFPOLRSUCCESS 47 + #define COLUMN_PGMNEIFPOLRORIGINATED 48 + #define COLUMN_PGMNEIFNCFERROR 49 + #define COLUMN_PGMNEIFNCFPARITYERROR 50 + #define COLUMN_PGMNEIFNCFPARTIALPARITY 51 + #define COLUMN_PGMNEIFNCFRECEIVED 52 + #define COLUMN_PGMNEIFNCFANTICIPATED 53 + #define COLUMN_PGMNEIFNCFREDIRECTING 54 + #define COLUMN_PGMNEIFNAKELIMINATED 55 + #define COLUMN_PGMNEIFNAKERROR 56 + #define COLUMN_PGMNEIFNAKPARITYERROR 57 + #define COLUMN_PGMNEIFNNAKELIMINATED 58 + #define COLUMN_PGMNEIFNNAKERROR 59 + #define COLUMN_PGMNEIFNNAKPARITYERROR 60 + #define COLUMN_PGMNEIFNNAKCONGESTIONREPORTS 61 + #define COLUMN_PGMNEIFNAKRETRYEXPIRED 62 + #define COLUMN_PGMNEIFNAKRETRYEXPIREDDLR 63 + #define COLUMN_PGMNEIFNAKFORWARDEDDLR 64 + #define COLUMN_PGMNEIFNAKRETRANSMITTED 65 + #define COLUMN_PGMNEIFRDATAELIMINATEDOIF 66 + #define COLUMN_PGMNEIFRDATAELIMINATEDSQN 67 + #define COLUMN_PGMNEIFINRDATAFRAGMENTS 68 + #define COLUMN_PGMNEIFRDATAFRAGMENTSNOSESSIONERRORS 69 + #define COLUMN_PGMNEIFRDATAFRAGMENTSELIMINATEDOIF 70 + #define COLUMN_PGMNEIFRDATAFRAGMENTSELIMINATEDSQN 71 + #define COLUMN_PGMNEIFOUTRDATAFRAGMENTS 72 + +/* column number definitions for table pgmNeTsiTable */ + #define COLUMN_PGMNETSIGLOBALID 1 + #define COLUMN_PGMNETSIDATASOURCEPORT 2 + #define COLUMN_PGMNETSISTATEBITS 3 + #define COLUMN_PGMNETSIDATADESTINATIONPORT 4 + #define COLUMN_PGMNETSISOURCEADDRESS 5 + #define COLUMN_PGMNETSIGROUPADDRESS 6 + #define COLUMN_PGMNETSIUPSTREAMADDRESS 7 + #define COLUMN_PGMNETSIUPSTREAMIFINDEX 8 + #define COLUMN_PGMNETSIDLRADDRESS 9 + +/* column number definitions for table pgmNeTsiPerformanceTable */ + #define COLUMN_PGMNETSIPERFORMANCEGLOBALID 1 + #define COLUMN_PGMNETSIPERFORMANCEDATASOURCEPORT 2 + #define COLUMN_PGMNETSISESSIONTRAILEDGESEQ 3 + #define COLUMN_PGMNETSISESSIONINCRSEQ 4 + #define COLUMN_PGMNETSILEADEDGESEQ 5 + #define COLUMN_PGMNETSIINSPMS 6 + #define COLUMN_PGMNETSIOUTSPMS 7 + #define COLUMN_PGMNETSIINPARITYSPMS 8 + #define COLUMN_PGMNETSIOUTPARITYSPMS 9 + #define COLUMN_PGMNETSITOTALREXMITSTATES 10 + #define COLUMN_PGMNETSITOTALREXMITTIMEDOUT 11 + #define COLUMN_PGMNETSIINRDATA 12 + #define COLUMN_PGMNETSIOUTRDATA 13 + #define COLUMN_PGMNETSIINPARITYRDATA 14 + #define COLUMN_PGMNETSIOUTPARITYRDATA 15 + #define COLUMN_PGMNETSIINRDATANOSTATEERRORS 16 + #define COLUMN_PGMNETSIUNIQUENAKS 17 + #define COLUMN_PGMNETSIINNAKS 18 + #define COLUMN_PGMNETSIOUTNAKS 19 + #define COLUMN_PGMNETSIUNIQUEPARITYNAKS 20 + #define COLUMN_PGMNETSIINPARITYNAKS 21 + #define COLUMN_PGMNETSIOUTPARITYNAKS 22 + #define COLUMN_PGMNETSIINNAKSEQERRORS 23 + #define COLUMN_PGMNETSIINNNAKS 24 + #define COLUMN_PGMNETSIOUTNNAKS 25 + #define COLUMN_PGMNETSIINPARITYNNAKS 26 + #define COLUMN_PGMNETSIOUTPARITYNNAKS 27 + #define COLUMN_PGMNETSIINNCFS 28 + #define COLUMN_PGMNETSIOUTNCFS 29 + #define COLUMN_PGMNETSIINPARITYNCFS 30 + #define COLUMN_PGMNETSIOUTPARITYNCFS 31 + #define COLUMN_PGMNETSISPMSEQUENCENUMBER 32 + #define COLUMN_PGMNETSITRANSMISSIONGROUPSIZE 33 + #define COLUMN_PGMNETSITIMEOUT 34 + #define COLUMN_PGMNETSILASTTTL 35 + #define COLUMN_PGMNETSILINKLOSSRATE 36 + #define COLUMN_PGMNETSIPATHLOSSRATE 37 + #define COLUMN_PGMNETSIRECEIVERLOSSRATE 38 + #define COLUMN_PGMNETSICONGESTIONREPORTLEAD 39 + #define COLUMN_PGMNETSICONGESTIONREPORTWORSTRECEIVER 40 + +/* column number definitions for table pgmNeTsiRtxTable */ + #define COLUMN_PGMNETSIRTXSEQUENCENUMBER 1 + #define COLUMN_PGMNETSIRTXSEQUENCENUMBERTYPE 2 + #define COLUMN_PGMNETSIRTXREQPARITYTGCOUNT 4 + #define COLUMN_PGMNETSIRTXTIMEOUT 5 + #define COLUMN_PGMNETSIRTXSTATEBITS 6 + +/* column number definitions for table pgmNeTsiRtxIfTable */ + #define COLUMN_PGMNETSIRTXIFINDEX 1 + #define COLUMN_PGMNETSIRTXIFPACKETCOUNT 2 + +/* column number definitions for table pgmNeTsiPolrTable */ + #define COLUMN_PGMNETSIPOLRSOURCE 1 + #define COLUMN_PGMNETSIPOLRSEQUENCENUMBER 2 + +/* column number definitions for table pgmNeTsiPollTable */ + #define COLUMN_PGMNETSIPOLLTYPE 1 + #define COLUMN_PGMNETSIPOLLSEQUENCE 2 + #define COLUMN_PGMNETSIPOLLCHILDBACKOFF 3 + #define COLUMN_PGMNETSIPOLLMASK 4 + #define COLUMN_PGMNETSIPOLLPERIOD 5 + #define COLUMN_PGMNETSIPOLLCOUNT 6 + #define COLUMN_PGMNETSIPOLLTIMEOUT 7 + +/* column number definitions for table pgmSourceTable */ + #define COLUMN_PGMSOURCEGLOBALID 1 + #define COLUMN_PGMSOURCESOURCEPORT 2 + #define COLUMN_PGMSOURCESOURCEADDRESS 3 + #define COLUMN_PGMSOURCEGROUPADDRESS 4 + #define COLUMN_PGMSOURCEDESTPORT 5 + #define COLUMN_PGMSOURCESOURCEGSI 6 + #define COLUMN_PGMSOURCESOURCEPORTNUMBER 7 + +/* column number definitions for table pgmSourceConfigTable */ + #define COLUMN_PGMSOURCECONFIGGLOBALID 1 + #define COLUMN_PGMSOURCECONFIGSOURCEPORT 2 + #define COLUMN_PGMSOURCETTL 3 + #define COLUMN_PGMSOURCEADVMODE 4 + #define COLUMN_PGMSOURCELATEJOIN 5 + #define COLUMN_PGMSOURCETXWMAXRTE 6 + #define COLUMN_PGMSOURCETXWSECS 7 + #define COLUMN_PGMSOURCETXWADVSECS 8 + #define COLUMN_PGMSOURCEADVIVL 9 + #define COLUMN_PGMSOURCESPMIVL 10 + #define COLUMN_PGMSOURCESPMHEARTBEATIVLMIN 11 + #define COLUMN_PGMSOURCESPMHEARTBEATIVLMAX 12 + #define COLUMN_PGMSOURCERDATABACKOFFIVL 13 + #define COLUMN_PGMSOURCEFEC 14 + #define COLUMN_PGMSOURCEFECTRANSMISSIONGRPSIZE 15 + #define COLUMN_PGMSOURCEFECPROACTIVEPARITYSIZE 16 + #define COLUMN_PGMSOURCESPMPATHADDRESS 17 + +/* column number definitions for table pgmSourcePerformanceTable */ + #define COLUMN_PGMSOURCEPERFORMANCEGLOBALID 1 + #define COLUMN_PGMSOURCEPERFORMANCESOURCEPORT 2 + #define COLUMN_PGMSOURCEDATABYTESSENT 3 + #define COLUMN_PGMSOURCEDATAMSGSSENT 4 + #define COLUMN_PGMSOURCEBYTESBUFFERED 5 + #define COLUMN_PGMSOURCEMSGSBUFFERED 6 + #define COLUMN_PGMSOURCEBYTESRETRANSMITTED 7 + #define COLUMN_PGMSOURCEMSGSRETRANSMITTED 8 + #define COLUMN_PGMSOURCEBYTESSENT 9 + #define COLUMN_PGMSOURCERAWNAKSRECEIVED 10 + #define COLUMN_PGMSOURCENAKSIGNORED 11 + #define COLUMN_PGMSOURCECKSUMERRORS 12 + #define COLUMN_PGMSOURCEMALFORMEDNAKS 13 + #define COLUMN_PGMSOURCEPACKETSDISCARDED 14 + #define COLUMN_PGMSOURCENAKSRCVD 15 + #define COLUMN_PGMSOURCEPARITYBYTESRETRANSMITTED 16 + #define COLUMN_PGMSOURCESELECTIVEBYTESRETRANSMITED 17 + #define COLUMN_PGMSOURCEPARITYMSGSRETRANSMITTED 18 + #define COLUMN_PGMSOURCESELECTIVEMSGSRETRANSMITTED 19 + #define COLUMN_PGMSOURCEBYTESADMIT 20 + #define COLUMN_PGMSOURCEMSGSADMIT 21 + #define COLUMN_PGMSOURCEPARITYNAKPACKETSRECEIVED 22 + #define COLUMN_PGMSOURCESELECTIVENAKPACKETSRECEIVED 23 + #define COLUMN_PGMSOURCEPARITYNAKSRECEIVED 24 + #define COLUMN_PGMSOURCESELECTIVENAKSRECEIVED 25 + #define COLUMN_PGMSOURCEPARITYNAKSIGNORED 26 + #define COLUMN_PGMSOURCESELECTIVENAKSIGNORED 27 + #define COLUMN_PGMSOURCEACKERRORS 28 + #define COLUMN_PGMSOURCEPGMCCACKER 29 + #define COLUMN_PGMSOURCETRANSMISSIONCURRENTRATE 30 + #define COLUMN_PGMSOURCEACKPACKETSRECEIVED 31 + #define COLUMN_PGMSOURCENNAKPACKETSRECEIVED 32 + #define COLUMN_PGMSOURCEPARITYNNAKPACKETSRECEIVED 33 + #define COLUMN_PGMSOURCESELECTIVENNAKPACKETSRECEIVED 34 + #define COLUMN_PGMSOURCENNAKSRECEIVED 35 + #define COLUMN_PGMSOURCEPARITYNNAKSRECEIVED 36 + #define COLUMN_PGMSOURCESELECTIVENNAKSRECEIVED 37 + #define COLUMN_PGMSOURCENNAKERRORS 38 + +/* column number definitions for table pgmReceiverTable */ + #define COLUMN_PGMRECEIVERGLOBALID 1 + #define COLUMN_PGMRECEIVERSOURCEPORT 2 + #define COLUMN_PGMRECEIVERINSTANCE 3 + #define COLUMN_PGMRECEIVERGROUPADDRESS 4 + #define COLUMN_PGMRECEIVERDESTPORT 5 + #define COLUMN_PGMRECEIVERSOURCEADDRESS 6 + #define COLUMN_PGMRECEIVERLASTHOP 7 + #define COLUMN_PGMRECEIVERSOURCEGSI 8 + #define COLUMN_PGMRECEIVERSOURCEPORTNUMBER 9 + #define COLUMN_PGMRECEIVERUNIQUEINSTANCE 10 + +/* column number definitions for table pgmReceiverConfigTable */ + #define COLUMN_PGMRECEIVERCONFIGGLOBALID 1 + #define COLUMN_PGMRECEIVERCONFIGSOURCEPORT 2 + #define COLUMN_PGMRECEIVERCONFIGINSTANCE 3 + #define COLUMN_PGMRECEIVERNAKBACKOFFIVL 4 + #define COLUMN_PGMRECEIVERNAKREPEATIVL 5 + #define COLUMN_PGMRECEIVERNAKNCFRETRIES 6 + #define COLUMN_PGMRECEIVERNAKRDATAIVL 7 + #define COLUMN_PGMRECEIVERNAKDATARETRIES 8 + #define COLUMN_PGMRECEIVERSENDNAKS 9 + #define COLUMN_PGMRECEIVERLATEJOIN 10 + #define COLUMN_PGMRECEIVERNAKTTL 11 + #define COLUMN_PGMRECEIVERDELIVERYORDER 12 + #define COLUMN_PGMRECEIVERMCASTNAKS 13 + #define COLUMN_PGMRECEIVERNAKFAILURETHRESHOLDTIMER 14 + #define COLUMN_PGMRECEIVERNAKFAILURETHRESHOLD 15 + +/* column number definitions for table pgmReceiverPerformanceTable */ + #define COLUMN_PGMRECEIVERPERFORMANCEGLOBALID 1 + #define COLUMN_PGMRECEIVERPERFORMANCESOURCEPORT 2 + #define COLUMN_PGMRECEIVERPERFORMANCEINSTANCE 3 + #define COLUMN_PGMRECEIVERDATABYTESRECEIVED 4 + #define COLUMN_PGMRECEIVERDATAMSGSRECEIVED 5 + #define COLUMN_PGMRECEIVERNAKSSENT 6 + #define COLUMN_PGMRECEIVERNAKSRETRANSMITTED 7 + #define COLUMN_PGMRECEIVERNAKFAILURES 8 + #define COLUMN_PGMRECEIVERBYTESRECEIVED 9 + #define COLUMN_PGMRECEIVERNAKSSUPPRESSED 10 + #define COLUMN_PGMRECEIVERCKSUMERRORS 11 + #define COLUMN_PGMRECEIVERMALFORMEDSPMS 12 + #define COLUMN_PGMRECEIVERMALFORMEDODATA 13 + #define COLUMN_PGMRECEIVERMALFORMEDRDATA 14 + #define COLUMN_PGMRECEIVERMALFORMEDNCFS 15 + #define COLUMN_PGMRECEIVERPACKETSDISCARDED 16 + #define COLUMN_PGMRECEIVERLOSSES 17 + #define COLUMN_PGMRECEIVERBYTESDELIVEREDTOAPP 18 + #define COLUMN_PGMRECEIVERMSGSDELIVEREDTOAPP 19 + #define COLUMN_PGMRECEIVERDUPSPMS 20 + #define COLUMN_PGMRECEIVERDUPDATAS 21 + #define COLUMN_PGMRECEIVERDUPPARITIES 22 + #define COLUMN_PGMRECEIVERNAKPACKETSSENT 23 + #define COLUMN_PGMRECEIVERPARITYNAKPACKETSSENT 24 + #define COLUMN_PGMRECEIVERSELECTIVENAKPACKETSSENT 25 + #define COLUMN_PGMRECEIVERPARITYNAKSSENT 26 + #define COLUMN_PGMRECEIVERSELECTIVENAKSSENT 27 + #define COLUMN_PGMRECEIVERPARITYNAKSRETRANSMITTED 28 + #define COLUMN_PGMRECEIVERSELECTIVENAKSRETRANSMITTED 29 + #define COLUMN_PGMRECEIVERNAKSFAILED 30 + #define COLUMN_PGMRECEIVERPARITYNAKSFAILED 31 + #define COLUMN_PGMRECEIVERSELECTIVENAKSFAILED 32 + #define COLUMN_PGMRECEIVERNAKSFAILEDRXWADVANCED 33 + #define COLUMN_PGMRECEIVERNAKSFALEDNCFRETRIESEXCEEDED 34 + #define COLUMN_PGMRECEIVERNAKSFAILEDDATARETRIESEXCEEDED 35 + #define COLUMN_PGMRECEIVERNAKSFAILEDGENEXPIRED 36 + #define COLUMN_PGMRECEIVERNAKFAILURESDELIVERED 37 + #define COLUMN_PGMRECEIVERPARITYNAKSSUPPRESSED 38 + #define COLUMN_PGMRECEIVERSELECTIVENAKSSUPPRESSED 39 + #define COLUMN_PGMRECEIVERNAKERRORS 40 + #define COLUMN_PGMRECEIVEROUTSTANDINGPARITYNAKS 41 + #define COLUMN_PGMRECEIVEROUTSTANDINGSELECTIVENAKS 42 + #define COLUMN_PGMRECEIVERLASTACTIVITY 43 + #define COLUMN_PGMRECEIVERNAKSVCTIMEMIN 44 + #define COLUMN_PGMRECEIVERNAKSVCTIMEMEAN 45 + #define COLUMN_PGMRECEIVERNAKSVCTIMEMAX 46 + #define COLUMN_PGMRECEIVERNAKFAILTIMEMIN 47 + #define COLUMN_PGMRECEIVERNAKFAILTIMEMEAN 48 + #define COLUMN_PGMRECEIVERNAKFAILTIMEMAX 49 + #define COLUMN_PGMRECEIVERNAKTRANSMITMIN 50 + #define COLUMN_PGMRECEIVERNAKTRANSMITMEAN 51 + #define COLUMN_PGMRECEIVERNAKTRANSMITMAX 52 + #define COLUMN_PGMRECEIVERACKSSENT 53 + #define COLUMN_PGMRECEIVERRXWTRAIL 54 + #define COLUMN_PGMRECEIVERRXWLEAD 55 + #define COLUMN_PGMRECEIVERNAKFAILURESLASTINTERVAL 56 + #define COLUMN_PGMRECEIVERLASTINTERVALNAKFAILURES 57 + +/* column number definitions for table pgmDlrSourceTable */ + #define COLUMN_PGMDLRSOURCEGLOBALID 1 + #define COLUMN_PGMDLRSOURCESOURCEPORT 2 + #define COLUMN_PGMDLRSOURCEGROUPADDRESS 3 + #define COLUMN_PGMDLRSOURCESOURCEGSI 4 + #define COLUMN_PGMDLRSOURCESOURCEPORTNUMBER 5 + +/* column number definitions for table pgmDlrSourceConfigTable */ + #define COLUMN_PGMDLRSOURCECONFIGGLOBALID 1 + #define COLUMN_PGMDLRSOURCECONFIGSOURCEPORT 2 + #define COLUMN_PGMDLRSOURCEGROUPTTL 3 + #define COLUMN_PGMDLRSOURCERDATABACKOFFIVL 4 + +/* column number definitions for table pgmDlrSourcePerformanceTable */ + #define COLUMN_PGMDLRSOURCEPERFORMANCEGLOBALID 1 + #define COLUMN_PGMDLRSOURCEPERFORMANCESOURCEPORT 2 + #define COLUMN_PGMDLRSOURCERDATAMSGSSENT 3 + #define COLUMN_PGMDLRSOURCERDATABYTESSENT 4 + #define COLUMN_PGMDLRSOURCEBYTESSENT 5 + #define COLUMN_PGMDLRSOURCENAKSRCVD 6 + #define COLUMN_PGMDLRSOURCENAKSIGNORED 7 + #define COLUMN_PGMDLRSOURCENAKERRORS 8 + #define COLUMN_PGMDLRSOURCEDISCARDS 9 + #define COLUMN_PGMDLRSOURCECKSUMERRORS 10 + #define COLUMN_PGMDLRSOURCENNAKSSENT 11 + #define COLUMN_PGMDLRSOURCEBYTESBUFFERED 12 + #define COLUMN_PGMDLRSOURCEMSGSBUFFERED 13 + #define COLUMN_PGMDLRSOURCEPARITYBYTESRETRANSMITTED 14 + #define COLUMN_PGMDLRSOURCESELECTIVEBYTESRETRANSMITED 15 + #define COLUMN_PGMDLRSOURCEPARITYMSGSRETRANSMITTED 16 + #define COLUMN_PGMDLRSOURCESELECTIVEMSGSRETRANSMITTED 17 + #define COLUMN_PGMDLRSOURCEBYTESADMIT 18 + #define COLUMN_PGMDLRSOURCEMSGSADMIT 19 + #define COLUMN_PGMDLRSOURCENAKPACKETSRECEIVED 20 + #define COLUMN_PGMDLRSOURCEPARITYNAKPACKETSRECEIVED 21 + #define COLUMN_PGMDLRSOURCESELECTIVENAKPACKETSRECEIVED 22 + #define COLUMN_PGMDLRSOURCEPARITYNAKSRECEIVED 23 + #define COLUMN_PGMDLRSOURCESELECTIVENAKSRECEIVED 24 + #define COLUMN_PGMDLRSOURCEPARITYNAKSIGNORED 25 + #define COLUMN_PGMDLRSOURCESELECTIVENAKSIGNORED 26 + #define COLUMN_PGMDLRSOURCEACKERRORS 27 + #define COLUMN_PGMDLRSOURCENNAKERRORS 28 + #define COLUMN_PGMDLRSOURCEACKPACKETSRECEIVED 29 + #define COLUMN_PGMDLRSOURCENNAKPACKETSRECEIVED 30 + #define COLUMN_PGMDLRSOURCEPARITYNNAKPACKETSRECEIVED 31 + #define COLUMN_PGMDLRSOURCESELECTIVENNAKPACKETSRECEIVED 32 + #define COLUMN_PGMDLRSOURCENNAKSRECEIVED 33 + #define COLUMN_PGMDLRSOURCEPARITYNNAKSRECEIVED 34 + #define COLUMN_PGMDLRSOURCESELECTIVENNAKSRECEIVED 35 +#endif /* PGMMIB_COLUMNS_H */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB_enums.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB_enums.h new file mode 100644 index 0000000..9ae5760 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/pgmMIB_enums.h @@ -0,0 +1,64 @@ +/* + * Note: this file originally auto-generated by mib2c using + * : mib2c.column_enums.conf,v 5.2 2003/02/22 04:09:25 hardaker Exp $ + */ +#ifndef PGMMIB_ENUMS_H +#define PGMMIB_ENUMS_H + +/* enums for column pgmNeIfPgmEnable */ + #define PGMNEIFPGMENABLE_ENABLE 1 + #define PGMNEIFPGMENABLE_DISABLE 2 + +/* enums for column pgmNeTsiStateBits */ + #define PGMNETSISTATEBITS_INITIALISING 0 + #define PGMNETSISTATEBITS_SPMSQNSTATEVALID 1 + #define PGMNETSISTATEBITS_DLRCANPROVIDEPARITY 2 + +/* enums for column pgmNeTsiRtxSequenceNumberType */ + #define PGMNETSIRTXSEQUENCENUMBERTYPE_SELECTIVE 1 + #define PGMNETSIRTXSEQUENCENUMBERTYPE_TG 2 + +/* enums for column pgmNeTsiRtxStateBits */ + #define PGMNETSIRTXSTATEBITS_INITIALISING 0 + #define PGMNETSIRTXSTATEBITS_ELIMINATING 1 + #define PGMNETSIRTXSTATEBITS_REDIRECTING 2 + #define PGMNETSIRTXSTATEBITS_STATECREATEDBYNULLNAK 3 + #define PGMNETSIRTXSTATEBITS_LISTNAKENTRY 4 + #define PGMNETSIRTXSTATEBITS_PARITYSTATE 5 + +/* enums for column pgmNeTsiPollType */ + #define PGMNETSIPOLLTYPE_GENERAL 1 + #define PGMNETSIPOLLTYPE_DLR 2 + +/* enums for column pgmSourceAdvMode */ + #define PGMSOURCEADVMODE_DATA 1 + #define PGMSOURCEADVMODE_TIME 2 + #define PGMSOURCEADVMODE_APPLCTRL 3 + #define PGMSOURCEADVMODE_OTHER 4 + +/* enums for column pgmSourceLateJoin */ + #define PGMSOURCELATEJOIN_ENABLE 1 + #define PGMSOURCELATEJOIN_DISABLE 2 + +/* enums for column pgmSourceFEC */ + #define PGMSOURCEFEC_DISABLED 1 + #define PGMSOURCEFEC_ENABLEDFIXEDPACKETSIZE 2 + #define PGMSOURCEFEC_ENABLEDVARIABLEPACKETSIZE 3 + +/* enums for column pgmReceiverSendNaks */ + #define PGMRECEIVERSENDNAKS_ENABLED 1 + #define PGMRECEIVERSENDNAKS_DISABLED 2 + +/* enums for column pgmReceiverLateJoin */ + #define PGMRECEIVERLATEJOIN_ENABLED 1 + #define PGMRECEIVERLATEJOIN_DISABLED 2 + +/* enums for column pgmReceiverDeliveryOrder */ + #define PGMRECEIVERDELIVERYORDER_UNORDERED 1 + #define PGMRECEIVERDELIVERYORDER_ORDERED 2 + +/* enums for column pgmReceiverMcastNaks */ + #define PGMRECEIVERMCASTNAKS_ENABLED 1 + #define PGMRECEIVERMCASTNAKS_DISABLED 2 + +#endif /* PGMMIB_ENUMS_H */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/processor.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/processor.h new file mode 100644 index 0000000..f7ee31a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/processor.h @@ -0,0 +1,61 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Processor macros for cross-platform, cross-compiler froyo. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_PROCESSOR_H__ +#define __PGM_IMPL_PROCESSOR_H__ + +/* Memory prefetch */ +#if defined( sun ) +static inline void pgm_prefetch (const void *x) +{ + asm volatile ( "prefetch [%0], #one_write" + : /* nil */ + : "r" (x)); +} +static inline void pgm_prefetchw (const void *x) +{ + asm volatile ( "prefetch [%0], #n_writes" + : /* nil */ + : "r" (x)); +} +#elif defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +static inline void pgm_prefetch (const void *x) +{ + __builtin_prefetch (x, 0 /* read */, 0 /* no temporal locality */); +} +static inline void pgm_prefetchw (const void *x) +{ + __builtin_prefetch (x, 1 /* write */, 3 /* high temporal */); +} +#else +static inline void pgm_prefetch (PGM_GNUC_UNUSED const void *x) +{ +} +static inline void pgm_prefetchw (PGM_GNUC_UNUSED const void *x) +{ +} +#endif + +#endif /* __PGM_IMPL_PROCESSOR_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/queue.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/queue.h new file mode 100644 index 0000000..c640e52 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/queue.h @@ -0,0 +1,51 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable double-ended queue. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_QUEUE_H__ +#define __PGM_IMPL_QUEUE_H__ + +typedef struct pgm_queue_t pgm_queue_t; + +#include +#include + +PGM_BEGIN_DECLS + +struct pgm_queue_t +{ + pgm_list_t* head; /* head & tail equal on 1 element */ + pgm_list_t* tail; + unsigned length; +}; + +PGM_GNUC_INTERNAL bool pgm_queue_is_empty (const pgm_queue_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_queue_push_head_link (pgm_queue_t*restrict, pgm_list_t*restrict); +PGM_GNUC_INTERNAL pgm_list_t* pgm_queue_pop_tail_link (pgm_queue_t*); +PGM_GNUC_INTERNAL pgm_list_t* pgm_queue_peek_tail_link (pgm_queue_t*) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_queue_unlink (pgm_queue_t*restrict, pgm_list_t*restrict); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_QUEUE_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/rand.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/rand.h new file mode 100644 index 0000000..0adfd78 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/rand.h @@ -0,0 +1,50 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable weak pseudo-random generator. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_RAND_H__ +#define __PGM_IMPL_RAND_H__ + +typedef struct pgm_rand_t pgm_rand_t; + +#include + +PGM_BEGIN_DECLS + +struct pgm_rand_t { + uint32_t seed; +}; + +PGM_GNUC_INTERNAL void pgm_rand_create (pgm_rand_t*); +PGM_GNUC_INTERNAL uint32_t pgm_rand_int (pgm_rand_t*); +PGM_GNUC_INTERNAL int32_t pgm_rand_int_range (pgm_rand_t*, int32_t, int32_t); +PGM_GNUC_INTERNAL uint32_t pgm_random_int (void); +PGM_GNUC_INTERNAL int32_t pgm_random_int_range (int32_t, int32_t); + +PGM_GNUC_INTERNAL void pgm_rand_init (void); +PGM_GNUC_INTERNAL void pgm_rand_shutdown (void); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_RAND_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/rate_control.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/rate_control.h new file mode 100644 index 0000000..b27b266 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/rate_control.h @@ -0,0 +1,54 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Rate regulation. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_RATE_CONTROL_H__ +#define __PGM_IMPL_RATE_CONTROL_H__ + +typedef struct pgm_rate_t pgm_rate_t; + +#include +#include +#include + +PGM_BEGIN_DECLS + +struct pgm_rate_t { + ssize_t rate_per_sec; + ssize_t rate_per_msec; + size_t iphdr_len; + + ssize_t rate_limit; /* signed for math */ + pgm_time_t last_rate_check; + pgm_spinlock_t spinlock; +}; + +PGM_GNUC_INTERNAL void pgm_rate_create (pgm_rate_t*, const ssize_t, const size_t, const uint16_t); +PGM_GNUC_INTERNAL void pgm_rate_destroy (pgm_rate_t*); +PGM_GNUC_INTERNAL bool pgm_rate_check (pgm_rate_t*, const size_t, const bool); +PGM_GNUC_INTERNAL pgm_time_t pgm_rate_remaining (pgm_rate_t*, const size_t); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_RATE_CONTROL_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/receiver.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/receiver.h new file mode 100644 index 0000000..e9c3a75 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/receiver.h @@ -0,0 +1,142 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM receiver socket. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_RECEIVER_H__ +#define __PGM_IMPL_RECEIVER_H__ + +typedef struct pgm_peer_t pgm_peer_t; + +#ifndef _WIN32 +# include +#endif +#include +#include + +PGM_BEGIN_DECLS + +/* Performance Counters */ + +enum { + PGM_PC_RECEIVER_DATA_BYTES_RECEIVED, + PGM_PC_RECEIVER_DATA_MSGS_RECEIVED, + PGM_PC_RECEIVER_NAK_FAILURES, + PGM_PC_RECEIVER_BYTES_RECEIVED, +/* PGM_PC_RECEIVER_CKSUM_ERRORS, */ /* inherently same as source */ + PGM_PC_RECEIVER_MALFORMED_SPMS, + PGM_PC_RECEIVER_MALFORMED_ODATA, + PGM_PC_RECEIVER_MALFORMED_RDATA, + PGM_PC_RECEIVER_MALFORMED_NCFS, + PGM_PC_RECEIVER_PACKETS_DISCARDED, + PGM_PC_RECEIVER_LOSSES, +/* PGM_PC_RECEIVER_BYTES_DELIVERED_TO_APP, */ +/* PGM_PC_RECEIVER_MSGS_DELIVERED_TO_APP, */ + PGM_PC_RECEIVER_DUP_SPMS, + PGM_PC_RECEIVER_DUP_DATAS, + PGM_PC_RECEIVER_PARITY_NAK_PACKETS_SENT, + PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT, + PGM_PC_RECEIVER_PARITY_NAKS_SENT, + PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT, + PGM_PC_RECEIVER_PARITY_NAKS_RETRANSMITTED, + PGM_PC_RECEIVER_SELECTIVE_NAKS_RETRANSMITTED, + PGM_PC_RECEIVER_PARITY_NAKS_FAILED, + PGM_PC_RECEIVER_SELECTIVE_NAKS_FAILED, + PGM_PC_RECEIVER_NAKS_FAILED_RXW_ADVANCED, + PGM_PC_RECEIVER_NAKS_FAILED_NCF_RETRIES_EXCEEDED, + PGM_PC_RECEIVER_NAKS_FAILED_DATA_RETRIES_EXCEEDED, +/* PGM_PC_RECEIVER_NAKS_FAILED_GEN_EXPIRED */ + PGM_PC_RECEIVER_NAK_FAILURES_DELIVERED, + PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED, + PGM_PC_RECEIVER_NAK_ERRORS, +/* PGM_PC_RECEIVER_LAST_ACTIVITY, */ +/* PGM_PC_RECEIVER_NAK_SVC_TIME_MIN, */ + PGM_PC_RECEIVER_NAK_SVC_TIME_MEAN, +/* PGM_PC_RECEIVER_NAK_SVC_TIME_MAX, */ +/* PGM_PC_RECEIVER_NAK_FAIL_TIME_MIN, */ + PGM_PC_RECEIVER_NAK_FAIL_TIME_MEAN, +/* PGM_PC_RECEIVER_NAK_FAIL_TIME_MAX, */ +/* PGM_PC_RECEIVER_TRANSMIT_MIN, */ + PGM_PC_RECEIVER_TRANSMIT_MEAN, +/* PGM_PC_RECEIVER_TRANSMIT_MAX, */ + PGM_PC_RECEIVER_ACKS_SENT, + +/* marker */ + PGM_PC_RECEIVER_MAX +}; + +struct pgm_peer_t { + volatile uint32_t ref_count; /* atomic integer */ + + pgm_tsi_t tsi; + struct sockaddr_storage group_nla; + struct sockaddr_storage nla, local_nla; /* nla = advertised, local_nla = from packet */ + struct sockaddr_storage poll_nla; /* from parent to direct poll-response */ + struct sockaddr_storage redirect_nla; /* from dlr */ + pgm_time_t polr_expiry; + pgm_time_t spmr_expiry; + pgm_time_t spmr_tstamp; + + pgm_rxw_t* restrict window; + pgm_sock_t* restrict sock; + pgm_list_t peers_link; + pgm_slist_t pending_link; + + unsigned is_fec_enabled:1; + unsigned has_proactive_parity:1; /* indicating availability from this source */ + unsigned has_ondemand_parity:1; + + uint32_t spm_sqn; + pgm_time_t expiry; + + pgm_time_t ack_rb_expiry; /* 0 = no ACK pending */ + pgm_time_t ack_last_tstamp; /* in source time reference */ + pgm_list_t ack_link; + + uint32_t last_poll_sqn; + uint16_t last_poll_round; + pgm_time_t last_packet; + pgm_time_t last_data_tstamp; /* local timestamp of ack_last_tstamp */ + unsigned last_commit; + uint32_t lost_count; + uint32_t last_cumulative_losses; + volatile uint32_t cumulative_stats[PGM_PC_RECEIVER_MAX]; + uint32_t snap_stats[PGM_PC_RECEIVER_MAX]; + + uint32_t min_fail_time; + uint32_t max_fail_time; +}; + +PGM_GNUC_INTERNAL pgm_peer_t* pgm_new_peer (pgm_sock_t*const restrict, const pgm_tsi_t*const restrict, const struct sockaddr*const restrict, const socklen_t, const struct sockaddr*const restrict, const socklen_t, const pgm_time_t); +PGM_GNUC_INTERNAL void pgm_peer_unref (pgm_peer_t*); +PGM_GNUC_INTERNAL int pgm_flush_peers_pending (pgm_sock_t*const restrict, struct pgm_msgv_t**restrict, const struct pgm_msgv_t*const, size_t*const restrict, unsigned*const restrict); +PGM_GNUC_INTERNAL bool pgm_peer_has_pending (pgm_peer_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_peer_set_pending (pgm_sock_t*const, pgm_peer_t*const); +PGM_GNUC_INTERNAL bool pgm_check_peer_state (pgm_sock_t*const, const pgm_time_t); +PGM_GNUC_INTERNAL void pgm_set_reset_error (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_msgv_t*const restrict); +PGM_GNUC_INTERNAL pgm_time_t pgm_min_receiver_expiry (pgm_time_t, pgm_sock_t*) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_on_peer_nak (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_on_data (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_on_ncf (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_on_spm (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_on_poll (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; + +PGM_END_DECLS + +#endif /* __PGM_IMPL_RECEIVER_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/reed_solomon.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/reed_solomon.h new file mode 100644 index 0000000..98f6734 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/reed_solomon.h @@ -0,0 +1,51 @@ +/* + * Reed-Solomon forward error correction based on Vandermonde matrices + * + * Copyright (c) 2006-2008 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_REED_SOLOMON_H__ +#define __PGM_IMPL_REED_SOLOMON_H__ + +typedef struct pgm_rs_t pgm_rs_t; + +#include +#include + +PGM_BEGIN_DECLS + +struct pgm_rs_t { + uint8_t n, k; /* RS(n, k) */ + pgm_gf8_t* GM; + pgm_gf8_t* RM; +}; + +#define PGM_RS_DEFAULT_N 255 + +PGM_GNUC_INTERNAL void pgm_rs_create (pgm_rs_t*, const uint8_t, const uint8_t); +PGM_GNUC_INTERNAL void pgm_rs_destroy (pgm_rs_t*); +PGM_GNUC_INTERNAL void pgm_rs_encode (pgm_rs_t*restrict, const pgm_gf8_t**restrict, const uint8_t, pgm_gf8_t*restrict, const uint16_t); +PGM_GNUC_INTERNAL void pgm_rs_decode_parity_inline (pgm_rs_t*restrict, pgm_gf8_t**restrict, const uint8_t*restrict, const uint16_t); +PGM_GNUC_INTERNAL void pgm_rs_decode_parity_appended (pgm_rs_t*restrict, pgm_gf8_t**restrict, const uint8_t*restrict, const uint16_t); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_REED_SOLOMON_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/rxw.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/rxw.h new file mode 100644 index 0000000..6eaa9f0 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/rxw.h @@ -0,0 +1,223 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * basic receive window. + * + * Copyright (c) 2006-2008 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_RXW_H__ +#define __PGM_IMPL_RXW_H__ + +typedef struct pgm_rxw_state_t pgm_rxw_state_t; +typedef struct pgm_rxw_t pgm_rxw_t; + +#include + +PGM_BEGIN_DECLS + +enum +{ + PGM_PKT_STATE_ERROR = 0, + PGM_PKT_STATE_BACK_OFF, /* PGM protocol recovery states */ + PGM_PKT_STATE_WAIT_NCF, + PGM_PKT_STATE_WAIT_DATA, + PGM_PKT_STATE_HAVE_DATA, /* data received waiting to commit to application layer */ + PGM_PKT_STATE_HAVE_PARITY, /* contains parity information not original data */ + PGM_PKT_STATE_COMMIT_DATA, /* commited data waiting for purging */ + PGM_PKT_STATE_LOST_DATA /* if recovery fails, but packet has not yet been commited */ +}; + +enum +{ + PGM_RXW_OK = 0, + PGM_RXW_INSERTED, + PGM_RXW_APPENDED, + PGM_RXW_UPDATED, + PGM_RXW_MISSING, + PGM_RXW_DUPLICATE, + PGM_RXW_MALFORMED, + PGM_RXW_BOUNDS, + PGM_RXW_SLOW_CONSUMER, + PGM_RXW_UNKNOWN +}; + +/* must be smaller than PGM skbuff control buffer */ +struct pgm_rxw_state_t { + pgm_time_t timer_expiry; + int pkt_state; + + uint8_t nak_transmit_count; /* 8-bit for size constraints */ + uint8_t ncf_retry_count; + uint8_t data_retry_count; + +/* only valid on tg_sqn::pkt_sqn = 0 */ + unsigned is_contiguous:1; /* transmission group */ +}; + +struct pgm_rxw_t { + const pgm_tsi_t* tsi; + + pgm_queue_t ack_backoff_queue; + pgm_queue_t nak_backoff_queue; + pgm_queue_t wait_ncf_queue; + pgm_queue_t wait_data_queue; +/* window context counters */ + uint32_t lost_count; /* failed to repair */ + uint32_t fragment_count; /* incomplete apdu */ + uint32_t parity_count; /* parity for repairs */ + uint32_t committed_count; /* but still in window */ + + uint16_t max_tpdu; /* maximum packet size */ + uint32_t lead, trail; + uint32_t rxw_trail, rxw_trail_init; + uint32_t commit_lead; + unsigned is_constrained:1; + unsigned is_defined:1; + unsigned has_event:1; /* edge triggered */ + unsigned is_fec_available:1; + pgm_rs_t rs; + uint32_t tg_size; /* transmission group size for parity recovery */ + uint8_t tg_sqn_shift; + + uint32_t bitmap; /* receive status of last 32 packets */ + uint32_t data_loss; /* p */ + uint32_t ack_c_p; /* constant Cᵨ */ + +/* counters all guint32 */ + uint32_t min_fill_time; /* restricted from pgm_time_t */ + uint32_t max_fill_time; + uint32_t min_nak_transmit_count; + uint32_t max_nak_transmit_count; + uint32_t cumulative_losses; + uint32_t bytes_delivered; + uint32_t msgs_delivered; + + size_t size; /* in bytes */ + unsigned alloc; /* in pkts */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +/* C99 flexible array, sizeof() invalid */ + struct pgm_sk_buff_t* pdata[]; +#elif !defined(__STDC_VERSION__) || defined(__cplusplus) +/* C90 and older */ + struct pgm_sk_buff_t* pdata[1]; +#else +/* GNU C variable-length object */ + struct pgm_sk_buff_t* pdata[0]; +#endif +}; + + +PGM_GNUC_INTERNAL pgm_rxw_t* pgm_rxw_create (const pgm_tsi_t*const, const uint16_t, const unsigned, const unsigned, const ssize_t, const uint32_t) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_rxw_destroy (pgm_rxw_t*const); +PGM_GNUC_INTERNAL int pgm_rxw_add (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict, const pgm_time_t, const pgm_time_t) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_rxw_add_ack (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict, const pgm_time_t); +PGM_GNUC_INTERNAL void pgm_rxw_remove_ack (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict); +PGM_GNUC_INTERNAL void pgm_rxw_remove_commit (pgm_rxw_t*const); +PGM_GNUC_INTERNAL ssize_t pgm_rxw_readv (pgm_rxw_t*const restrict, struct pgm_msgv_t** restrict, const unsigned) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL unsigned pgm_rxw_remove_trail (pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL unsigned pgm_rxw_update (pgm_rxw_t*const, const uint32_t, const uint32_t, const pgm_time_t, const pgm_time_t) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_rxw_update_fec (pgm_rxw_t*const, const uint8_t); +PGM_GNUC_INTERNAL int pgm_rxw_confirm (pgm_rxw_t*const, const uint32_t, const pgm_time_t, const pgm_time_t, const pgm_time_t) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_rxw_lost (pgm_rxw_t*const, const uint32_t); +PGM_GNUC_INTERNAL void pgm_rxw_state (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict, const int); +PGM_GNUC_INTERNAL struct pgm_sk_buff_t* pgm_rxw_peek (pgm_rxw_t*const, const uint32_t) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL const char* pgm_pkt_state_string (const int) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL const char* pgm_rxw_returns_string (const int) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_rxw_dump (const pgm_rxw_t*const); + +/* declare for GCC attributes */ +static inline unsigned pgm_rxw_max_length (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline uint32_t pgm_rxw_length (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline size_t pgm_rxw_size (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline bool pgm_rxw_is_empty (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline bool pgm_rxw_is_full (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline uint32_t pgm_rxw_lead (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline uint32_t pgm_rxw_next_lead (const pgm_rxw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; + +static inline +unsigned +pgm_rxw_max_length ( + const pgm_rxw_t* const window + ) +{ + pgm_assert (NULL != window); + return window->alloc; +} + +static inline +uint32_t +pgm_rxw_length ( + const pgm_rxw_t* const window + ) +{ + pgm_assert (NULL != window); + return ( 1 + window->lead ) - window->trail; +} + +static inline +size_t +pgm_rxw_size ( + const pgm_rxw_t* const window + ) +{ + pgm_assert (NULL != window); + return window->size; +} + +static inline +bool +pgm_rxw_is_empty ( + const pgm_rxw_t* const window + ) +{ + pgm_assert (NULL != window); + return pgm_rxw_length (window) == 0; +} + +static inline +bool +pgm_rxw_is_full ( + const pgm_rxw_t* const window + ) +{ + pgm_assert (NULL != window); + return pgm_rxw_length (window) == pgm_rxw_max_length (window); +} + +static inline +uint32_t +pgm_rxw_lead ( + const pgm_rxw_t* const window + ) +{ + pgm_assert (NULL != window); + return window->lead; +} + +static inline +uint32_t +pgm_rxw_next_lead ( + const pgm_rxw_t* const window + ) +{ + pgm_assert (NULL != window); + return (uint32_t)(pgm_rxw_lead (window) + 1); +} + +PGM_END_DECLS + +#endif /* __PGM_IMPL_RXW_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/slist.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/slist.h new file mode 100644 index 0000000..e71b15d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/slist.h @@ -0,0 +1,52 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable singly-linked list. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_SLIST_H__ +#define __PGM_IMPL_SLIST_H__ + +typedef struct pgm_slist_t pgm_slist_t; + +#include + +PGM_BEGIN_DECLS + +struct pgm_slist_t +{ + void* restrict data; + struct pgm_slist_t* restrict next; +}; + +PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_append (pgm_slist_t*restrict, void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_prepend (pgm_slist_t*restrict, void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_prepend_link (pgm_slist_t*restrict, pgm_slist_t*restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_remove (pgm_slist_t*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_remove_first (pgm_slist_t*) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_slist_free (pgm_slist_t*); +PGM_GNUC_INTERNAL pgm_slist_t* pgm_slist_last (pgm_slist_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL unsigned pgm_slist_length (pgm_slist_t*) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; + +PGM_END_DECLS + +#endif /* __PGM_IMPL_SLIST_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/sn.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/sn.h new file mode 100644 index 0000000..a8cd3da --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/sn.h @@ -0,0 +1,174 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * serial number arithmetic: rfc 1982 + * + * Copyright (c) 2006-2007 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_SN_H__ +#define __PGM_IMPL_SN_H__ + +#include +#include + +PGM_BEGIN_DECLS + +#define PGM_UINT32_SIGN_BIT (1UL<<31) +#define PGM_UINT64_SIGN_BIT (1ULL<<63) + +/* declare for GCC attributes */ +static inline bool pgm_uint32_lt (const uint32_t, const uint32_t) PGM_GNUC_CONST; +static inline bool pgm_uint32_lte (const uint32_t, const uint32_t) PGM_GNUC_CONST; +static inline bool pgm_uint32_gt (const uint32_t, const uint32_t) PGM_GNUC_CONST; +static inline bool pgm_uint32_gte (const uint32_t, const uint32_t) PGM_GNUC_CONST; +static inline bool pgm_uint64_lt (const uint64_t, const uint64_t) PGM_GNUC_CONST; +static inline bool pgm_uint64_lte (const uint64_t, const uint64_t) PGM_GNUC_CONST; +static inline bool pgm_uint64_gt (const uint64_t, const uint64_t) PGM_GNUC_CONST; +static inline bool pgm_uint64_gte (const uint64_t, const uint64_t) PGM_GNUC_CONST; + +/* 32 bit */ +static inline +bool pgm_uint32_lt ( + const uint32_t s, + const uint32_t t + ) +{ + pgm_assert (sizeof(int) >= 4); + return ((s) - (t)) & PGM_UINT32_SIGN_BIT; +} + +static inline +bool +pgm_uint32_lte ( + const uint32_t s, + const uint32_t t + ) +{ + pgm_assert (sizeof(int) >= 4); + return ((s) == (t)) || ( ((s) - (t)) & PGM_UINT32_SIGN_BIT ); +} + +static inline +bool +pgm_uint32_gt ( + const uint32_t s, + const uint32_t t + ) +{ + pgm_assert (sizeof(int) >= 4); + return ((t) - (s)) & PGM_UINT32_SIGN_BIT; +} + +static inline +bool +pgm_uint32_gte ( + const uint32_t s, + const uint32_t t + ) +{ + pgm_assert (sizeof(int) >= 4); + return ((s) == (t)) || ( ((t) - (s)) & PGM_UINT32_SIGN_BIT ); +} + +/* 64 bit */ +static inline +bool +pgm_uint64_lt ( + const uint64_t s, + const uint64_t t + ) +{ + if (sizeof(int) == 4) + { +/* need to force boolean conversion when int = 32bits */ + return ( ((s) - (t)) & PGM_UINT64_SIGN_BIT ) != 0; + } + else + { + pgm_assert (sizeof(int) >= 8); + return ( ((s) - (t)) & PGM_UINT64_SIGN_BIT ) != 0; + } +} + +static inline +bool +pgm_uint64_lte ( + const uint64_t s, + const uint64_t t + ) +{ + if (sizeof(int) == 4) + { +/* need to force boolean conversion when int = 32bits */ + return ( (s) == (t) ) + || + ( ( ((s) - (t)) & PGM_UINT64_SIGN_BIT ) != 0 ); + } + else + { + pgm_assert (sizeof(int) >= 8); + return ( ((s) == (t)) || ( ((s) - (t)) & PGM_UINT64_SIGN_BIT ) ) != 0; + } +} + +static inline +bool +pgm_uint64_gt ( + const uint64_t s, + const uint64_t t + ) +{ + if (sizeof(int) == 4) + { +/* need to force boolean conversion when int = 32bits */ + return ( ((t) - (s)) & PGM_UINT64_SIGN_BIT ) != 0; + } + else + { + pgm_assert (sizeof(int) >= 8); + return ( ((t) - (s)) & PGM_UINT64_SIGN_BIT ) != 0; + } +} + +static inline +bool +pgm_uint64_gte ( + const uint64_t s, + const uint64_t t + ) +{ + if (sizeof(int) == 4) + { +/* need to force boolean conversion when int = 32bits */ + return ( (s) == (t) ) + || + ( ( ((t) - (s)) & PGM_UINT64_SIGN_BIT ) != 0 ); + } + else + { + pgm_assert (sizeof(int) >= 8); + return ( ((s) == (t)) || ( ((t) - (s)) & PGM_UINT64_SIGN_BIT ) ) != 0; + } +} + +PGM_END_DECLS + +#endif /* __PGM_IMPL_SN_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/sockaddr.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/sockaddr.h new file mode 100644 index 0000000..715c63f --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/sockaddr.h @@ -0,0 +1,105 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * struct sockaddr functions independent of in or in6. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_SOCKADDR_H__ +#define __PGM_IMPL_SOCKADDR_H__ + +#ifndef _WIN32 +# include +#endif +#include + +PGM_BEGIN_DECLS + +/* fallback values where not directly supported */ +#ifndef MSG_DONTWAIT +# define MSG_DONTWAIT 0 +#endif +#ifndef MSG_ERRQUEUE +# define MSG_ERRQUEUE 0x2000 +#endif +#if !defined(EAFNOSUPPORT) && defined(WSAEAFNOSUPPORT) +# define EAFNOSUPPORT WSAEAFNOSUPPORT +#endif + +#ifndef _WIN32 +# define PGM_INVALID_SOCKET -1 +# define PGM_SOCKET_ERROR -1 +# define pgm_closesocket close +# define pgm_sock_errno() (errno) +# define pgm_sock_strerror(e) strerror(e) +# define pgm_error_from_sock_errno pgm_error_from_errno +#else +# define PGM_INVALID_SOCKET (int)INVALID_SOCKET +# define PGM_SOCKET_ERROR (int)SOCKET_ERROR +# define pgm_closesocket closesocket +# define pgm_sock_errno() WSAGetLastError() +# define pgm_sock_strerror(e) pgm_wsastrerror(e) +# define pgm_error_from_sock_errno pgm_error_from_wsa_errno +#endif + +PGM_GNUC_INTERNAL sa_family_t pgm_sockaddr_family (const struct sockaddr* sa); +PGM_GNUC_INTERNAL uint16_t pgm_sockaddr_port (const struct sockaddr* sa); +PGM_GNUC_INTERNAL socklen_t pgm_sockaddr_len (const struct sockaddr* sa); +PGM_GNUC_INTERNAL socklen_t pgm_sockaddr_storage_len (const struct sockaddr_storage* ss); +PGM_GNUC_INTERNAL uint32_t pgm_sockaddr_scope_id (const struct sockaddr* sa); +PGM_GNUC_INTERNAL int pgm_sockaddr_ntop (const struct sockaddr*restrict sa, char*restrict dst, size_t ulen); +PGM_GNUC_INTERNAL int pgm_sockaddr_pton (const char*restrict src, struct sockaddr*restrict dst); +PGM_GNUC_INTERNAL int pgm_sockaddr_is_addr_multicast (const struct sockaddr* sa); +PGM_GNUC_INTERNAL int pgm_sockaddr_is_addr_unspecified (const struct sockaddr* sa); +PGM_GNUC_INTERNAL int pgm_sockaddr_cmp (const struct sockaddr*restrict sa1, const struct sockaddr*restrict sa2); +PGM_GNUC_INTERNAL int pgm_sockaddr_hdrincl (const int s, const sa_family_t sa_family, const bool v); +PGM_GNUC_INTERNAL int pgm_sockaddr_pktinfo (const int s, const sa_family_t sa_family, const bool v); +PGM_GNUC_INTERNAL int pgm_sockaddr_router_alert (const int s, const sa_family_t sa_family, const bool v); +PGM_GNUC_INTERNAL int pgm_sockaddr_tos (const int s, const sa_family_t sa_family, const int tos); +PGM_GNUC_INTERNAL int pgm_sockaddr_join_group (const int s, const sa_family_t sa_family, const struct group_req* gr); +PGM_GNUC_INTERNAL int pgm_sockaddr_leave_group (const int s, const sa_family_t sa_family, const struct group_req* gr); +PGM_GNUC_INTERNAL int pgm_sockaddr_block_source (const int s, const sa_family_t sa_family, const struct group_source_req* gsr); +PGM_GNUC_INTERNAL int pgm_sockaddr_unblock_source (const int s, const sa_family_t sa_family, const struct group_source_req* gsr); +PGM_GNUC_INTERNAL int pgm_sockaddr_join_source_group (const int s, const sa_family_t sa_family, const struct group_source_req* gsr); +PGM_GNUC_INTERNAL int pgm_sockaddr_leave_source_group (const int s, const sa_family_t sa_family, const struct group_source_req* gsr); +#if defined(MCAST_MSFILTER) || defined(SIOCSMSFILTER) +# ifndef GROUP_FILTER_SIZE +# define GROUP_FILTER_SIZE(numsrc) (sizeof (struct group_filter) \ + - sizeof (struct sockaddr_storage) \ + + ((numsrc) \ + * sizeof (struct sockaddr_storage))) +# endif +PGM_GNUC_INTERNAL int pgm_sockaddr_msfilter (const int s, const sa_family_t sa_family, const struct group_filter* gf_list); +#endif +PGM_GNUC_INTERNAL int pgm_sockaddr_multicast_if (int s, const struct sockaddr* address, unsigned ifindex); +PGM_GNUC_INTERNAL int pgm_sockaddr_multicast_loop (const int s, const sa_family_t sa_family, const bool v); +PGM_GNUC_INTERNAL int pgm_sockaddr_multicast_hops (const int s, const sa_family_t sa_family, const unsigned hops); +PGM_GNUC_INTERNAL void pgm_sockaddr_nonblocking (const int s, const bool v); + +PGM_GNUC_INTERNAL const char* pgm_inet_ntop (int af, const void*restrict src, char*restrict dst, socklen_t size); +PGM_GNUC_INTERNAL int pgm_inet_pton (int af, const char*restrict src, void*restrict dst); + +PGM_GNUC_INTERNAL int pgm_nla_to_sockaddr (const void*restrict nla, struct sockaddr*restrict sa); +PGM_GNUC_INTERNAL int pgm_sockaddr_to_nla (const struct sockaddr*restrict sa, void*restrict nla); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_SOCKADDR_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/socket.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/socket.h new file mode 100644 index 0000000..ee175d8 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/socket.h @@ -0,0 +1,182 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM socket. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_SOCKET_H__ +#define __PGM_IMPL_SOCKET_H__ + +struct pgm_sock_t; + +#include +#include +#include + +PGM_BEGIN_DECLS + +#ifndef IP_MAX_MEMBERSHIPS +# define IP_MAX_MEMBERSHIPS 20 +#endif + +struct pgm_sock_t { + sa_family_t family; /* communications domain */ + int socket_type; + int protocol; + pgm_tsi_t tsi; + uint16_t dport; + uint16_t udp_encap_ucast_port; + uint16_t udp_encap_mcast_port; + uint32_t rand_node_id; /* node identifier */ + + pgm_rwlock_t lock; /* running / destroyed */ + pgm_mutex_t receiver_mutex; /* receiver API */ + pgm_mutex_t source_mutex; /* source API */ + pgm_spinlock_t txw_spinlock; /* transmit window */ + pgm_mutex_t send_mutex; /* non-router alert socket */ + pgm_mutex_t timer_mutex; /* next timer expiration */ + + bool is_bound; + bool is_connected; + bool is_destroyed; + bool is_reset; + bool is_abort_on_reset; + + bool can_send_data; /* and SPMs */ + bool can_send_nak; /* muted receiver */ + bool can_recv_data; /* send-only */ + bool is_edge_triggered_recv; + bool is_nonblocking; + + struct group_source_req send_gsr; /* multicast */ + struct sockaddr_storage send_addr; /* unicast nla */ + int send_sock; + int send_with_router_alert_sock; + struct group_source_req recv_gsr[IP_MAX_MEMBERSHIPS]; /* sa_family = 0 terminated */ + unsigned recv_gsr_len; + int recv_sock; + + size_t max_apdu; + uint16_t max_tpdu; + uint16_t max_tsdu; /* excluding optional var_pktlen word */ + uint16_t max_tsdu_fragment; + size_t iphdr_len; + bool use_multicast_loop; /* and reuseaddr for UDP encapsulation */ + unsigned hops; + unsigned txw_sqns, txw_secs; + unsigned rxw_sqns, rxw_secs; + ssize_t txw_max_rte, rxw_max_rte; + size_t sndbuf, rcvbuf; /* setsockopt (SO_SNDBUF/SO_RCVBUF) */ + + pgm_txw_t* restrict window; + pgm_rate_t rate_control; + pgm_time_t adv_ivl; /* advancing with data */ + unsigned adv_mode; /* 0 = time, 1 = data */ + bool is_controlled_spm; + bool is_controlled_odata; + bool is_controlled_rdata; + + bool use_cr; /* congestion reports */ + bool use_pgmcc; /* congestion control */ + bool is_pending_crqst; + unsigned ack_c; /* constant C */ + unsigned ack_c_p; /* constant Cᵨ */ + uint32_t ssthresh; /* slow-start threshold */ + uint32_t tokens; + uint32_t cwnd_size; /* congestion window size */ + uint32_t ack_rx_max; + uint32_t ack_bitmap; + uint32_t acks_after_loss; + uint32_t suspended_sqn; + bool is_congested; + pgm_time_t ack_expiry; + pgm_time_t ack_expiry_ivl; + pgm_time_t next_crqst; + pgm_time_t crqst_ivl; + pgm_time_t ack_bo_ivl; + struct sockaddr_storage acker_nla; + uint64_t acker_loss; + + pgm_notify_t ack_notify; + pgm_notify_t rdata_notify; + + pgm_hash_t last_hash_key; + void* restrict last_hash_value; + unsigned last_commit; + size_t blocklen; /* length of buffer blocked */ + bool is_apdu_eagain; /* writer-lock on window_lock exists as send would block */ + bool is_spm_eagain; /* writer-lock in receiver */ + + struct { + size_t data_pkt_offset; + size_t data_bytes_offset; + uint32_t first_sqn; + struct pgm_sk_buff_t* skb; /* references external buffer */ + size_t tsdu_length; + uint32_t unfolded_odata; + size_t apdu_length; + unsigned vector_index; + size_t vector_offset; + bool is_rate_limited; + } pkt_dontwait_state; + + uint32_t spm_sqn; + unsigned spm_ambient_interval; /* microseconds */ + unsigned* restrict spm_heartbeat_interval; /* zero terminated, zero lead-pad */ + unsigned spm_heartbeat_state; /* indexof spm_heartbeat_interval */ + unsigned spm_heartbeat_len; + unsigned peer_expiry; /* from absence of SPMs */ + unsigned spmr_expiry; /* waiting for peer SPMRs */ + + pgm_rand_t rand_; /* for calculating nak_rb_ivl from nak_bo_ivl */ + unsigned nak_data_retries, nak_ncf_retries; + pgm_time_t nak_bo_ivl, nak_rpt_ivl, nak_rdata_ivl; + pgm_time_t next_heartbeat_spm, next_ambient_spm; + + bool use_proactive_parity; + bool use_ondemand_parity; + bool use_var_pktlen; + uint8_t rs_n; + uint8_t rs_k; + uint8_t rs_proactive_h; /* 0 <= proactive-h <= ( n - k ) */ + uint8_t tg_sqn_shift; + struct pgm_sk_buff_t* restrict rx_buffer; + + pgm_rwlock_t peers_lock; + pgm_hashtable_t* restrict peers_hashtable; /* fast lookup */ + pgm_list_t* restrict peers_list; /* easy iteration */ + pgm_slist_t* restrict peers_pending; /* rxw: have or lost data */ + pgm_notify_t pending_notify; /* timer to rx */ + bool is_pending_read; + pgm_time_t next_poll; + + uint32_t cumulative_stats[PGM_PC_SOURCE_MAX]; + uint32_t snap_stats[PGM_PC_SOURCE_MAX]; + pgm_time_t snap_time; +}; + + +/* global variables */ +extern pgm_rwlock_t pgm_sock_list_lock; +extern pgm_slist_t* pgm_sock_list; + +size_t pgm_pkt_offset (bool, sa_family_t); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_SOCKET_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/source.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/source.h new file mode 100644 index 0000000..5349046 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/source.h @@ -0,0 +1,75 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM source socket. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_SOURCE_H__ +#define __PGM_IMPL_SOURCE_H__ + +#include +#include + +PGM_BEGIN_DECLS + +/* Performance Counters */ +enum { + PGM_PC_SOURCE_DATA_BYTES_SENT, + PGM_PC_SOURCE_DATA_MSGS_SENT, /* msgs = packets not APDUs */ +/* PGM_PC_SOURCE_BYTES_BUFFERED, */ /* tx window contents in bytes */ +/* PGM_PC_SOURCE_MSGS_BUFFERED, */ + PGM_PC_SOURCE_BYTES_SENT, +/* PGM_PC_SOURCE_RAW_NAKS_RECEIVED, */ + PGM_PC_SOURCE_CKSUM_ERRORS, + PGM_PC_SOURCE_MALFORMED_NAKS, + PGM_PC_SOURCE_PACKETS_DISCARDED, + PGM_PC_SOURCE_PARITY_BYTES_RETRANSMITTED, + PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED, + PGM_PC_SOURCE_PARITY_MSGS_RETRANSMITTED, + PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED, + PGM_PC_SOURCE_PARITY_NAK_PACKETS_RECEIVED, + PGM_PC_SOURCE_SELECTIVE_NAK_PACKETS_RECEIVED, /* total packets */ + PGM_PC_SOURCE_PARITY_NAKS_RECEIVED, + PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED, /* serial numbers */ + PGM_PC_SOURCE_PARITY_NAKS_IGNORED, + PGM_PC_SOURCE_SELECTIVE_NAKS_IGNORED, + PGM_PC_SOURCE_ACK_ERRORS, +/* PGM_PC_SOURCE_PGMCC_ACKER, */ + PGM_PC_SOURCE_TRANSMISSION_CURRENT_RATE, + PGM_PC_SOURCE_ACK_PACKETS_RECEIVED, + PGM_PC_SOURCE_PARITY_NNAK_PACKETS_RECEIVED, + PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED, + PGM_PC_SOURCE_PARITY_NNAKS_RECEIVED, + PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED, + PGM_PC_SOURCE_NNAK_ERRORS, + +/* marker */ + PGM_PC_SOURCE_MAX +}; + +PGM_GNUC_INTERNAL bool pgm_send_spm (pgm_sock_t*const, const int) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_on_deferred_nak (pgm_sock_t*const); +PGM_GNUC_INTERNAL bool pgm_on_spmr (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_on_nak (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_on_nnak (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_on_ack (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict) PGM_GNUC_WARN_UNUSED_RESULT; + +PGM_END_DECLS + +#endif /* __PGM_IMPL_SOURCE_H__ */ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/sqn_list.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/sqn_list.h new file mode 100644 index 0000000..4d216ae --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/sqn_list.h @@ -0,0 +1,38 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM sequence list. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_SQN_LIST_H__ +#define __PGM_IMPL_SQN_LIST_H__ + +struct pgm_sqn_list_t; + +#include + +PGM_BEGIN_DECLS + +struct pgm_sqn_list_t { + uint8_t len; + uint32_t sqn[63]; /* list of sequence numbers */ +}; + +PGM_END_DECLS + +#endif /* __PGM_IMPL_SQN_LIST_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/string.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/string.h new file mode 100644 index 0000000..8357c2a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/string.h @@ -0,0 +1,59 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable string manipulation functions. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_STRING_H__ +#define __PGM_IMPL_STRING_H__ + +typedef struct pgm_string_t pgm_string_t; + +#include +#include + +PGM_BEGIN_DECLS + +struct pgm_string_t { + char* str; + size_t len; + size_t allocated_len; +}; + +PGM_GNUC_INTERNAL char* pgm_strdup (const char*) PGM_GNUC_MALLOC; +PGM_GNUC_INTERNAL int pgm_printf_string_upper_bound (const char*, va_list) PGM_GNUC_PRINTF(1, 0); +PGM_GNUC_INTERNAL int pgm_vasprintf (char**restrict, char const*restrict, va_list args) PGM_GNUC_PRINTF(2, 0); +PGM_GNUC_INTERNAL char* pgm_strdup_vprintf (const char*, va_list) PGM_GNUC_PRINTF(1, 0) PGM_GNUC_MALLOC; +PGM_GNUC_INTERNAL char* pgm_strconcat (const char*, ...) PGM_GNUC_MALLOC PGM_GNUC_NULL_TERMINATED; +PGM_GNUC_INTERNAL char** pgm_strsplit (const char*restrict, const char*restrict, int) PGM_GNUC_MALLOC; +PGM_GNUC_INTERNAL void pgm_strfreev (char**); + +PGM_GNUC_INTERNAL pgm_string_t* pgm_string_new (const char*); +PGM_GNUC_INTERNAL char* pgm_string_free (pgm_string_t*, bool); +PGM_GNUC_INTERNAL void pgm_string_printf (pgm_string_t*restrict, const char*restrict, ...) PGM_GNUC_PRINTF(2, 3); +PGM_GNUC_INTERNAL pgm_string_t* pgm_string_append (pgm_string_t*restrict, const char*restrict); +PGM_GNUC_INTERNAL pgm_string_t* pgm_string_append_c (pgm_string_t*, char); +PGM_GNUC_INTERNAL void pgm_string_append_printf (pgm_string_t*restrict, const char*restrict, ...) PGM_GNUC_PRINTF(2, 3); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_STRING_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/thread.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/thread.h new file mode 100644 index 0000000..105e9ce --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/thread.h @@ -0,0 +1,211 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * mutexes and locks. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_THREAD_H__ +#define __PGM_IMPL_THREAD_H__ + +typedef struct pgm_mutex_t pgm_mutex_t; +typedef struct pgm_spinlock_t pgm_spinlock_t; +typedef struct pgm_cond_t pgm_cond_t; +typedef struct pgm_rwlock_t pgm_rwlock_t; + +#ifndef _WIN32 +# include +# include +#else +# define WIN32_LEAN_AND_MEAN +# include +#endif +#include + +PGM_BEGIN_DECLS + +struct pgm_mutex_t { +#ifndef _WIN32 + pthread_mutex_t pthread_mutex; +#else + HANDLE win32_mutex; +#endif /* !_WIN32 */ +}; + +struct pgm_spinlock_t { +#ifndef _WIN32 + pthread_spinlock_t pthread_spinlock; +#else + CRITICAL_SECTION win32_spinlock; +#endif +}; + +struct pgm_cond_t { +#ifndef _WIN32 + pthread_cond_t pthread_cond; +#elif defined(CONFIG_HAVE_WIN_COND) + CONDITION_VARIABLE win32_cond; +#else + CRITICAL_SECTION win32_spinlock; + size_t len; + size_t allocated_len; + HANDLE* phandle; +#endif /* !_WIN32 */ +}; + +struct pgm_rwlock_t { +#ifndef _WIN32 + pthread_rwlock_t pthread_rwlock; +#elif CONFIG_HAVE_WIN_SRW_LOCK + SRWLOCK win32_lock; + pthread_rwlock_t pthread_rwlock; +#else + CRITICAL_SECTION win32_spinlock; + pgm_cond_t read_cond; + pgm_cond_t write_cond; + unsigned read_counter; + bool have_writer; + unsigned want_to_read; + unsigned want_to_write; +#endif /* !CONFIG_HAVE_WIN_SRW_LOCK */ +}; + +PGM_GNUC_INTERNAL void pgm_mutex_init (pgm_mutex_t*); +PGM_GNUC_INTERNAL void pgm_mutex_free (pgm_mutex_t*); +PGM_GNUC_INTERNAL bool pgm_mutex_trylock (pgm_mutex_t*); + +static inline void pgm_mutex_lock (pgm_mutex_t* mutex) { +#ifndef _WIN32 + pthread_mutex_lock (&mutex->pthread_mutex); +#else + WaitForSingleObject (mutex->win32_mutex, INFINITE); +#endif /* !_WIN32 */ +} + +static inline void pgm_mutex_unlock (pgm_mutex_t* mutex) { +#ifndef _WIN32 + pthread_mutex_unlock (&mutex->pthread_mutex); +#else + ReleaseMutex (mutex->win32_mutex); +#endif /* !_WIN32 */ +} + +PGM_GNUC_INTERNAL void pgm_spinlock_init (pgm_spinlock_t*); +PGM_GNUC_INTERNAL void pgm_spinlock_free (pgm_spinlock_t*); +PGM_GNUC_INTERNAL bool pgm_spinlock_trylock (pgm_spinlock_t*); + +static inline void pgm_spinlock_lock (pgm_spinlock_t* spinlock) { +#ifndef _WIN32 + pthread_spin_lock (&spinlock->pthread_spinlock); +#else + EnterCriticalSection (&spinlock->win32_spinlock); +#endif /* !_WIN32 */ +} + +static inline void pgm_spinlock_unlock (pgm_spinlock_t* spinlock) { +#ifndef _WIN32 + pthread_spin_unlock (&spinlock->pthread_spinlock); +#else + LeaveCriticalSection (&spinlock->win32_spinlock); +#endif /* !_WIN32 */ +} + +PGM_GNUC_INTERNAL void pgm_cond_init (pgm_cond_t*); +PGM_GNUC_INTERNAL void pgm_cond_signal (pgm_cond_t*); +PGM_GNUC_INTERNAL void pgm_cond_broadcast (pgm_cond_t*); +#ifndef _WIN32 +PGM_GNUC_INTERNAL void pgm_cond_wait (pgm_cond_t*, pthread_mutex_t*); +#else +PGM_GNUC_INTERNAL void pgm_cond_wait (pgm_cond_t*, CRITICAL_SECTION*); +#endif +PGM_GNUC_INTERNAL void pgm_cond_free (pgm_cond_t*); + +#ifndef _WIN32 +static inline void pgm_rwlock_reader_lock (pgm_rwlock_t* rwlock) { + pthread_rwlock_rdlock (&rwlock->pthread_rwlock); +} +static inline bool pgm_rwlock_reader_trylock (pgm_rwlock_t* rwlock) { + return !pthread_rwlock_tryrdlock (&rwlock->pthread_rwlock); +} +static inline void pgm_rwlock_reader_unlock(pgm_rwlock_t* rwlock) { + pthread_rwlock_unlock (&rwlock->pthread_rwlock); +} +static inline void pgm_rwlock_writer_lock (pgm_rwlock_t* rwlock) { + pthread_rwlock_wrlock (&rwlock->pthread_rwlock); +} +static inline bool pgm_rwlock_writer_trylock (pgm_rwlock_t* rwlock) { + return !pthread_rwlock_trywrlock (&rwlock->pthread_rwlock); +} +static inline void pgm_rwlock_writer_unlock (pgm_rwlock_t* rwlock) { + pthread_rwlock_unlock (&rwlock->pthread_rwlock); +} +#elif defined(CONFIG_HAVE_WIN_SRW_LOCK) +static inline void pgm_rwlock_reader_lock (pgm_rwlock_t* rwlock) { + AcquireSRWLockShared (&rwlock->win32_lock); +} +static inline bool pgm_rwlock_reader_trylock (pgm_rwlock_t* rwlock) { + return TryAcquireSRWLockShared (&rwlock->win32_lock); +} +static inline void pgm_rwlock_reader_unlock(pgm_rwlock_t* rwlock) { + ReleaseSRWLockShared (&rwlock->win32_lock); +} +static inline void pgm_rwlock_writer_lock (pgm_rwlock_t* rwlock) { + AcquireSRWLockExclusive (&rwlock->win32_lock); +} +static inline bool pgm_rwlock_writer_trylock (pgm_rwlock_t* rwlock) { + return AcquireSRWLockExclusive (&rwlock->win32_lock); +} +static inline void pgm_rwlock_writer_unlock (pgm_rwlock_t* rwlock) { + ReleaseSRWLockExclusive (&rwlock->win32_lock); +} +#else +PGM_GNUC_INTERNAL void pgm_rwlock_reader_lock (pgm_rwlock_t*); +PGM_GNUC_INTERNAL bool pgm_rwlock_reader_trylock (pgm_rwlock_t*); +PGM_GNUC_INTERNAL void pgm_rwlock_reader_unlock(pgm_rwlock_t*); +PGM_GNUC_INTERNAL void pgm_rwlock_writer_lock (pgm_rwlock_t*); +PGM_GNUC_INTERNAL bool pgm_rwlock_writer_trylock (pgm_rwlock_t*); +PGM_GNUC_INTERNAL void pgm_rwlock_writer_unlock (pgm_rwlock_t*); +#endif + +PGM_GNUC_INTERNAL void pgm_rwlock_init (pgm_rwlock_t*); +PGM_GNUC_INTERNAL void pgm_rwlock_free (pgm_rwlock_t*); + +PGM_GNUC_INTERNAL void pgm_thread_init (void); +PGM_GNUC_INTERNAL void pgm_thread_shutdown (void); + +static inline +void +pgm_thread_yield (void) +{ +#ifndef _WIN32 +# ifdef _POSIX_PRIORITY_SCHEDULING + sched_yield(); +# else + pthread_yield(); /* requires _GNU */ +# endif +#else + Sleep (0); /* If you specify 0 milliseconds, the thread will relinquish + * the remainder of its time slice but remain ready. + */ +#endif /* _WIN32 */ +} + +PGM_END_DECLS + +#endif /* __PGM_IMPL_THREAD_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/time.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/time.h new file mode 100644 index 0000000..70c0d37 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/time.h @@ -0,0 +1,51 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * high resolution timers. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_TIME_H__ +#define __PGM_IMPL_TIME_H__ + +#include +#include +#include + +PGM_BEGIN_DECLS + +typedef pgm_time_t (*pgm_time_update_func)(void); + +#define pgm_time_after(a,b) ( (a) > (b) ) +#define pgm_time_before(a,b) ( pgm_time_after((b),(a)) ) + +#define pgm_time_after_eq(a,b) ( (a) >= (b) ) +#define pgm_time_before_eq(a,b) ( pgm_time_after_eq((b),(a)) ) + +extern pgm_time_update_func pgm_time_update_now; + +PGM_GNUC_INTERNAL bool pgm_time_init (pgm_error_t**) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_time_shutdown (void); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_TIME_H__ */ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/timer.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/timer.h new file mode 100644 index 0000000..4f900e4 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/timer.h @@ -0,0 +1,58 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM timer thread. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_TIMER_H__ +#define __PGM_IMPL_TIMER_H__ + +#include +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL bool pgm_timer_prepare (pgm_sock_t*const); +PGM_GNUC_INTERNAL bool pgm_timer_check (pgm_sock_t*const); +PGM_GNUC_INTERNAL pgm_time_t pgm_timer_expiration (pgm_sock_t*const); +PGM_GNUC_INTERNAL bool pgm_timer_dispatch (pgm_sock_t*const); + +static inline +void +pgm_timer_lock ( + pgm_sock_t* const sock + ) +{ + if (sock->can_send_data) + pgm_mutex_lock (&sock->timer_mutex); +} + +static inline +void +pgm_timer_unlock ( + pgm_sock_t* const sock + ) +{ + if (sock->can_send_data) + pgm_mutex_unlock (&sock->timer_mutex); +} + +PGM_END_DECLS + +#endif /* __PGM_IMPL_TIMER_H__ */ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/tsi.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/tsi.h new file mode 100644 index 0000000..be93e62 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/tsi.h @@ -0,0 +1,39 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * transport session ID helper functions + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_TSI_H__ +#define __PGM_IMPL_TSI_H__ + +#include +#include +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_INTERNAL pgm_hash_t pgm_tsi_hash (const void*) PGM_GNUC_WARN_UNUSED_RESULT; + +PGM_END_DECLS + +#endif /* __PGM_IMPL_TSI_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/txw.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/txw.h new file mode 100644 index 0000000..650cd6a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/txw.h @@ -0,0 +1,207 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * basic transmit window. + * + * Copyright (c) 2006 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IMPL_TXW_H__ +#define __PGM_IMPL_TXW_H__ + +typedef struct pgm_txw_state_t pgm_txw_state_t; +typedef struct pgm_txw_t pgm_txw_t; + +#include + +PGM_BEGIN_DECLS + +/* must be smaller than PGM skbuff control buffer */ +struct pgm_txw_state_t { + uint32_t unfolded_checksum; /* first 32-bit word must be checksum */ + + unsigned waiting_retransmit:1; /* in retransmit queue */ + unsigned retransmit_count:15; + unsigned nak_elimination_count:16; + + uint8_t pkt_cnt_requested; /* # parity packets to send */ + uint8_t pkt_cnt_sent; /* # parity packets already sent */ +}; + +struct pgm_txw_t { + const pgm_tsi_t* restrict tsi; + +/* option: lockless atomics */ + volatile uint32_t lead; + volatile uint32_t trail; + + pgm_queue_t retransmit_queue; + + pgm_rs_t rs; + uint8_t tg_sqn_shift; + struct pgm_sk_buff_t* restrict parity_buffer; + +/* Advance with data */ + pgm_time_t adv_ivl_expiry; + unsigned increment_window_naks; + unsigned adv_secs; /* TXW_ADV_SECS */ + unsigned adv_sqns; /* TXW_ADV_SECS in sequences */ + + unsigned is_fec_enabled:1; + unsigned adv_mode:1; /* 0 = advance by time, 1 = advance by data */ + + size_t size; /* window content size in bytes */ + unsigned alloc; /* length of pdata[] */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +/* C99 flexible array, sizeof() invalid */ + struct pgm_sk_buff_t* pdata[]; +#elif !defined(__STDC_VERSION__) || defined(__cplusplus) +/* C90 and older */ + struct pgm_sk_buff_t* pdata[1]; +#else +/* GNU C variable-length object */ + struct pgm_sk_buff_t* pdata[0]; +#endif +}; + +PGM_GNUC_INTERNAL pgm_txw_t* pgm_txw_create (const pgm_tsi_t*const, const uint16_t, const uint32_t, const unsigned, const ssize_t, const bool, const uint8_t, const uint8_t) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_txw_shutdown (pgm_txw_t*const); +PGM_GNUC_INTERNAL void pgm_txw_add (pgm_txw_t*const restrict, struct pgm_sk_buff_t*const restrict); +PGM_GNUC_INTERNAL struct pgm_sk_buff_t* pgm_txw_peek (const pgm_txw_t*const, const uint32_t) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL bool pgm_txw_retransmit_push (pgm_txw_t*const, const uint32_t, const bool, const uint8_t) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL struct pgm_sk_buff_t* pgm_txw_retransmit_try_peek (pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +PGM_GNUC_INTERNAL void pgm_txw_retransmit_remove_head (pgm_txw_t*const); +PGM_GNUC_INTERNAL uint32_t pgm_txw_get_unfolded_checksum (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE; +PGM_GNUC_INTERNAL void pgm_txw_set_unfolded_checksum (struct pgm_sk_buff_t*const, const uint32_t); +PGM_GNUC_INTERNAL void pgm_txw_inc_retransmit_count (struct pgm_sk_buff_t*const); +PGM_GNUC_INTERNAL bool pgm_txw_retransmit_is_empty (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; + +/* declare for GCC attributes */ +static inline size_t pgm_txw_max_length (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline uint32_t pgm_txw_length (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline size_t pgm_txw_size (const pgm_txw_t*const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline bool pgm_txw_is_empty (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline bool pgm_txw_is_full (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline uint32_t pgm_txw_lead (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline uint32_t pgm_txw_lead_atomic (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline uint32_t pgm_txw_next_lead (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline uint32_t pgm_txw_trail (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; +static inline uint32_t pgm_txw_trail_atomic (const pgm_txw_t* const) PGM_GNUC_WARN_UNUSED_RESULT; + +static inline +size_t +pgm_txw_max_length ( + const pgm_txw_t*const window + ) +{ + pgm_assert (NULL != window); + return window->alloc; +} + +static inline +uint32_t +pgm_txw_length ( + const pgm_txw_t*const window + ) +{ + pgm_assert (NULL != window); + return ( 1 + window->lead ) - window->trail; +} + +static inline +size_t +pgm_txw_size ( + const pgm_txw_t*const window + ) +{ + pgm_assert (NULL != window); + return window->size; +} + +static inline +bool +pgm_txw_is_empty ( + const pgm_txw_t*const window + ) +{ + pgm_assert (NULL != window); + return (0 == pgm_txw_length (window)); +} + +static inline +bool +pgm_txw_is_full ( + const pgm_txw_t*const window + ) +{ + pgm_assert (NULL != window); + return (pgm_txw_length (window) == pgm_txw_max_length (window)); +} + +static inline +uint32_t +pgm_txw_lead ( + const pgm_txw_t*const window + ) +{ + pgm_assert (NULL != window); + return window->lead; +} + +/* atomics may rely on global variables and so cannot be defined __pure__ */ +static inline +uint32_t +pgm_txw_lead_atomic ( + const pgm_txw_t*const window + ) +{ + pgm_assert (NULL != window); + return pgm_atomic_read32 (&window->lead); +} + +static inline +uint32_t +pgm_txw_next_lead ( + const pgm_txw_t*const window + ) +{ + pgm_assert (NULL != window); + return (uint32_t)(pgm_txw_lead (window) + 1); +} + +static inline +uint32_t +pgm_txw_trail ( + const pgm_txw_t*const window + ) +{ + pgm_assert (NULL != window); + return window->trail; +} + +static inline +uint32_t +pgm_txw_trail_atomic ( + const pgm_txw_t*const window + ) +{ + pgm_assert (NULL != window); + return pgm_atomic_read32 (&window->trail); +} + +PGM_END_DECLS + +#endif /* __PGM_IMPL_TXW_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/impl/wsastrerror.h b/3rdparty/openpgm-svn-r1135/pgm/include/impl/wsastrerror.h new file mode 100644 index 0000000..1be4ef2 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/impl/wsastrerror.h @@ -0,0 +1,37 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Winsock Error strings. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined (__PGM_IMPL_FRAMEWORK_H_INSIDE__) && !defined (PGM_COMPILATION) +# error "Only can be included directly." +#endif + +#ifndef __PGM_IMPL_WSASTRERROR_H__ +#define __PGM_IMPL_WSASTRERROR_H__ + +#include + +PGM_BEGIN_DECLS + +char* pgm_wsastrerror (const int); +char* pgm_adapter_strerror (const int); +char* pgm_win_strerror (char*, size_t, const int); + +PGM_END_DECLS + +#endif /* __PGM_IMPL_WSASTRERROR_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/atomic.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/atomic.h new file mode 100644 index 0000000..60349f7 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/atomic.h @@ -0,0 +1,140 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * 32-bit atomic operations. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_ATOMIC_H__ +#define __PGM_ATOMIC_H__ + +#ifdef sun +# include +#endif +#include + +static inline +uint32_t +pgm_atomic_exchange_and_add32 ( + volatile uint32_t* atomic, + const uint32_t val + ) +{ +#if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) + uint32_t result; + asm volatile ( "lock\n\t" + "xaddl %0, %1" + : "=r" (result), "=m" (*atomic) + : "0" (val), "m" (*atomic) + : "memory", "cc" ); + return result; +#elif (defined( __SUNPRO_C ) || defined( __SUNPRO_CC )) && (defined( __i386 ) || defined( __amd64 )) + uint32_t result = val; + asm volatile ( "lock\n\t" + "xaddl %0, %1" + :: "r" (result), "m" (*atomic) ); + return result; +#elif defined( sun ) + const uint32_t nv = atomic_add_32_nv (atomic, (int32_t)val); + return nv - val; +#elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) + return __sync_fetch_and_add (atomic, val); +#elif defined( _WIN32 ) + return InterlockedExchangeAdd ((volatile LONG*)atomic, val); +#else +# error "No supported atomic operations for this platform." +#endif +} + +static inline +void +pgm_atomic_add32 ( + volatile uint32_t* atomic, + const uint32_t val + ) +{ +#if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) + asm volatile ( "lock\n\t" + "addl %1, %0" + : "=m" (*atomic) + : "ir" (val), "m" (*atomic) + : "memory", "cc" ); +#elif (defined( __SUNPRO_C ) || defined( __SUNPRO_CC )) && (defined( __i386 ) || defined( __amd64 )) + asm volatile ( "lock\n\t" + "addl %1, %0" + :: "r" (val), "m" (*atomic) ); +#elif defined( sun ) + atomic_add_32 (atomic, (int32_t)val); +#elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) + __sync_fetch_and_add (atomic, val); +#elif defined( _WIN32 ) + InterlockedExchangeAdd ((volatile LONG*)atomic, val); +#endif +} + +static inline +void +pgm_atomic_inc32 ( + volatile uint32_t* atomic + ) +{ +#if (defined( __GNUC__ ) && (defined( __i386__ ) || defined( __x86_64__ ))) || ((defined( __SUNPRO_C ) || defined( __SUNPRO_CC )) && (defined( __i386 ) || defined( __amd64 ))) + pgm_atomic_add32 (atomic, 1); +#elif defined( sun ) + atomic_inc_32 (atomic); +#elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) + pgm_atomic_add32 (atomic, 1); +#elif defined( _WIN32 ) + InterlockedIncrement ((volatile LONG*)atomic); +#endif +} + +static inline +void +pgm_atomic_dec32 ( + volatile uint32_t* atomic + ) +{ +#if (defined( __GNUC__ ) && (defined( __i386__ ) || defined( __x86_64__ ))) || ((defined( __SUNPRO_C ) || defined( __SUNPRO_CC )) && (defined( __i386 ) || defined( __amd64 ))) + pgm_atomic_add32 (atomic, (uint32_t)-1); +#elif defined( sun ) + atomic_dec_32 (atomic); +#elif defined( __GNUC__ ) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) + pgm_atomic_add32 (atomic, (uint32_t)-1); +#elif defined( _WIN32 ) + InterlockedDecrement ((volatile LONG*)atomic); +#endif +} + +static inline +uint32_t +pgm_atomic_read32 ( + const volatile uint32_t* atomic + ) +{ + return *atomic; +} + +static inline +void +pgm_atomic_write32 ( + volatile uint32_t* atomic, + const uint32_t val + ) +{ + *atomic = val; +} + +#endif /* __PGM_ATOMIC_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/backtrace.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/backtrace.h new file mode 100644 index 0000000..24f8469 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/backtrace.h @@ -0,0 +1,33 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Dump back trace to stderr and try gdb. + * + * Copyright (c) 2006 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_BACKTRACE_H__ +#define __PGM_BACKTRACE_H__ + +#include + +PGM_BEGIN_DECLS + +PGM_GNUC_NORETURN void on_sigsegv (int); + +PGM_END_DECLS + +#endif /* __PGM_BACKTRACE_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/engine.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/engine.h new file mode 100644 index 0000000..43115e8 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/engine.h @@ -0,0 +1,37 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM engine. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_ENGINE_H__ +#define __PGM_ENGINE_H__ + +#include +#include + +PGM_BEGIN_DECLS + +bool pgm_init (pgm_error_t**); +bool pgm_supported (void) PGM_GNUC_WARN_UNUSED_RESULT PGM_GNUC_PURE; +bool pgm_shutdown (void); +void pgm_drop_superuser (void); + +PGM_END_DECLS + +#endif /* __PGM_ENGINE_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/error.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/error.h new file mode 100644 index 0000000..3d77290 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/error.h @@ -0,0 +1,109 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable error reporting. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_ERROR_H__ +#define __PGM_ERROR_H__ + +typedef struct pgm_error_t pgm_error_t; + +#include + +PGM_BEGIN_DECLS + +/* error domains */ +enum +{ + PGM_ERROR_DOMAIN_IF, /* interface and host */ + PGM_ERROR_DOMAIN_PACKET, + PGM_ERROR_DOMAIN_RECV, + PGM_ERROR_DOMAIN_TIME, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_DOMAIN_ENGINE, + PGM_ERROR_DOMAIN_HTTP, + PGM_ERROR_DOMAIN_SNMP +}; + +/* error codes */ +enum +{ + /* Derived from errno, eai_errno, etc */ + PGM_ERROR_ADDRFAMILY, /* EAI_ADDRFAMILY */ + PGM_ERROR_AFNOSUPPORT, /* EAI_FAMILY */ + PGM_ERROR_AGAIN, + PGM_ERROR_BADE, /* ERROR_INVALID_DATA */ + PGM_ERROR_BADF, + PGM_ERROR_BOUNDS, /* sequence out-of-bounds */ + PGM_ERROR_CKSUM, /* pkt cksum incorrect */ + PGM_ERROR_CONNRESET, + PGM_ERROR_FAIL, /* EAI_FAIL */ + PGM_ERROR_FAULT, + PGM_ERROR_INPROGRESS, /* WSAEINPROGRESS */ + PGM_ERROR_INTR, + PGM_ERROR_INVAL, + PGM_ERROR_MFILE, + PGM_ERROR_NFILE, + PGM_ERROR_NOBUFS, /* ERROR_BUFFER_OVERFLOW */ + PGM_ERROR_NODATA, /* EAI_NODATA */ + PGM_ERROR_NODEV, + PGM_ERROR_NOENT, + PGM_ERROR_NOMEM, + PGM_ERROR_NONAME, /* EAI_NONAME */ + PGM_ERROR_NONET, + PGM_ERROR_NOPROTOOPT, + PGM_ERROR_NOSYS, /* ERROR_NOT_SUPPORTED */ + PGM_ERROR_NOTUNIQ, + PGM_ERROR_NXIO, + PGM_ERROR_PERM, + PGM_ERROR_PROCLIM, /* WSAEPROCLIM */ + PGM_ERROR_PROTO, + PGM_ERROR_RANGE, + PGM_ERROR_SERVICE, /* EAI_SERVICE */ + PGM_ERROR_SOCKTNOSUPPORT, /* EAI_SOCKTYPE */ + PGM_ERROR_SYSNOTAREADY, /* WSASYSNOTAREADY */ + PGM_ERROR_SYSTEM, /* EAI_SYSTEM */ + PGM_ERROR_VERNOTSUPPORTED, /* WSAVERNOTSUPPORTED */ + PGM_ERROR_XDEV, + + PGM_ERROR_FAILED /* generic error */ +}; + +struct pgm_error_t +{ + int domain; + int code; + char* message; +}; + +void pgm_error_free (pgm_error_t*); +void pgm_set_error (pgm_error_t**restrict, const int, const int, const char*restrict, ...) PGM_GNUC_PRINTF (4, 5); +void pgm_propagate_error (pgm_error_t**restrict, pgm_error_t*restrict); +void pgm_clear_error (pgm_error_t**); +void pgm_prefix_error (pgm_error_t**restrict, const char*restrict, ...) PGM_GNUC_PRINTF (2, 3); + +int pgm_error_from_errno (const int) PGM_GNUC_CONST; +int pgm_error_from_h_errno (const int) PGM_GNUC_CONST; +int pgm_error_from_eai_errno (const int, const int) PGM_GNUC_CONST; +int pgm_error_from_wsa_errno (const int) PGM_GNUC_CONST; +int pgm_error_from_win_errno (const int) PGM_GNUC_CONST; + +PGM_END_DECLS + +#endif /* __PGM_ERROR_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/gsi.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/gsi.h new file mode 100644 index 0000000..86d2921 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/gsi.h @@ -0,0 +1,51 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * global session ID helper functions + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_GSI_H__ +#define __PGM_GSI_H__ + +typedef struct pgm_gsi_t pgm_gsi_t; + +#include +#include + +PGM_BEGIN_DECLS + +#define PGM_GSISTRLEN (sizeof("000.000.000.000.000.000")) +#define PGM_GSI_INIT {{ 0, 0, 0, 0, 0, 0 }} + +struct pgm_gsi_t { + uint8_t identifier[6]; +}; + +PGM_STATIC_ASSERT(sizeof(struct pgm_gsi_t) == 6); + +bool pgm_gsi_create_from_hostname (pgm_gsi_t*restrict, pgm_error_t**restrict); +bool pgm_gsi_create_from_addr (pgm_gsi_t*restrict, pgm_error_t**restrict); +bool pgm_gsi_create_from_data (pgm_gsi_t*restrict, const uint8_t*restrict, const size_t); +bool pgm_gsi_create_from_string (pgm_gsi_t*restrict, const char*restrict, ssize_t); +int pgm_gsi_print_r (const pgm_gsi_t*restrict, char*restrict, const size_t); +char* pgm_gsi_print (const pgm_gsi_t*); +bool pgm_gsi_equal (const void*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; + +PGM_END_DECLS + +#endif /* __PGM_GSI_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/http.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/http.h new file mode 100644 index 0000000..5c65d15 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/http.h @@ -0,0 +1,37 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * HTTP administrative interface + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_HTTP_H__ +#define __PGM_HTTP_H__ + +#include +#include + +PGM_BEGIN_DECLS + +#define PGM_HTTP_DEFAULT_SERVER_PORT 4968 + +bool pgm_http_init (uint16_t, pgm_error_t**) PGM_GNUC_WARN_UNUSED_RESULT; +bool pgm_http_shutdown (void); + +PGM_END_DECLS + +#endif /* __PGM_HTTP_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/if.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/if.h new file mode 100644 index 0000000..814d235 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/if.h @@ -0,0 +1,33 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * network interface handling. + * + * Copyright (c) 2006 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IF_H__ +#define __PGM_IF_H__ + +#include + +PGM_BEGIN_DECLS + +void pgm_if_print_all (void); + +PGM_END_DECLS + +#endif /* __PGM_IF_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/ip/pgm.hh b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/ip/pgm.hh new file mode 100644 index 0000000..a5e260f --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/ip/pgm.hh @@ -0,0 +1,100 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM protocol + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IP_PGM_HH__ +#define __PGM_IP_PGM_HH__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +namespace pgm { +#define restrict +#include +} + +namespace ip { + +class pgm +{ +public: + /// The type of a PGM endpoint. + typedef pgm_endpoint endpoint; + + /// Construct to represent PGM over IPv4. + static pgm v4() + { + return pgm (PF_INET); + } + + /// Construct to represent PGM over IPv6. + static pgm v6() + { + return pgm (PF_INET6); + } + + /// Obtain an identifier for the type of the protocol. + int type() const + { + return SOCK_SEQPACKET; + } + + /// Obtain an identifier for the protocol. + int protocol() const + { + return IPPROTO_PGM; + } + + /// Obtain an identifier for the protocol family. + int family() const + { + return family_; + } + + /// The PGM socket type. + typedef pgm_socket socket; + + /// Compare two protocols for equality. + friend bool operator== (const pgm& p1, const pgm& p2) + { + return p1.family_ == p2.family_; + } + + /// Compare two protocols for inequality. + friend bool operator!= (const pgm& p1, const pgm& p2) + { + return p1.family_ != p2.family_; + } + +private: + // Construct with a specific family. + explicit pgm (int family) + : family_ (family) + { + } + + int family_; +}; + +} // namespace ip + + +#endif /* __PGM_IP_PGM_HH__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/ip/pgm_endpoint.hh b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/ip/pgm_endpoint.hh new file mode 100644 index 0000000..1114719 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/ip/pgm_endpoint.hh @@ -0,0 +1,171 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM endpoint + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_IP_PGM_ENDPOINT_HH__ +#define __PGM_IP_PGM_ENDPOINT_HH__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +namespace pgm { +#define restrict +#include +} + +namespace ip { + +template +class pgm_endpoint +{ +public: + /// The protocol type associated with the endpoint. + typedef InternetProtocol protocol_type; + + typedef struct cpgm::pgm_sockaddr_t data_type; + + /// Default constructor. + pgm_endpoint() + : data_() + { + data_.sa_port = 0; + cpgm::pgm_tsi_t tmp_addr = PGM_TSI_INIT; + data_.sa_addr = tmp_addr; + } + + /// Construct an endpoint using a port number, specified in host byte + /// order. The GSI will be generated from the node name. + /** + * @par examples + * To initialise a PGM endpoint for port 7500, use: + * @code + * ip::pgm::endpoint ep (7500); + * @endcode + */ + pgm_endpoint (unsigned short port_num) + : data_() + { + data_.sa_port = port_num; + data_.sa_addr.sport = 0; + pgm_gsi_create_from_hostname (&data_.sa_addr.gsi, NULL); + } + + /// Construct an endpoint using a port number and a TSI. + pgm_endpoint (const cpgm::pgm_tsi_t& tsi, unsigned short port_num) + : data_() + { + data_.sa_port = port_num; + data_.sa_addr = tsi; + } + + /// Construct an endpoint using a port number and a memory area. + pgm_endpoint (const void* src, std::size_t len, unsigned short port_num) + : data_() + { + data_.sa_port = port_num; + data_.sa_addr.sport = 0; + pgm_gsi_create_from_data (&data_.sa_addr.gsi, src, len); + } + + /// Copy constructor. + pgm_endpoint (const pgm_endpoint& other) + : data_ (other.data_) + { + } + + /// Assign from another endpoint. + pgm_endpoint& operator= (const pgm_endpoint& other) + { + data_ = other.data_; + return *this; + } + + /// Get the underlying endpoint in the native type. + const data_type* data() const + { + return &data_; + } + + /// Get the underlying size of the endpoint in the native type. + std::size_t size() const + { + return sizeof(data_type); + } + + /// Get the port associated with the endpoint. The port number is always in + /// the host's byte order. + unsigned short port() const + { + return data_.sa_port; + } + + /// Set the port associated with the endpoint. The port number is always in + /// the host's byte order. + void port (unsigned short port_num) + { + data_.sa_port = port_num; + } + + /// Get the TSI associated with the endpoint. + const cpgm::pgm_tsi_t* address() const + { + return &data_.sa_addr; + } + + /// Set the TSI associated with the endpoint. + void address (cpgm::pgm_tsi_t& addr) + { + data_.sa_addr = addr; + } + + /// Compare two endpoints for equality. + friend bool operator== (const pgm_endpoint& e1, + const pgm_endpoint& e2) + { + return e1.address() == e2.address() && e1.port() == e2.port(); + } + + /// Compare two endpoints for inequality. + friend bool operator!= (const pgm_endpoint& e1, + const pgm_endpoint& e2) + { + return e1.address() != e2.address() || e1.port() != e2.port(); + } + + /// Compare endpoints for ordering. + friend bool operator<(const pgm_endpoint& e1, + const pgm_endpoint& e2) + { + if (e1.address() < e2.address()) + return true; + if (e1.address() != e2.address()) + return false; + return e1.port() < e2.port(); + } + +private: + // The underlying PGM socket address. + data_type data_; +}; + +} // namespace ip + +#endif /* __PGM_IP_PGM_ENDPOINT_HH__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/list.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/list.h new file mode 100644 index 0000000..b91abc9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/list.h @@ -0,0 +1,40 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable doubly-linked list. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_LIST_H__ +#define __PGM_LIST_H__ + +typedef struct pgm_list_t pgm_list_t; + +#include + +PGM_BEGIN_DECLS + +struct pgm_list_t +{ + void* data; + struct pgm_list_t* next; + struct pgm_list_t* prev; +}; + +PGM_END_DECLS + +#endif /* __PGM_LIST_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/log.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/log.h new file mode 100644 index 0000000..2b6c036 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/log.h @@ -0,0 +1,33 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * basic logging. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_LOG_H__ +#define __PGM_LOG_H__ + +#include + +PGM_BEGIN_DECLS + +bool log_init (void); + +PGM_END_DECLS + +#endif /* __PGM_LOG_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/macros.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/macros.h new file mode 100644 index 0000000..da7e4d7 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/macros.h @@ -0,0 +1,171 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Pre-processor macros for cross-platform, cross-compiler ice cream. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_MACROS_H__ +#define __PGM_MACROS_H__ + +/* NULL, ptrdiff_t, and size_t + */ + +#include + + +/* GCC function attributes + * http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html + */ + +#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) + +/* No side-effects except return value, may follow pointers and read globals */ +# define PGM_GNUC_PURE __attribute__((__pure__)) + +/* Returns new memory like malloc() */ +# define PGM_GNUC_MALLOC __attribute__((__malloc__)) + +# define PGM_GNUC_CACHELINE_ALIGNED __attribute__((__aligned__(SMP_CACHE_BYTES), \ + __section__((".data.cacheline_aligned"))) +# define PGM_GNUC_READ_MOSTLY __attribute__((__section__(".data.read_mostly"))) + +#else +# define PGM_GNUC_PURE +# define PGM_GNUC_MALLOC +# define PGM_GNUC_CACHELINE_ALIGNED +# define PGM_GNUC_READ_MOSTLY +#endif + +#if (__GNUC__ >= 4) + +/* Variable argument function with NULL terminated list */ +# define PGM_GNUC_NULL_TERMINATED __attribute__((__sentinel__)) +#else +# define PGM_GNUC_NULL_TERMINATED +#endif + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) + +/* malloc() with xth parameter being size */ +# define PGM_GNUC_ALLOC_SIZE(x) __attribute__((__alloc_size__(x))) + +/* malloc() with xth*yth parameters being size */ +# define PGM_GNUC_ALLOC_SIZE2(x,y) __attribute__((__alloc_size__(x,y))) +#else +# define PGM_GNUC_ALLOC_SIZE(x) +# define PGM_GNUC_ALLOC_SIZE2(x,y) +#endif + +#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) + +/* printf() like function */ +# define PGM_GNUC_PRINTF(format, args) __attribute__((__format__ (__printf__, format, args))) +# define PGM_GNUC_FORMAT(format) __attribute__((__format_arg__ (format))) + +/* Function will never return */ +# define PGM_GNUC_NORETURN __attribute__((__noreturn__)) + +/* No side-effects except return value, must not follow pointers or read globals */ +# define PGM_GNUC_CONST __attribute__((__const__)) + +/* Unused function */ +# define PGM_GNUC_UNUSED __attribute__((__unused__)) + +#else /* !__GNUC__ */ +# define PGM_GNUC_PRINTF(format, args) +# define PGM_GNUC_NORETURN +# define PGM_GNUC_CONST +# define PGM_GNUC_UNUSED +#endif /* !__GNUC__ */ + +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + +/* Raise compiler warning if caller ignores return value */ +# define PGM_GNUC_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) + +# ifdef CONFIG_HAVE_DSO_VISIBILITY +/* Hidden visibility */ +# define PGM_GNUC_INTERNAL __attribute__((visibility("hidden"))) +# else +# define PGM_GNUC_INTERNAL +# endif +#else /* !__GNUC__ */ +# define PGM_GNUC_WARN_UNUSED_RESULT +# if ((defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)) || (defined(__SUNPRO_CC) && (__SUNPRO_CC >= 0x550))) && defined(CONFIG_HAVE_DSO_VISIBILITY) +# define PGM_GNUC_INTERNAL __hidden +# else +# define PGM_GNUC_INTERNAL +# endif +#endif /* __GNUC__ */ + + +/* Compiler time assertions, must be on unique lines in the project */ +#define PGM_PASTE_ARGS(identifier1,identifier2) identifier1 ## identifier2 +#define PGM_PASTE(identifier1,identifier2) PGM_PASTE_ARGS (identifier1, identifier2) +#define PGM_STATIC_ASSERT(expr) typedef struct { char compile_time_assertion[(expr) ? 1 : -1]; } PGM_PASTE (_pgm_static_assert_, __LINE__) + +/* Function declaration wrappers for C++ */ +#ifdef __cplusplus +# define PGM_BEGIN_DECLS extern "C" { +# define PGM_END_DECLS } +#else +# define PGM_BEGIN_DECLS +# define PGM_END_DECLS +#endif + +/* Surprisingly still not defined in C99 */ +#ifndef FALSE +# define FALSE (0) +#endif + +#ifndef TRUE +# define TRUE (!FALSE) +#endif + +#undef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#undef ABS +#define ABS(a) (((a) < 0) ? -(a) : (a)) + +#undef CLAMP +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) + +/* Number of elements */ +#define PGM_N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0])) + +/* Structure offsets */ +#if defined(__GNUC__) && __GNUC__ >= 4 +# define PGM_OFFSETOF(struct_type, member) (offsetof (struct_type, member)) +#else +# define PGM_OFFSETOF(struct_type, member) ((size_t)((char*)&((struct_type*) 0)->member)) +#endif + +/* Branch prediction hint */ +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +# define PGM_LIKELY(expr) __builtin_expect ((expr), 1) +# define PGM_UNLIKELY(expr) __builtin_expect ((expr), 0) +#else +# define PGM_LIKELY(expr) (expr) +# define PGM_UNLIKELY(expr) (expr) +#endif + +#endif /* __PGM_MACROS_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/mem.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/mem.h new file mode 100644 index 0000000..eea31fe --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/mem.h @@ -0,0 +1,60 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable fail fast memory allocation. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_MEM_H__ +#define __PGM_MEM_H__ + +#ifdef CONFIG_HAVE_ALLOCA_H +# include +#elif defined(_WIN32) +# include +#else +# include +#endif +#include + +PGM_BEGIN_DECLS + +extern bool pgm_mem_gc_friendly; + +void* pgm_malloc (const size_t) PGM_GNUC_MALLOC PGM_GNUC_ALLOC_SIZE(1); +void* pgm_malloc_n (const size_t, const size_t) PGM_GNUC_MALLOC PGM_GNUC_ALLOC_SIZE2(1, 2); +void* pgm_malloc0 (const size_t) PGM_GNUC_MALLOC PGM_GNUC_ALLOC_SIZE(1); +void* pgm_malloc0_n (const size_t, const size_t) PGM_GNUC_MALLOC PGM_GNUC_ALLOC_SIZE2(1, 2); +void* pgm_memdup (const void*, const size_t) PGM_GNUC_MALLOC; +void* pgm_realloc (void*, const size_t) PGM_GNUC_WARN_UNUSED_RESULT; +void pgm_free (void*); + +/* Convenience memory allocators that wont work well above 32-bit sizes + */ +#define pgm_new(struct_type, n_structs) \ + ((struct_type*)pgm_malloc_n ((size_t)sizeof(struct_type), (size_t)(n_structs))) +#define pgm_new0(struct_type, n_structs) \ + ((struct_type*)pgm_malloc0_n ((size_t)sizeof(struct_type), (size_t)(n_structs))) + +#define pgm_alloca(size) \ + alloca (size) +#define pgm_newa(struct_type, n_structs) \ + ((struct_type*) pgm_alloca (sizeof(struct_type) * (size_t)(n_structs))) + +PGM_END_DECLS + +#endif /* __PGM_MEM_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/messages.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/messages.h new file mode 100644 index 0000000..6a00b8f --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/messages.h @@ -0,0 +1,66 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * basic message reporting. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_MESSAGES_H__ +#define __PGM_MESSAGES_H__ + +#include + +PGM_BEGIN_DECLS + +/* Set bitmask of log roles in environmental variable PGM_LOG_MASK, + * borrowed from SmartPGM. + */ +enum { + PGM_LOG_ROLE_MEMORY = 0x001, + PGM_LOG_ROLE_NETWORK = 0x002, + PGM_LOG_ROLE_CONFIGURATION = 0x004, + PGM_LOG_ROLE_SESSION = 0x010, + PGM_LOG_ROLE_NAK = 0x020, + PGM_LOG_ROLE_RATE_CONTROL = 0x040, + PGM_LOG_ROLE_TX_WINDOW = 0x080, + PGM_LOG_ROLE_RX_WINDOW = 0x100, + PGM_LOG_ROLE_FEC = 0x400, + PGM_LOG_ROLE_CONGESTION_CONTROL = 0x800 +}; + +enum { + PGM_LOG_LEVEL_DEBUG = 0, + PGM_LOG_LEVEL_TRACE = 1, + PGM_LOG_LEVEL_MINOR = 2, + PGM_LOG_LEVEL_NORMAL = 3, + PGM_LOG_LEVEL_WARNING = 4, + PGM_LOG_LEVEL_ERROR = 5, + PGM_LOG_LEVEL_FATAL = 6 +}; + +extern int pgm_log_mask; +extern int pgm_min_log_level; + +typedef void (*pgm_log_func_t) (const int, const char*restrict, void*restrict); + +pgm_log_func_t pgm_log_set_handler (pgm_log_func_t, void*); +void pgm_messages_init (void); +void pgm_messages_shutdown (void); + +PGM_END_DECLS + +#endif /* __PGM_MESSAGES_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/msgv.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/msgv.h new file mode 100644 index 0000000..f5effcb --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/msgv.h @@ -0,0 +1,54 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Vector message container + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_MSGV_H__ +#define __PGM_MSGV_H__ + +struct pgm_iovec; +struct pgm_msgv_t; + +#include +#include +#include + +PGM_BEGIN_DECLS + +/* struct for scatter/gather I/O */ +struct pgm_iovec { +#ifndef _WIN32 +/* match struct iovec */ + void* iov_base; + size_t iov_len; /* size of iov_base */ +#else +/* match WSABUF */ + u_long iov_len; + char* iov_base; +#endif /* _WIN32 */ +}; + +struct pgm_msgv_t { + uint32_t msgv_len; /* number of elements in skb */ + struct pgm_sk_buff_t* msgv_skb[PGM_MAX_FRAGMENTS]; /* PGM socket buffer array */ +}; + +PGM_END_DECLS + +#endif /* __PGM_MSGV_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/packet.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/packet.h new file mode 100644 index 0000000..fb1c13a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/packet.h @@ -0,0 +1,475 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM packet formats, RFC 3208. + * + * Copyright (c) 2006 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_PACKET_H__ +#define __PGM_PACKET_H__ + +#ifndef _WIN32 +# include +# include +# include +#endif +#include + +PGM_BEGIN_DECLS + +/* protocol number assigned by IANA */ +#ifndef IPPROTO_PGM +# define IPPROTO_PGM 113 +#endif + +/* read from /etc/protocols if available */ +extern int pgm_ipproto_pgm; + + +/* address family indicator, rfc 1700 (ADDRESS FAMILY NUMBERS) */ +#ifndef AFI_IP +# define AFI_IP 1 /* IP (IP version 4) */ +# define AFI_IP6 2 /* IP6 (IP version 6) */ +#endif + +/* UDP ports for UDP encapsulation, as per IBM WebSphere MQ */ +#define DEFAULT_UDP_ENCAP_UCAST_PORT 3055 +#define DEFAULT_UDP_ENCAP_MCAST_PORT 3056 + +/* PGM default ports */ +#define DEFAULT_DATA_DESTINATION_PORT 7500 +#define DEFAULT_DATA_SOURCE_PORT 0 /* random */ + +/* DoS limitation to protocol (MS08-036, KB950762) */ +#ifndef PGM_MAX_APDU +# define PGM_MAX_APDU UINT16_MAX +#endif + +/* Cisco default: 24 (max 8200), Juniper & H3C default: 16, SmartPGM: 64 */ +#ifndef PGM_MAX_FRAGMENTS +# define PGM_MAX_FRAGMENTS 16 +#endif + + +enum pgm_type_e { + PGM_SPM = 0x00, /* 8.1: source path message */ + PGM_POLL = 0x01, /* 14.7.1: poll request */ + PGM_POLR = 0x02, /* 14.7.2: poll response */ + PGM_ODATA = 0x04, /* 8.2: original data */ + PGM_RDATA = 0x05, /* 8.2: repair data */ + PGM_NAK = 0x08, /* 8.3: NAK or negative acknowledgement */ + PGM_NNAK = 0x09, /* 8.3: N-NAK or null negative acknowledgement */ + PGM_NCF = 0x0a, /* 8.3: NCF or NAK confirmation */ + PGM_SPMR = 0x0c, /* 13.6: SPM request */ + PGM_ACK = 0x0d, /* PGMCC: congestion control ACK */ + PGM_MAX = 0xff +}; + +#define PGM_OPT_LENGTH 0x00 /* options length */ +#define PGM_OPT_FRAGMENT 0x01 /* fragmentation */ +#define PGM_OPT_NAK_LIST 0x02 /* list of nak entries */ +#define PGM_OPT_JOIN 0x03 /* late joining */ +#define PGM_OPT_REDIRECT 0x07 /* redirect */ +#define PGM_OPT_SYN 0x0d /* synchronisation */ +#define PGM_OPT_FIN 0x0e /* session end */ +#define PGM_OPT_RST 0x0f /* session reset */ + +#define PGM_OPT_PARITY_PRM 0x08 /* forward error correction parameters */ +#define PGM_OPT_PARITY_GRP 0x09 /* group number */ +#define PGM_OPT_CURR_TGSIZE 0x0a /* group size */ + +#define PGM_OPT_CR 0x10 /* congestion report */ +#define PGM_OPT_CRQST 0x11 /* congestion report request */ + +#define PGM_OPT_PGMCC_DATA 0x12 +#define PGM_OPT_PGMCC_FEEDBACK 0x13 + +#define PGM_OPT_NAK_BO_IVL 0x04 /* nak back-off interval */ +#define PGM_OPT_NAK_BO_RNG 0x05 /* nak back-off range */ +#define PGM_OPT_NBR_UNREACH 0x0b /* neighbour unreachable */ +#define PGM_OPT_PATH_NLA 0x0c /* path nla */ + +#define PGM_OPT_INVALID 0x7f /* option invalidated */ + +/* byte alignment for packet memory maps */ +#if defined( __GNUC__ ) && !defined( sun ) +# pragma pack(push) +#endif +#pragma pack(1) + +/* 8. PGM header */ +struct pgm_header { + uint16_t pgm_sport; /* source port: tsi::sport or UDP port depending on direction */ + uint16_t pgm_dport; /* destination port */ + uint8_t pgm_type; /* version / packet type */ + uint8_t pgm_options; /* options */ +#define PGM_OPT_PARITY 0x80 /* parity packet */ +#define PGM_OPT_VAR_PKTLEN 0x40 /* + variable sized packets */ +#define PGM_OPT_NETWORK 0x02 /* network-significant: must be interpreted by network elements */ +#define PGM_OPT_PRESENT 0x01 /* option extension are present */ + uint16_t pgm_checksum; /* checksum */ + uint8_t pgm_gsi[6]; /* global source id */ + uint16_t pgm_tsdu_length; /* tsdu length */ + /* tpdu length = th length (header + options) + tsdu length */ +}; + +/* 8.1. Source Path Messages (SPM) */ +struct pgm_spm { + uint32_t spm_sqn; /* spm sequence number */ + uint32_t spm_trail; /* trailing edge sequence number */ + uint32_t spm_lead; /* leading edge sequence number */ + uint16_t spm_nla_afi; /* nla afi */ + uint16_t spm_reserved; /* reserved */ + struct in_addr spm_nla; /* path nla */ + /* ... option extensions */ +}; + +struct pgm_spm6 { + uint32_t spm6_sqn; /* spm sequence number */ + uint32_t spm6_trail; /* trailing edge sequence number */ + uint32_t spm6_lead; /* leading edge sequence number */ + uint16_t spm6_nla_afi; /* nla afi */ + uint16_t spm6_reserved; /* reserved */ + struct in6_addr spm6_nla; /* path nla */ + /* ... option extensions */ +}; + +/* 8.2. Data Packet */ +struct pgm_data { + uint32_t data_sqn; /* data packet sequence number */ + uint32_t data_trail; /* trailing edge sequence number */ + /* ... option extensions */ + /* ... data */ +}; + +/* 8.3. Negative Acknowledgments and Confirmations (NAK, N-NAK, & NCF) */ +struct pgm_nak { + uint32_t nak_sqn; /* requested sequence number */ + uint16_t nak_src_nla_afi; /* nla afi */ + uint16_t nak_reserved; /* reserved */ + struct in_addr nak_src_nla; /* source nla */ + uint16_t nak_grp_nla_afi; /* nla afi */ + uint16_t nak_reserved2; /* reserved */ + struct in_addr nak_grp_nla; /* multicast group nla */ + /* ... option extension */ +}; + +struct pgm_nak6 { + uint32_t nak6_sqn; /* requested sequence number */ + uint16_t nak6_src_nla_afi; /* nla afi */ + uint16_t nak6_reserved; /* reserved */ + struct in6_addr nak6_src_nla; /* source nla */ + uint16_t nak6_grp_nla_afi; /* nla afi */ + uint16_t nak6_reserved2; /* reserved */ + struct in6_addr nak6_grp_nla; /* multicast group nla */ + /* ... option extension */ +}; + +/* 9. Option header (max 16 per packet) */ +struct pgm_opt_header { + uint8_t opt_type; /* option type */ +#define PGM_OPT_MASK 0x7f +#define PGM_OPT_END 0x80 /* end of options flag */ + uint8_t opt_length; /* option length */ + uint8_t opt_reserved; +#define PGM_OP_ENCODED 0x8 /* F-bit */ +#define PGM_OPX_MASK 0x3 +#define PGM_OPX_IGNORE 0x0 /* extensibility bits */ +#define PGM_OPX_INVALIDATE 0x1 +#define PGM_OPX_DISCARD 0x2 +#define PGM_OP_ENCODED_NULL 0x80 /* U-bit */ +}; + +/* 9.1. Option extension length - OPT_LENGTH */ +struct pgm_opt_length { + uint8_t opt_type; /* include header as total length overwrites reserved/OPX bits */ + uint8_t opt_length; + uint16_t opt_total_length; /* total length of all options */ +}; + +/* 9.2. Option fragment - OPT_FRAGMENT */ +struct pgm_opt_fragment { + uint8_t opt_reserved; /* reserved */ + uint32_t opt_sqn; /* first sequence number */ + uint32_t opt_frag_off; /* offset */ + uint32_t opt_frag_len; /* length */ +}; + +/* 9.3.5. Option NAK List - OPT_NAK_LIST + * + * GNU C allows opt_sqn[0], ISO C89 requireqs opt_sqn[1], ISO C99 permits opt_sqn[] + */ +struct pgm_opt_nak_list { + uint8_t opt_reserved; /* reserved */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +/* C99 flexible array, sizeof() invalid */ + uint32_t opt_sqn[]; /* requested sequence number [62] */ +#elif !defined(__STDC_VERSION__) || defined(__cplusplus) +/* C90 and older */ + uint32_t opt_sqn[1]; +#else +/* GNU C variable-length object */ + uint32_t opt_sqn[0]; +#endif +}; + +/* 9.4.2. Option Join - OPT_JOIN */ +struct pgm_opt_join { + uint8_t opt_reserved; /* reserved */ + uint32_t opt_join_min; /* minimum sequence number */ +}; + +/* 9.5.5. Option Redirect - OPT_REDIRECT */ +struct pgm_opt_redirect { + uint8_t opt_reserved; /* reserved */ + uint16_t opt_nla_afi; /* nla afi */ + uint16_t opt_reserved2; /* reserved */ + struct in_addr opt_nla; /* dlr nla */ +}; + +struct pgm_opt6_redirect { + uint8_t opt6_reserved; /* reserved */ + uint16_t opt6_nla_afi; /* nla afi */ + uint16_t opt6_reserved2; /* reserved */ + struct in6_addr opt6_nla; /* dlr nla */ +}; + +/* 9.6.2. Option Sources - OPT_SYN */ +struct pgm_opt_syn { + uint8_t opt_reserved; /* reserved */ +}; + +/* 9.7.4. Option End Session - OPT_FIN */ +struct pgm_opt_fin { + uint8_t opt_reserved; /* reserved */ +}; + +/* 9.8.4. Option Reset - OPT_RST */ +struct pgm_opt_rst { + uint8_t opt_reserved; /* reserved */ +}; + + +/* + * Forward Error Correction - FEC + */ + +/* 11.8.1. Option Parity - OPT_PARITY_PRM */ +struct pgm_opt_parity_prm { + uint8_t opt_reserved; /* reserved */ +#define PGM_PARITY_PRM_MASK 0x3 +#define PGM_PARITY_PRM_PRO 0x1 /* source provides pro-active parity packets */ +#define PGM_PARITY_PRM_OND 0x2 /* on-demand parity packets */ + uint32_t parity_prm_tgs; /* transmission group size */ +}; + +/* 11.8.2. Option Parity Group - OPT_PARITY_GRP */ +struct pgm_opt_parity_grp { + uint8_t opt_reserved; /* reserved */ + uint32_t prm_group; /* parity group number */ +}; + +/* 11.8.3. Option Current Transmission Group Size - OPT_CURR_TGSIZE */ +struct pgm_opt_curr_tgsize { + uint8_t opt_reserved; /* reserved */ + uint32_t prm_atgsize; /* actual transmission group size */ +}; + +/* + * Congestion Control + */ + +/* 12.7.1. Option Congestion Report - OPT_CR */ +struct pgm_opt_cr { + uint8_t opt_reserved; /* reserved */ +#define PGM_OPT_CR_NEL 0x0 /* OPT_CR_NE_WL report */ +#define PGM_OPT_CR_NEP 0x1 /* OPT_CR_NE_WP report */ +#define PGM_OPT_CR_RXP 0x2 /* OPT_CR_RX_WP report */ + uint32_t opt_cr_lead; /* congestion report reference sqn */ + uint16_t opt_cr_ne_wl; /* ne worst link */ + uint16_t opt_cr_ne_wp; /* ne worst path */ + uint16_t opt_cr_rx_wp; /* rcvr worst path */ + uint16_t opt_reserved2; /* reserved */ + uint16_t opt_nla_afi; /* nla afi */ + uint16_t opt_reserved3; /* reserved */ + uint32_t opt_cr_rcvr; /* worst receivers nla */ +}; + +/* 12.7.2. Option Congestion Report Request - OPT_CRQST */ +struct pgm_opt_crqst { + uint8_t opt_reserved; /* reserved */ +#define PGM_OPT_CRQST_NEL 0x0 /* request OPT_CR_NE_WL report */ +#define PGM_OPT_CRQST_NEP 0x1 /* request OPT_CR_NE_WP report */ +#define PGM_OPT_CRQST_RXP 0x2 /* request OPT_CR_RX_WP report */ +}; + +/* PGMCC. ACK Packet */ +struct pgm_ack { + uint32_t ack_rx_max; /* RX_MAX */ + uint32_t ack_bitmap; /* received packets */ + /* ... option extensions */ +}; + +/* PGMCC Options */ +struct pgm_opt_pgmcc_data { + uint8_t opt_reserved; /* reserved */ + uint32_t opt_tstamp; /* timestamp */ + uint16_t opt_nla_afi; /* nla afi */ + uint16_t opt_reserved2; /* reserved */ + struct in_addr opt_nla; /* ACKER nla */ +}; + +struct pgm_opt6_pgmcc_data { + uint8_t opt6_reserved; /* reserved */ + uint32_t opt6_tstamp; /* timestamp */ + uint16_t opt6_nla_afi; /* nla afi */ + uint16_t opt6_reserved2; /* reserved */ + struct in6_addr opt6_nla; /* ACKER nla */ +}; + +struct pgm_opt_pgmcc_feedback { + uint8_t opt_reserved; /* reserved */ + uint32_t opt_tstamp; /* timestamp */ + uint16_t opt_nla_afi; /* nla afi */ + uint16_t opt_loss_rate; /* loss rate */ + struct in_addr opt_nla; /* ACKER nla */ +}; + +struct pgm_opt6_pgmcc_feedback { + uint8_t opt6_reserved; /* reserved */ + uint32_t opt6_tstamp; /* timestamp */ + uint16_t opt6_nla_afi; /* nla afi */ + uint16_t opt6_loss_rate; /* loss rate */ + struct in6_addr opt6_nla; /* ACKER nla */ +}; + + +/* + * SPM Requests + */ + +/* 13.6. SPM Requests */ +#if 0 +struct pgm_spmr { + /* ... option extensions */ +}; +#endif + + +/* + * Poll Mechanism + */ + +/* 14.7.1. Poll Request */ +struct pgm_poll { + uint32_t poll_sqn; /* poll sequence number */ + uint16_t poll_round; /* poll round */ + uint16_t poll_s_type; /* poll sub-type */ +#define PGM_POLL_GENERAL 0x0 /* general poll */ +#define PGM_POLL_DLR 0x1 /* DLR poll */ + uint16_t poll_nla_afi; /* nla afi */ + uint16_t poll_reserved; /* reserved */ + struct in_addr poll_nla; /* path nla */ + uint32_t poll_bo_ivl; /* poll back-off interval */ + char poll_rand[4]; /* random string */ + uint32_t poll_mask; /* matching bit-mask */ + /* ... option extensions */ +}; + +struct pgm_poll6 { + uint32_t poll6_sqn; /* poll sequence number */ + uint16_t poll6_round; /* poll round */ + uint16_t poll6_s_type; /* poll sub-type */ + uint16_t poll6_nla_afi; /* nla afi */ + uint16_t poll6_reserved; /* reserved */ + struct in6_addr poll6_nla; /* path nla */ + uint32_t poll6_bo_ivl; /* poll back-off interval */ + char poll6_rand[4]; /* random string */ + uint32_t poll6_mask; /* matching bit-mask */ + /* ... option extensions */ +}; + +/* 14.7.2. Poll Response */ +struct pgm_polr { + uint32_t polr_sqn; /* polr sequence number */ + uint16_t polr_round; /* polr round */ + uint16_t polr_reserved; /* reserved */ + /* ... option extensions */ +}; + + +/* + * Implosion Prevention + */ + +/* 15.4.1. Option NAK Back-Off Interval - OPT_NAK_BO_IVL */ +struct pgm_opt_nak_bo_ivl { + uint8_t opt_reserved; /* reserved */ + uint32_t opt_nak_bo_ivl; /* nak back-off interval */ + uint32_t opt_nak_bo_ivl_sqn; /* nak back-off interval sqn */ +}; + +/* 15.4.2. Option NAK Back-Off Range - OPT_NAK_BO_RNG */ +struct pgm_opt_nak_bo_rng { + uint8_t opt_reserved; /* reserved */ + uint32_t opt_nak_max_bo_ivl; /* maximum nak back-off interval */ + uint32_t opt_nak_min_bo_ivl; /* minimum nak back-off interval */ +}; + +/* 15.4.3. Option Neighbour Unreachable - OPT_NBR_UNREACH */ +struct pgm_opt_nbr_unreach { + uint8_t opt_reserved; /* reserved */ +}; + +/* 15.4.4. Option Path - OPT_PATH_NLA */ +struct pgm_opt_path_nla { + uint8_t opt_reserved; /* reserved */ + struct in_addr opt_path_nla; /* path nla */ +}; + +struct pgm_opt6_path_nla { + uint8_t opt6_reserved; /* reserved */ + struct in6_addr opt6_path_nla; /* path nla */ +}; + + +#if defined( __GNUC__ ) && !defined( sun ) +# pragma pack(pop) +#else +# pragma pack() +#endif + +#define PGM_IS_UPSTREAM(t) \ + ((t) == PGM_NAK /* unicast */ \ + || (t) == PGM_NNAK /* unicast */ \ + || (t) == PGM_SPMR /* multicast + unicast */ \ + || (t) == PGM_POLR /* unicast */ \ + || (t) == PGM_ACK) /* unicast */ + +#define PGM_IS_PEER(t) \ + ((t) == PGM_SPMR) /* multicast */ + +#define PGM_IS_DOWNSTREAM(t) \ + ((t) == PGM_SPM /* all types are multicast */ \ + || (t) == PGM_ODATA \ + || (t) == PGM_RDATA \ + || (t) == PGM_POLL \ + || (t) == PGM_NCF) + +PGM_END_DECLS + +#endif /* __PGM_PACKET_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm.h new file mode 100644 index 0000000..a122f48 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm.h @@ -0,0 +1,42 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * OpenPGM, an implementation of the PGM network protocol. + * + * Copyright (c) 2006-2008 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_H__ +#define __PGM_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* __PGM_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm.hh b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm.hh new file mode 100644 index 0000000..fc3476f --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm.hh @@ -0,0 +1,33 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * OpenPGM C++ wrapper. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_HH__ +#define __PGM_HH__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#endif /* __PGM_HH__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm_socket.hh b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm_socket.hh new file mode 100644 index 0000000..87a5609 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/pgm_socket.hh @@ -0,0 +1,157 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM socket + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_SOCKET_HH__ +#define __PGM_SOCKET_HH__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#ifndef _WIN32 +# include +# include +#else +# include +#endif + +namespace cpgm { +#define restrict +#include +}; + +template +class pgm_socket +{ +public: + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// The native socket type. + typedef struct cpgm::pgm_sock_t* native_type; + + /// Construct a pgm_socket without opening it. + pgm_socket() + { + } + + // Open a new PGM socket implementation. + bool open (::sa_family_t family, int sock_type, int protocol, cpgm::pgm_error_t** error) + { + return cpgm::pgm_socket (&this->native_type_, family, sock_type, protocol, error); + } + + /// Close a PGM socket implementation. + bool close (bool flush) + { + return pgm_close (this->native_type_, flush); + } + + /// Get the native socket implementation. + native_type native (void) + { + return this->native_type_; + } + + // Bind the datagram socket to the specified local endpoint. + bool bind (const endpoint_type& addr, cpgm::pgm_error_t** error) + { + return pgm_bind (this->native_type_, addr.data(), sizeof(addr.data()), error); + } + + /// Connect the PGM socket to the specified endpoint. + bool connect (cpgm::pgm_error_t** error) + { + return pgm_connect (this->native_type_, error); + } + + /// Set a socket option. + bool set_option (int level, int optname, const void* optval, ::socklen_t optlen) + { + return pgm_setsockopt (this->native_type_, level, optname, optval, optlen); + } + + /// Get a socket option. + bool get_option (int level, int optname, void* optval, ::socklen_t* optlen) + { + return pgm_getsockopt (this->native_type_, level, optname, optval, optlen); + } + + /// Get the local endpoint. + endpoint_type local_endpoint() const + { + endpoint_type endpoint; + pgm_getsockname (this->native_type_, &endpoint); + return endpoint; + } + + /// Disable sends or receives on the socket. + bool shutdown (int what) + { + int optname, v = 1; +#ifndef _WIN32 + if (SHUT_RD == what) optname = cpgm::PGM_SEND_ONLY; + else if (SHUT_WR == what) optname = cpgm::PGM_RECV_ONLY; +#else + if (SD_RECEIVE == what) optname = cpgm::PGM_SEND_ONLY; + else if (SD_SEND == what) optname = cpgm::PGM_RECV_ONLY; +#endif + else { + errno = EINVAL; + return false; + } + return pgm_setsockopt (this->native_type_, optname, v, sizeof(v)); + } + + /// Send some data on a connected socket. + int send (const void* buf, std::size_t len, std::size_t* bytes_sent) + { + return pgm_send (this->native_type_, buf, len, bytes_sent); + } + + /// Receive some data from the peer. + int receive (void* buf, std::size_t len, int flags, std::size_t* bytes_read, cpgm::pgm_error_t** error) + { + return pgm_recv (this->native_type_, buf, len, flags, bytes_read, error); + } + + /// Receive a datagram with the endpoint of the sender. + int receive_from (void* buf, std::size_t len, int flags, std::size_t* bytes_read, endpoint_type* from, cpgm::pgm_error_t** error) + { + int ec; + struct cpgm::pgm_sockaddr_t addr; + socklen_t addrlen = sizeof (addr); + ec = pgm_recvfrom (this->native_type_, buf, len, flags, bytes_read, &addr, &addrlen, error); + from->port (addr.sa_port); + from->address (addr.sa_addr); +/* TODO: set data-destination port */ + return ec; + } + +private: + native_type native_type_; +}; + +#endif /* __PGM_SOCKET_HH__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/signal.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/signal.h new file mode 100644 index 0000000..546fb7e --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/signal.h @@ -0,0 +1,36 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Re-entrant safe signal handling. + * + * Copyright (c) 2006-2007 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_SIGNAL_H__ +#define __PGM_SIGNAL_H__ + +#include +#include + +typedef void (*pgm_sighandler_t)(int, gpointer); + +G_BEGIN_DECLS + +gboolean pgm_signal_install (int, pgm_sighandler_t, gpointer); + +G_END_DECLS + +#endif /* __PGM_SIGNAL_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/skbuff.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/skbuff.h new file mode 100644 index 0000000..06f1264 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/skbuff.h @@ -0,0 +1,258 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM socket buffers + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_SKBUFF_H__ +#define __PGM_SKBUFF_H__ + +#include + +struct pgm_sk_buff_t; + +#include +#include +#include +#include +#include +#include +#include +#include + +PGM_BEGIN_DECLS + +struct pgm_sk_buff_t { + pgm_list_t link_; + + pgm_sock_t* restrict sock; + pgm_time_t tstamp; + pgm_tsi_t tsi; + + uint32_t sequence; + uint32_t __padding; /* push alignment of pgm_sk_buff_t::cb to 8 bytes */ + + char cb[48]; /* control buffer */ + + uint16_t len; /* actual data */ + unsigned zero_padded:1; + + struct pgm_header* pgm_header; + struct pgm_opt_fragment* pgm_opt_fragment; +#define of_apdu_first_sqn pgm_opt_fragment->opt_sqn +#define of_frag_offset pgm_opt_fragment->opt_frag_off +#define of_apdu_len pgm_opt_fragment->opt_frag_len + struct pgm_opt_pgmcc_data* pgm_opt_pgmcc_data; + struct pgm_data* pgm_data; + + void *head, /* all may-alias */ + *data, + *tail, + *end; + uint32_t truesize; + volatile uint32_t users; /* atomic */ +}; + +void pgm_skb_over_panic (const struct pgm_sk_buff_t*const, const uint16_t) PGM_GNUC_NORETURN; +void pgm_skb_under_panic (const struct pgm_sk_buff_t*const, const uint16_t) PGM_GNUC_NORETURN; +bool pgm_skb_is_valid (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; + +/* attribute __pure__ only valid for platforms with atomic ops. + * attribute __malloc__ not used as only part of the memory should be aliased. + * attribute __alloc_size__ does not allow headroom. + */ +static inline struct pgm_sk_buff_t* pgm_alloc_skb (const uint16_t) PGM_GNUC_WARN_UNUSED_RESULT; + +static inline +struct pgm_sk_buff_t* +pgm_alloc_skb ( + const uint16_t size + ) +{ + struct pgm_sk_buff_t* skb; + + skb = (struct pgm_sk_buff_t*)pgm_malloc (size + sizeof(struct pgm_sk_buff_t)); +/* Requires fast FSB to test + pgm_prefetchw (skb); + */ + if (PGM_UNLIKELY(pgm_mem_gc_friendly)) { + memset (skb, 0, size + sizeof(struct pgm_sk_buff_t)); + skb->zero_padded = 1; + } else { + memset (skb, 0, sizeof(struct pgm_sk_buff_t)); + } + skb->truesize = size + sizeof(struct pgm_sk_buff_t); + pgm_atomic_write32 (&skb->users, 1); + skb->head = skb + 1; + skb->data = skb->tail = skb->head; + skb->end = (char*)skb->data + size; + return skb; +} + +/* increase reference count */ +static inline +struct pgm_sk_buff_t* +pgm_skb_get ( + struct pgm_sk_buff_t*const skb + ) +{ + pgm_atomic_inc32 (&skb->users); + return skb; +} + +static inline +void +pgm_free_skb ( + struct pgm_sk_buff_t*const skb + ) +{ + if (pgm_atomic_exchange_and_add32 (&skb->users, (uint32_t)-1) == 1) + pgm_free (skb); +} + +/* add data */ +static inline +void* +pgm_skb_put ( + struct pgm_sk_buff_t* const skb, + const uint16_t len + ) +{ + void* tmp = skb->tail; + skb->tail = (char*)skb->tail + len; + skb->len += len; + if (PGM_UNLIKELY(skb->tail > skb->end)) + pgm_skb_over_panic (skb, len); + return tmp; +} + +static inline +void* +__pgm_skb_pull ( + struct pgm_sk_buff_t*const skb, + const uint16_t len + ) +{ + skb->len -= len; + return skb->data = (char*)skb->data + len; +} + +/* remove data from start of buffer */ +static inline +void* +pgm_skb_pull ( + struct pgm_sk_buff_t*const skb, + const uint16_t len + ) +{ + return PGM_UNLIKELY(len > skb->len) ? NULL : __pgm_skb_pull (skb, len); +} + +static inline uint16_t pgm_skb_headroom (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; +static inline uint16_t pgm_skb_tailroom (const struct pgm_sk_buff_t*const) PGM_GNUC_PURE PGM_GNUC_WARN_UNUSED_RESULT; + +static inline +uint16_t +pgm_skb_headroom ( + const struct pgm_sk_buff_t*const skb + ) +{ + return (char*)skb->data - (char*)skb->head; +} + +static inline +uint16_t +pgm_skb_tailroom ( + const struct pgm_sk_buff_t*const skb + ) +{ + return (char*)skb->end - (char*)skb->tail; +} + +/* reserve space to add data */ +static inline +void +pgm_skb_reserve ( + struct pgm_sk_buff_t*const skb, + const uint16_t len + ) +{ + skb->data = (char*)skb->data + len; + skb->tail = (char*)skb->tail + len; + if (PGM_UNLIKELY(skb->tail > skb->end)) + pgm_skb_over_panic (skb, len); + if (PGM_UNLIKELY(skb->data < skb->head)) + pgm_skb_under_panic (skb, len); +} + +static inline struct pgm_sk_buff_t* pgm_skb_copy (const struct pgm_sk_buff_t* const) PGM_GNUC_WARN_UNUSED_RESULT; + +static inline +struct pgm_sk_buff_t* +pgm_skb_copy ( + const struct pgm_sk_buff_t* const skb + ) +{ + struct pgm_sk_buff_t* newskb; + newskb = (struct pgm_sk_buff_t*)pgm_malloc (skb->truesize); + memcpy (newskb, skb, PGM_OFFSETOF(struct pgm_sk_buff_t, pgm_header)); + newskb->zero_padded = 0; + newskb->truesize = skb->truesize; + pgm_atomic_write32 (&newskb->users, 1); + newskb->head = newskb + 1; + newskb->end = (char*)newskb->head + ((char*)skb->end - (char*)skb->head); + newskb->data = (char*)newskb->head + ((char*)skb->data - (char*)skb->head); + newskb->tail = (char*)newskb->head + ((char*)skb->tail - (char*)skb->head); + newskb->pgm_header = skb->pgm_header ? (struct pgm_header*)((char*)newskb->head + ((char*)skb->pgm_header - (char*)skb->head)) : skb->pgm_header; + newskb->pgm_opt_fragment = skb->pgm_opt_fragment ? (struct pgm_opt_fragment*)((char*)newskb->head + ((char*)skb->pgm_opt_fragment - (char*)skb->head)) : skb->pgm_opt_fragment; + newskb->pgm_data = skb->pgm_data ? (struct pgm_data*)((char*)newskb->head + ((char*)skb->pgm_data - (char*)skb->head)) : skb->pgm_data; + memcpy (newskb->head, skb->head, (char*)skb->end - (char*)skb->head); + return newskb; +} + +static inline +void +pgm_skb_zero_pad ( + struct pgm_sk_buff_t* const skb, + const uint16_t len + ) +{ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +/* C99 version */ + if (skb->zero_padded) + return; + + const uint16_t tailroom = MIN(pgm_skb_tailroom (skb), len); + if (tailroom > 0) + memset (skb->tail, 0, tailroom); + skb->zero_padded = 1; +#else +/* C89 version */ + const uint16_t tailroom = MIN(pgm_skb_tailroom (skb), len); + if (skb->zero_padded) + return; + + if (tailroom > 0) + memset (skb->tail, 0, tailroom); + skb->zero_padded = 1; +#endif +} + +PGM_END_DECLS + +#endif /* __PGM_SKBUFF_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/snmp.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/snmp.h new file mode 100644 index 0000000..922f4e2 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/snmp.h @@ -0,0 +1,35 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * SNMP + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_SNMP_H__ +#define __PGM_SNMP_H__ + +#include +#include + +PGM_BEGIN_DECLS + +bool pgm_snmp_init (pgm_error_t**) PGM_GNUC_WARN_UNUSED_RESULT; +bool pgm_snmp_shutdown (void); + +PGM_END_DECLS + +#endif /* __PGM_SNMP_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/socket.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/socket.h new file mode 100644 index 0000000..1e32af7 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/socket.h @@ -0,0 +1,172 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * PGM socket. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_SOCKET_H__ +#define __PGM_SOCKET_H__ + +typedef struct pgm_sock_t pgm_sock_t; +struct pgm_sockaddr_t; +struct pgm_addrinfo_t; +struct pgm_fecinto_t; + +#ifdef CONFIG_HAVE_POLL +# include +#endif +#ifdef CONFIG_HAVE_EPOLL +# include +#endif +#ifndef _WIN32 +# include +# include +#endif +#include +#include +#include +#include + +PGM_BEGIN_DECLS + +struct pgm_sockaddr_t { + uint16_t sa_port; /* data-destination port */ + pgm_tsi_t sa_addr; +}; + +struct pgm_addrinfo_t { + sa_family_t ai_family; + uint32_t ai_recv_addrs_len; + struct group_source_req* restrict ai_recv_addrs; + uint32_t ai_send_addrs_len; + struct group_source_req* restrict ai_send_addrs; +}; + +struct pgm_interface_req_t { + uint32_t ir_interface; + uint32_t ir_scope_id; +}; + +struct pgm_fecinfo_t { + uint8_t block_size; + uint8_t proactive_packets; + uint8_t group_size; + bool ondemand_parity_enabled; + bool var_pktlen_enabled; +}; + +struct pgm_pgmccinfo_t { + uint32_t ack_bo_ivl; + uint32_t ack_c; + uint32_t ack_c_p; +}; + +/* socket options */ +enum { + PGM_SEND_SOCK = 0x2000, + PGM_RECV_SOCK, + PGM_REPAIR_SOCK, + PGM_PENDING_SOCK, + PGM_ACK_SOCK, + PGM_TIME_REMAIN, + PGM_RATE_REMAIN, + PGM_IP_ROUTER_ALERT, + PGM_MTU, + PGM_MSSS, + PGM_MSS, + PGM_PDU, + PGM_MULTICAST_LOOP, + PGM_MULTICAST_HOPS, + PGM_TOS, + PGM_AMBIENT_SPM, + PGM_HEARTBEAT_SPM, + PGM_TXW_SQNS, + PGM_TXW_SECS, + PGM_TXW_MAX_RTE, + PGM_PEER_EXPIRY, + PGM_SPMR_EXPIRY, + PGM_RXW_SQNS, + PGM_RXW_SECS, + PGM_RXW_MAX_RTE, + PGM_NAK_BO_IVL, + PGM_NAK_RPT_IVL, + PGM_NAK_RDATA_IVL, + PGM_NAK_DATA_RETRIES, + PGM_NAK_NCF_RETRIES, + PGM_USE_FEC, + PGM_USE_CR, + PGM_USE_PGMCC, + PGM_SEND_ONLY, + PGM_RECV_ONLY, + PGM_PASSIVE, + PGM_ABORT_ON_RESET, + PGM_NOBLOCK, + PGM_SEND_GROUP, + PGM_JOIN_GROUP, + PGM_LEAVE_GROUP, + PGM_BLOCK_SOURCE, + PGM_UNBLOCK_SOURCE, + PGM_JOIN_SOURCE_GROUP, + PGM_LEAVE_SOURCE_GROUP, + PGM_MSFILTER, + PGM_UDP_ENCAP_UCAST_PORT, + PGM_UDP_ENCAP_MCAST_PORT +}; + +/* IO status */ +enum { + PGM_IO_STATUS_ERROR, /* an error occurred */ + PGM_IO_STATUS_NORMAL, /* success */ + PGM_IO_STATUS_RESET, /* session reset */ + PGM_IO_STATUS_FIN, /* session finished */ + PGM_IO_STATUS_EOF, /* socket closed */ + PGM_IO_STATUS_WOULD_BLOCK, /* resource temporarily unavailable */ + PGM_IO_STATUS_RATE_LIMITED, /* would-block on rate limit, check timer */ + PGM_IO_STATUS_TIMER_PENDING, /* would-block with pending timer */ + PGM_IO_STATUS_CONGESTION /* would-block waiting on ACK or timeout */ +}; + +bool pgm_socket (pgm_sock_t**restrict, const sa_family_t, const int, const int, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; +bool pgm_bind (pgm_sock_t*restrict, const struct pgm_sockaddr_t*const restrict, const socklen_t, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; +bool pgm_bind3 (pgm_sock_t*restrict, const struct pgm_sockaddr_t*const restrict, const socklen_t, const struct pgm_interface_req_t*const, const socklen_t, const struct pgm_interface_req_t*const, const socklen_t, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; +bool pgm_connect (pgm_sock_t*restrict, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; +bool pgm_close (pgm_sock_t*, bool); +bool pgm_setsockopt (pgm_sock_t*const restrict, const int, const int, const void*restrict, const socklen_t); +bool pgm_getsockopt (pgm_sock_t*const restrict, const int, const int, void*restrict, socklen_t*restrict); +bool pgm_getaddrinfo (const char*restrict, const struct pgm_addrinfo_t*const restrict, struct pgm_addrinfo_t**restrict, pgm_error_t**restrict); +void pgm_freeaddrinfo (struct pgm_addrinfo_t*); +int pgm_send (pgm_sock_t*const restrict, const void*restrict, const size_t, size_t*restrict); +int pgm_sendv (pgm_sock_t*const restrict, const struct pgm_iovec*const restrict, const unsigned, const bool, size_t*restrict); +int pgm_send_skbv (pgm_sock_t*const restrict, struct pgm_sk_buff_t**const restrict, const unsigned, const bool, size_t*restrict); +int pgm_recvmsg (pgm_sock_t*const restrict, struct pgm_msgv_t*const restrict, const int, size_t*restrict, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; +int pgm_recvmsgv (pgm_sock_t*const restrict, struct pgm_msgv_t*const restrict, const size_t, const int, size_t*restrict, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; +int pgm_recv (pgm_sock_t*const restrict, void*restrict, const size_t, const int, size_t*const restrict, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; +int pgm_recvfrom (pgm_sock_t*const restrict, void*restrict, const size_t, const int, size_t*restrict, struct pgm_sockaddr_t*restrict, socklen_t*restrict, pgm_error_t**restrict) PGM_GNUC_WARN_UNUSED_RESULT; + +bool pgm_getsockname (pgm_sock_t*const restrict, struct pgm_sockaddr_t*restrict, socklen_t*restrict); +int pgm_select_info (pgm_sock_t*const restrict, fd_set*const restrict, fd_set*const restrict, int*const restrict); +#ifdef CONFIG_HAVE_POLL +int pgm_poll_info (pgm_sock_t*const restrict, struct pollfd*const restrict, int*const restrict, const int); +#endif +#ifdef CONFIG_HAVE_EPOLL +int pgm_epoll_ctl (pgm_sock_t*const, const int, const int, const int); +#endif + +PGM_END_DECLS + +#endif /* __PGM_SOCKET_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/time.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/time.h new file mode 100644 index 0000000..2fd3898 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/time.h @@ -0,0 +1,54 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * high resolution timers. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_TIME_H__ +#define __PGM_TIME_H__ + +#include + +PGM_BEGIN_DECLS + +typedef uint64_t pgm_time_t; +typedef void (*pgm_time_since_epoch_func)(const pgm_time_t*const restrict, time_t*restrict); + +#define pgm_to_secs(t) ((uint64_t)( (t) / 1000000UL )) +#define pgm_to_msecs(t) ((uint64_t)( (t) / 1000UL )) +#define pgm_to_usecs(t) ( (t) ) +#define pgm_to_nsecs(t) ((uint64_t)( (t) * 1000UL )) + +#define pgm_to_secsf(t) ( (double)(t) / 1000000.0 ) +#define pgm_to_msecsf(t) ( (double)(t) / 1000.0 ) +#define pgm_to_usecsf(t) ( (double)(t) ) +#define pgm_to_nsecsf(t) ( (double)(t) * 1000.0 ) + +#define pgm_secs(t) ((uint64_t)( (uint64_t)(t) * 1000000UL )) +#define pgm_msecs(t) ((uint64_t)( (uint64_t)(t) * 1000UL )) +#define pgm_usecs(t) ((uint64_t)( (t) )) +#define pgm_nsecs(t) ((uint64_t)( (t) / 1000UL )) + +#define PGM_TIME_FORMAT PRIu64 + +extern pgm_time_since_epoch_func pgm_time_since_epoch; + +PGM_END_DECLS + +#endif /* __PGM_TIME_H__ */ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/tsi.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/tsi.h new file mode 100644 index 0000000..d99f090 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/tsi.h @@ -0,0 +1,49 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * transport session ID helper functions + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_TSI_H__ +#define __PGM_TSI_H__ + +typedef struct pgm_tsi_t pgm_tsi_t; + +#include +#include + +PGM_BEGIN_DECLS + +/* maximum length of TSI as a string */ +#define PGM_TSISTRLEN (sizeof("000.000.000.000.000.000.00000")) +#define PGM_TSI_INIT { PGM_GSI_INIT, 0 } + +struct pgm_tsi_t { + pgm_gsi_t gsi; /* global session identifier */ + uint16_t sport; /* source port: a random number to help detect session re-starts */ +}; + +PGM_STATIC_ASSERT(sizeof(struct pgm_tsi_t) == 8); + +char* pgm_tsi_print (const pgm_tsi_t*) PGM_GNUC_WARN_UNUSED_RESULT; +int pgm_tsi_print_r (const pgm_tsi_t*restrict, char*restrict, size_t); +bool pgm_tsi_equal (const void*restrict, const void*restrict) PGM_GNUC_WARN_UNUSED_RESULT; + +PGM_END_DECLS + +#endif /* __PGM_TSI_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/types.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/types.h new file mode 100644 index 0000000..e8b2d82 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/types.h @@ -0,0 +1,66 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Cross-platform data types. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_TYPES_H__ +#define __PGM_TYPES_H__ + +#ifndef _MSC_VER +# include +#endif +#include + +#ifdef _WIN32 +# include +# include +# ifdef _MSC_VER +# define sa_family_t ADDRESS_FAMILY +# else +# define sa_family_t USHORT +# endif +#endif + +#ifdef _MSC_VER +# include +# define bool BOOL +# define ssize_t SSIZE_T +# define inline __inline +#elif !defined(__cplusplus) || (__GNUC__ >= 4) +/* g++ v4 handles C99 headers without complaints */ +# include +# include +#else +/* g++ v3 and other ancient compilers */ +# define bool int +# include +#endif + +#if !defined(restrict) || (__STDC_VERSION__ < 199901L) +/* C89 ANSI standard */ +# define restrict +#endif + +PGM_BEGIN_DECLS + +/* nc */ + +PGM_END_DECLS + +#endif /* __PGM_TYPES_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/version.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/version.h new file mode 100644 index 0000000..7928450 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/version.h @@ -0,0 +1,41 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * OpenPGM version. + * + * Copyright (c) 2006-2008 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_VERSION_H__ +#define __PGM_VERSION_H__ + +#include + +PGM_BEGIN_DECLS + +extern const unsigned pgm_major_version; +extern const unsigned pgm_minor_version; +extern const unsigned pgm_micro_version; + +extern const char* pgm_build_date; +extern const char* pgm_build_time; +extern const char* pgm_build_system; +extern const char* pgm_build_machine; +extern const char* pgm_build_revision; + +PGM_END_DECLS + +#endif /* __PGM_VERSION_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/winint.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/winint.h new file mode 100644 index 0000000..0205cdf --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/winint.h @@ -0,0 +1,198 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * stdint.h for Win32 & Win64 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_WININT_H__ +#define __PGM_WININT_H__ + +#include + +/* 7.18.1.1 Exact-width integer types */ +typedef signed __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef signed __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef signed __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + +/* 7.18.1.2 Minimum-width integer types */ +typedef int8_t int_least8_t; +typedef uint8_t uint_least8_t; +typedef int16_t int_least16_t; +typedef uint16_t uint_least16_t; +typedef int32_t int_least32_t; +typedef uint32_t uint_least32_t; +typedef int64_t int_least64_t; +typedef uint64_t uint_least64_t; + +/* 7.18.1.3 Fastest minimum-width integer types + * Not actually guaranteed to be fastest for all purposes + * Here we use the exact-width types for 8 and 16-bit ints. + */ +typedef int8_t int_fast8_t; +typedef uint8_t uint_fast8_t; +typedef int16_t int_fast16_t; +typedef uint16_t uint_fast16_t; +typedef int32_t int_fast32_t; +typedef uint32_t uint_fast32_t; +typedef int64_t int_fast64_t; +typedef uint64_t uint_fast64_t; + +/* 7.18.1.5 Greatest-width integer types */ +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + +/* 7.18.2 Limits of specified-width integer types */ +#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) + +/* 7.18.2.1 Limits of exact-width integer types */ +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +/* 7.18.2.2 Limits of minimum-width integer types */ +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN + +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +/* 7.18.2.3 Limits of fastest minimum-width integer types */ +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST64_MIN INT64_MIN + +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +/* 7.18.2.4 Limits of integer types capable of holding + object pointers */ +#ifdef _WIN64 +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif + +/* 7.18.2.5 Limits of greatest-width integer types */ +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +/* 7.18.3 Limits of other integer types */ +#ifdef _WIN64 +# define PTRDIFF_MIN INT64_MIN +# define PTRDIFF_MAX INT64_MAX +#else +# define PTRDIFF_MIN INT32_MIN +# define PTRDIFF_MAX INT32_MAX +#endif + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX +# ifdef _WIN64 +# define SIZE_MAX UINT64_MAX +# else +# define SIZE_MAX UINT32_MAX +# endif +#endif + +#ifndef WCHAR_MIN /* also in wchar.h */ +# define WCHAR_MIN 0U +# define WCHAR_MAX UINT16_MAX +#endif + +/* + * wint_t is unsigned short for compatibility with MS runtime + */ +#define WINT_MIN 0U +#define WINT_MAX UINT16_MAX + +#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ + + +/* 7.18.4 Macros for integer constants */ +#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) + +/* 7.18.4.1 Macros for minimum-width integer constants + + Accoding to Douglas Gwyn : + "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC + 9899:1999 as initially published, the expansion was required + to be an integer constant of precisely matching type, which + is impossible to accomplish for the shorter types on most + platforms, because C99 provides no standard way to designate + an integer constant with width less than that of type int. + TC1 changed this to require just an integer constant + *expression* with *promoted* type." + + The trick used here is from Clive D W Feather. +*/ + +#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val)) +#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val)) +#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val)) +/* The 'trick' doesn't work in C89 for long long because, without + suffix, (val) will be evaluated as int, not intmax_t */ +#define INT64_C(val) val##LL + +#define UINT8_C(val) (val) +#define UINT16_C(val) (val) +#define UINT32_C(val) (val##U) +#define UINT64_C(val) val##ULL + +/* 7.18.4.2 Macros for greatest-width integer constants */ +#define INTMAX_C(val) val##LL +#define UINTMAX_C(val) val##ULL + +#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ + +#endif /* __PGM_WININT_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/include/pgm/wininttypes.h b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/wininttypes.h new file mode 100644 index 0000000..5daa7f1 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/include/pgm/wininttypes.h @@ -0,0 +1,254 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * inttypes.h for Win32 & Win64 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_WININTTYPES_H__ +#define __PGM_WININTTYPES_H__ + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) + +/* 7.8.1 Macros for format specifiers + * + * MS runtime does not yet understand C9x standard "ll" + * length specifier. It appears to treat "ll" as "l". + * The non-standard I64 length specifier causes warning in GCC, + * but understood by MS runtime functions. + */ + +/* fprintf macros for signed types */ +#define PRId8 "d" +#define PRId16 "hd" +#define PRId32 "I32d" +#define PRId64 "I64d" + +#define PRIdLEAST8 "d" +#define PRIdLEAST16 "hd" +#define PRIdLEAST32 "I32d" +#define PRIdLEAST64 "I64d" + +#define PRIdFAST8 "d" +#define PRIdFAST16 "hd" +#define PRIdFAST32 "I32d" +#define PRIdFAST64 "I64d" + +#define PRIdMAX "I64d" + +#define PRIi8 "i" +#define PRIi16 "hi" +#define PRIi32 "i" +#define PRIi64 "I64i" + +#define PRIiLEAST8 "i" +#define PRIiLEAST16 "hi" +#define PRIiLEAST32 "I32i" +#define PRIiLEAST64 "I64i" + +#define PRIiFAST8 "i" +#define PRIiFAST16 "hi" +#define PRIiFAST32 "I32i" +#define PRIiFAST64 "I64i" + +#define PRIiMAX "I64i" + +#define PRIo8 "o" +#define PRIo16 "ho" +#define PRIo32 "I32o" +#define PRIo64 "I64o" + +#define PRIoLEAST8 "o" +#define PRIoLEAST16 "ho" +#define PRIoLEAST32 "I32o" +#define PRIoLEAST64 "I64o" + +#define PRIoFAST8 "o" +#define PRIoFAST16 "ho" +#define PRIoFAST32 "o" +#define PRIoFAST64 "I64o" + +#define PRIoMAX "I64o" + +/* fprintf macros for unsigned types */ +#define PRIu8 "u" +#define PRIu16 "hu" +#define PRIu32 "I32u" +#define PRIu64 "I64u" + +#define PRIuLEAST8 "u" +#define PRIuLEAST16 "hu" +#define PRIuLEAST32 "I32u" +#define PRIuLEAST64 "I64u" + +#define PRIuFAST8 "u" +#define PRIuFAST16 "hu" +#define PRIuFAST32 "I32u" +#define PRIuFAST64 "I64u" + +#define PRIuMAX "I64u" + +#define PRIx8 "x" +#define PRIx16 "hx" +#define PRIx32 "I32x" +#define PRIx64 "I64x" + +#define PRIxLEAST8 "x" +#define PRIxLEAST16 "hx" +#define PRIxLEAST32 "I32x" +#define PRIxLEAST64 "I64x" + +#define PRIxFAST8 "x" +#define PRIxFAST16 "hx" +#define PRIxFAST32 "I32x" +#define PRIxFAST64 "I64x" + +#define PRIxMAX "I64x" + +#define PRIX8 "X" +#define PRIX16 "hX" +#define PRIX32 "I32X" +#define PRIX64 "I64X" + +#define PRIXLEAST8 "X" +#define PRIXLEAST16 "hX" +#define PRIXLEAST32 "I32X" +#define PRIXLEAST64 "I64X" + +#define PRIXFAST8 "X" +#define PRIXFAST16 "hX" +#define PRIXFAST32 "I32X" +#define PRIXFAST64 "I64X" + +#define PRIXMAX "I64X" + +/* fscanf macros for signed int types */ + +#define SCNd8 "hhd" +#define SCNd16 "hd" +#define SCNd32 "ld" +#define SCNd64 "I64d" + +#define SCNdLEAST8 "hhd" +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "ld" +#define SCNdLEAST64 "I64d" + +#define SCNdFAST8 "hhd" +#define SCNdFAST16 "hd" +#define SCNdFAST32 "ld" +#define SCNdFAST64 "I64d" + +#define SCNdMAX "I64d" + +#define SCNi8 "hhi" +#define SCNi16 "hi" +#define SCNi32 "li" +#define SCNi64 "I64i" + +#define SCNiLEAST8 "hhi" +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "li" +#define SCNiLEAST64 "I64i" + +#define SCNiFAST8 "hhi" +#define SCNiFAST16 "hi" +#define SCNiFAST32 "li" +#define SCNiFAST64 "I64i" + +#define SCNiMAX "I64i" + +#define SCNo8 "hho" +#define SCNo16 "ho" +#define SCNo32 "lo" +#define SCNo64 "I64o" + +#define SCNoLEAST8 "hho" +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "lo" +#define SCNoLEAST64 "I64o" + +#define SCNoFAST8 "hho" +#define SCNoFAST16 "ho" +#define SCNoFAST32 "lo" +#define SCNoFAST64 "I64o" + +#define SCNoMAX "I64o" + +#define SCNx8 "hhx" +#define SCNx16 "hx" +#define SCNx32 "lx" +#define SCNx64 "I64x" + +#define SCNxLEAST8 "hhx" +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "lx" +#define SCNxLEAST64 "I64x" + +#define SCNxFAST8 "hhx" +#define SCNxFAST16 "hx" +#define SCNxFAST32 "lx" +#define SCNxFAST64 "I64x" + +#define SCNxMAX "I64x" + +/* fscanf macros for unsigned int types */ + +#define SCNu8 "hhu" +#define SCNu16 "hu" +#define SCNu32 "lu" +#define SCNu64 "I64u" + +#define SCNuLEAST8 "hhu" +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "lu" +#define SCNuLEAST64 "I64u" + +#define SCNuFAST8 "hhu" +#define SCNuFAST16 "hu" +#define SCNuFAST32 "lu" +#define SCNuFAST64 "I64u" + +#define SCNuMAX "I64u" + +#ifdef _WIN64 +# define PRIdPTR "I64d" +# define PRIiPTR "I64i" +# define PRIoPTR "I64o" +# define PRIuPTR "I64u" +# define PRIxPTR "I64x" +# define PRIXPTR "I64X" +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +# define SCNoPTR "I64o" +# define SCNxPTR "I64x" +# define SCNuPTR "I64u" +#else +# define PRIdPTR "ld" +# define PRIiPTR "li" +# define PRIoPTR "lo" +# define PRIuPTR "lu" +# define PRIxPTR "lx" +# define PRIXPTR "lX" +# define SCNdPTR "ld" +# define SCNiPTR "li" +# define SCNoPTR "lo" +# define SCNxPTR "lx" +# define SCNuPTR "lu" +#endif + +#endif /* !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) */ + +#endif /* __PGM_WININTTYPES_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/indextoaddr.c b/3rdparty/openpgm-svn-r1135/pgm/indextoaddr.c new file mode 100644 index 0000000..479dffd --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/indextoaddr.c @@ -0,0 +1,98 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable interface index to socket address function. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + + +//#define INDEXTOADDR_DEBUG + + +/* interfaces indexes refer to the link layer, we want to find the internet layer address. + * the big problem is that multiple IPv6 addresses can be bound to one link - called scopes. + * we can just pick the first scope and let IP routing handle the rest. + */ + +bool +pgm_if_indextoaddr ( + const unsigned ifindex, + const sa_family_t iffamily, + const uint32_t ifscope, + struct sockaddr* restrict ifsa, + pgm_error_t** restrict error + ) +{ + pgm_return_val_if_fail (NULL != ifsa, FALSE); + + if (0 == ifindex) /* any interface or address */ + { + ifsa->sa_family = iffamily; + switch (iffamily) { + case AF_INET: + ((struct sockaddr_in*)ifsa)->sin_addr.s_addr = INADDR_ANY; + break; + + case AF_INET6: + ((struct sockaddr_in6*)ifsa)->sin6_addr = in6addr_any; + break; + + default: + pgm_return_val_if_reached (FALSE); + break; + } + return TRUE; + } + + struct pgm_ifaddrs_t *ifap, *ifa; + if (!pgm_getifaddrs (&ifap, error)) { + pgm_prefix_error (error, + _("Enumerating network interfaces: ")); + return FALSE; + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) + { + if (NULL == ifa->ifa_addr || + ifa->ifa_addr->sa_family != iffamily) + continue; + + const unsigned i = pgm_if_nametoindex (iffamily, ifa->ifa_name); + pgm_assert (0 != i); + if (i == ifindex) + { + if (ifscope && ifscope != pgm_sockaddr_scope_id (ifa->ifa_addr)) + continue; + memcpy (ifsa, ifa->ifa_addr, pgm_sockaddr_len(ifa->ifa_addr)); + pgm_freeifaddrs (ifap); + return TRUE; + } + } + + pgm_set_error (error, + PGM_ERROR_DOMAIN_IF, + PGM_ERROR_NODEV, + _("No matching network interface index: %i"), + ifindex); + pgm_freeifaddrs (ifap); + return FALSE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/indextoaddr.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/indextoaddr.c.c89.patch new file mode 100644 index 0000000..4965077 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/indextoaddr.c.c89.patch @@ -0,0 +1,44 @@ +--- indextoaddr.c 2010-05-21 11:34:27.000000000 +0800 ++++ indextoaddr.c89 2010-08-04 12:06:20.000000000 +0800 +@@ -44,7 +44,9 @@ + + if (0 == ifindex) /* any interface or address */ + { ++#pragma warning( disable : 4244 ) + ifsa->sa_family = iffamily; ++#pragma warning( default : 4244 ) + switch (iffamily) { + case AF_INET: + ((struct sockaddr_in*)ifsa)->sin_addr.s_addr = INADDR_ANY; +@@ -61,6 +63,7 @@ + return TRUE; + } + ++ { + struct pgm_ifaddrs_t *ifap, *ifa; + if (!pgm_getifaddrs (&ifap, error)) { + pgm_prefix_error (error, +@@ -74,6 +77,7 @@ + ifa->ifa_addr->sa_family != iffamily) + continue; + ++ { + const unsigned i = pgm_if_nametoindex (iffamily, ifa->ifa_name); + pgm_assert (0 != i); + if (i == ifindex) +@@ -84,6 +88,7 @@ + pgm_freeifaddrs (ifap); + return TRUE; + } ++ } + } + + pgm_set_error (error, +@@ -93,6 +98,7 @@ + ifindex); + pgm_freeifaddrs (ifap); + return FALSE; ++ } + } + + /* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/indextoaddr_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/indextoaddr_unittest.c new file mode 100644 index 0000000..7699f9c --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/indextoaddr_unittest.c @@ -0,0 +1,302 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for portable interface index to socket address function. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* IFF_UP */ +#define _BSD_SOURCE 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* mock state */ + +struct mock_interface_t { + unsigned int index; + char* name; + unsigned int flags; + struct sockaddr_storage addr; + struct sockaddr_storage netmask; +}; + +static GList *mock_interfaces = NULL; + +struct pgm_ifaddrs_t; +struct pgm_error_t; + +static bool mock_pgm_getifaddrs (struct pgm_ifaddrs_t**, struct pgm_error_t**); +static void mock_pgm_freeifaddrs (struct pgm_ifaddrs_t*); +static unsigned mock_pgm_if_nametoindex (const sa_family_t, const char*); + + +#define pgm_getifaddrs mock_pgm_getifaddrs +#define pgm_freeifaddrs mock_pgm_freeifaddrs +#define pgm_if_nametoindex mock_pgm_if_nametoindex + + +#define INDEXTOADDR_DEBUG +#include "indextoaddr.c" + + +static +gpointer +create_interface ( + const unsigned index, + const char* name, + const char* flags + ) +{ + struct mock_interface_t* new_interface; + + g_assert (name); + g_assert (flags); + + new_interface = g_slice_alloc0 (sizeof(struct mock_interface_t)); + new_interface->index = index; + new_interface->name = g_strdup (name); + + struct sockaddr_in* sin = (gpointer)&new_interface->addr; + struct sockaddr_in6* sin6 = (gpointer)&new_interface->addr; + + gchar** tokens = g_strsplit (flags, ",", 0); + for (guint i = 0; tokens[i]; i++) + { + if (strcmp (tokens[i], "up") == 0) + new_interface->flags |= IFF_UP; + else if (strcmp (tokens[i], "down") == 0) + new_interface->flags |= 0; + else if (strcmp (tokens[i], "loop") == 0) + new_interface->flags |= IFF_LOOPBACK; + else if (strcmp (tokens[i], "broadcast") == 0) + new_interface->flags |= IFF_BROADCAST; + else if (strcmp (tokens[i], "multicast") == 0) + new_interface->flags |= IFF_MULTICAST; + else if (strncmp (tokens[i], "ip=", strlen("ip=")) == 0) { + const char* addr = tokens[i] + strlen("ip="); + g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->addr)); + } + else if (strncmp (tokens[i], "netmask=", strlen("netmask=")) == 0) { + const char* addr = tokens[i] + strlen("netmask="); + g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->netmask)); + } + else if (strncmp (tokens[i], "scope=", strlen("scope=")) == 0) { + const char* scope = tokens[i] + strlen("scope="); + g_assert (AF_INET6 == ((struct sockaddr*)&new_interface->addr)->sa_family); + ((struct sockaddr_in6*)&new_interface->addr)->sin6_scope_id = atoi (scope); + } + else + g_error ("parsing failed for flag \"%s\"", tokens[i]); + } + + g_strfreev (tokens); + return new_interface; +} + +#define APPEND_INTERFACE(a,b,c) \ + do { \ + gpointer data = create_interface ((a), (b), (c)); \ + g_assert (data); \ + mock_interfaces = g_list_append (mock_interfaces, data); \ + g_assert (mock_interfaces); g_assert (mock_interfaces->data); \ + } while (0) +static +void +mock_setup_net (void) +{ + APPEND_INTERFACE( 1, "lo", "up,loop"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast"); + APPEND_INTERFACE( 3, "eth1", "down,broadcast,multicast"); + APPEND_INTERFACE( 1, "lo", "up,loop,ip=127.0.0.1,netmask=255.0.0.0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=10.6.28.33,netmask=255.255.255.0"); + APPEND_INTERFACE( 1, "lo", "up,loop,ip=::1,netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,scope=0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=2002:dce8:d28e::33,netmask=ffff:ffff:ffff:ffff::0,scope=0"); + APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=fe80::214:5eff:febd:6dda,netmask=ffff:ffff:ffff:ffff::0,scope=2"); +} + +static +void +mock_teardown_net (void) +{ + GList* list; + + list = mock_interfaces; + while (list) { + struct mock_interface_t* interface = list->data; + g_free (interface->name); + g_slice_free1 (sizeof(struct mock_interface_t), interface); + list = list->next; + } + g_list_free (mock_interfaces); +} + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + +bool +mock_pgm_getifaddrs ( + struct pgm_ifaddrs_t** ifap, + pgm_error_t** err + ) +{ + if (NULL == ifap) { + return FALSE; + } + + g_debug ("mock_getifaddrs (ifap:%p err:%p)", (gpointer)ifap, (gpointer)err); + + GList* list = mock_interfaces; + int n = g_list_length (list); + struct pgm_ifaddrs_t* ifa = calloc (n, sizeof(struct pgm_ifaddrs_t)); + struct pgm_ifaddrs_t* ift = ifa; + while (list) { + struct mock_interface_t* interface = list->data; + ift->ifa_addr = (gpointer)&interface->addr; + ift->ifa_name = interface->name; + ift->ifa_flags = interface->flags; + ift->ifa_netmask = (gpointer)&interface->netmask; + list = list->next; + if (list) { + ift->ifa_next = ift + 1; + ift = ift->ifa_next; + } + } + + *ifap = ifa; + return TRUE; +} + +static +void +mock_pgm_freeifaddrs ( + struct pgm_ifaddrs_t* ifa + ) +{ + g_debug ("mock_freeifaddrs (ifa:%p)", (gpointer)ifa); + free (ifa); +} + +unsigned +mock_pgm_if_nametoindex ( + const sa_family_t iffamily, + const char* ifname + ) +{ + GList* list = mock_interfaces; + while (list) { + const struct mock_interface_t* interface = list->data; + if (0 == strcmp (ifname, interface->name)) + return interface->index; + list = list->next; + } + return 0; +} + + +/* target: + * bool + * pgm_if_indextoaddr ( + * const unsigned ifindex, + * const sa_family_t iffamily, + * const uint32_t ifscope, + * struct sockaddr* ifsa, + * pgm_error_t** error + * ) + */ + +START_TEST (test_indextoaddr_pass_001) +{ + char saddr[INET6_ADDRSTRLEN]; + struct sockaddr_storage addr; + pgm_error_t* err = NULL; + const unsigned int ifindex = 2; + fail_unless (TRUE == pgm_if_indextoaddr (ifindex, AF_INET, 0, (struct sockaddr*)&addr, &err)); + pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); + g_message ("index:%d -> %s", + ifindex, saddr); + fail_unless (TRUE == pgm_if_indextoaddr (ifindex, AF_INET6, 0, (struct sockaddr*)&addr, &err)); + pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); + g_message ("index:%d -> %s", + ifindex, saddr); +} +END_TEST + +START_TEST (test_indextoaddr_fail_001) +{ + pgm_error_t* err = NULL; + fail_unless (FALSE == pgm_if_indextoaddr (0, 0, 0, NULL, &err)); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_indextoaddr = tcase_create ("init-ctx"); + suite_add_tcase (s, tc_indextoaddr); + tcase_add_checked_fixture (tc_indextoaddr, mock_setup_net, mock_teardown_net); + tcase_add_test (tc_indextoaddr, test_indextoaddr_pass_001); + tcase_add_test (tc_indextoaddr, test_indextoaddr_fail_001); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/indextoname.c b/3rdparty/openpgm-svn-r1135/pgm/indextoname.c new file mode 100644 index 0000000..c4043ef --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/indextoname.c @@ -0,0 +1,52 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Windows interface index to interface name function. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef _WIN32 +# include +# include +#endif +#include + + +//#define INDEXTONAME_DEBUG + + +char* +pgm_if_indextoname ( + unsigned int ifindex, + char* ifname + ) +{ +#ifndef _WIN32 + return if_indextoname (ifindex, ifname); +#else + pgm_return_val_if_fail (NULL != ifname, NULL); + + MIB_IFROW ifRow = { .dwIndex = ifindex }; + const DWORD dwRetval = GetIfEntry (&ifRow); + if (NO_ERROR != dwRetval) + return NULL; + strcpy (ifname, (char*)ifRow.wszName); + return ifname; +#endif /* _WIN32 */ +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/indextoname.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/indextoname.c.c89.patch new file mode 100644 index 0000000..307ec77 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/indextoname.c.c89.patch @@ -0,0 +1,29 @@ +--- indextoname.c 2010-05-21 11:35:23.000000000 +0800 ++++ indextoname.c89 2010-08-05 14:12:26.000000000 +0800 +@@ -39,13 +39,25 @@ + return if_indextoname (ifindex, ifname); + #else + pgm_return_val_if_fail (NULL != ifname, NULL); ++ { + +- MIB_IFROW ifRow = { .dwIndex = ifindex }; ++ MIB_IFROW ifRow; ++ ifRow.dwIndex = ifindex; ++ { + const DWORD dwRetval = GetIfEntry (&ifRow); + if (NO_ERROR != dwRetval) + return NULL; ++#ifdef _MSC_VER ++ { ++ int i; ++ wcstombs_s (&i, ifname, IF_NAMESIZE, ifRow.wszName, _TRUNCATE); ++ } ++#else + strcpy (ifname, (char*)ifRow.wszName); ++#endif + return ifname; ++ } ++ } + #endif /* _WIN32 */ + } + diff --git a/3rdparty/openpgm-svn-r1135/pgm/inet_network.c b/3rdparty/openpgm-svn-r1135/pgm/inet_network.c new file mode 100644 index 0000000..8cac34b --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/inet_network.c @@ -0,0 +1,237 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable implementations of inet_network and inet_network6. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + + +//#define INET_NETWORK_DEBUG + +/* locals */ + +static uint32_t cidr_to_netmask (const unsigned) PGM_GNUC_CONST; + + +/* calculate IPv4 netmask from network size, returns address in + * host byte order. + */ + +static +uint32_t +cidr_to_netmask ( + const unsigned cidr + ) +{ + return (cidr == 0) ? 0 : (0xffffffff - (1 << (32 - cidr)) + 1); +} + + +/* Converts a numbers-and-dots notation string into a network number in + * host order. + * Note parameters and return value differs from inet_network(). This + * function will not interpret octal numbers, preceeded with a 0, or + * hexadecimal numbers, preceeded by 0x. + * + * 127 => 127.0.0.0 + * 127.1/8 => 127.0.0.0 -- 127.1.0.0 + * inet_addr() would be 127.0.0.1 + * inet_network() would be 0.0.127.1 + * + * returns 0 on success, returns -1 on invalid address. + */ + +int /* return type to match inet_network() */ +pgm_inet_network ( + const char* restrict s, + struct in_addr* restrict in + ) +{ + pgm_return_val_if_fail (NULL != s, -1); + pgm_return_val_if_fail (NULL != in, -1); + + pgm_debug ("pgm_inet_network (s:\"%s\" in:%p)", + s, (const void*)in); + + const char *p = s; + unsigned val = 0; + int shift = 24; + + in->s_addr = INADDR_ANY; + + while (*p) + { + if (isdigit (*p)) { + val = 10 * val + (*p - '0'); + } else if (*p == '.' || *p == 0) { + if (val > 0xff) { + in->s_addr = INADDR_NONE; + return -1; + } + +//g_trace ("elem %i", val); + + in->s_addr |= val << shift; + val = 0; + shift -= 8; + if (shift < 0 && *p != 0) { + in->s_addr = INADDR_NONE; + return -1; + } + + } else if (*p == '/') { + if (val > 0xff) { + in->s_addr = INADDR_NONE; + return -1; + } +//g_trace ("elem %i", val); + in->s_addr |= val << shift; + p++; val = 0; + while (*p) + { + if (isdigit (*p)) { + val = 10 * val + (*p - '0'); + } else { + in->s_addr = INADDR_NONE; + return -1; + } + p++; + } + if (val == 0 || val > 32) { + in->s_addr = INADDR_NONE; + return -1; + } +//g_trace ("bit mask %i", val); + +/* zero out host bits */ + const struct in_addr netaddr = { .s_addr = cidr_to_netmask (val) }; +#ifdef INET_NETWORK_DEBUG +{ +g_debug ("netaddr %s", inet_ntoa (netaddr)); +} +#endif + in->s_addr &= netaddr.s_addr; + return 0; + + } else if (*p == 'x' || *p == 'X') { /* skip number, e.g. 1.x.x.x */ + if (val > 0) { + in->s_addr = INADDR_NONE; + return -1; + } + + } else { + in->s_addr = INADDR_NONE; + return -1; + } + p++; + } + + in->s_addr |= val << shift; + return 0; +} + +/* Converts a numbers-and-dots notation string into an IPv6 network number. + * + * ::1/128 => 0:0:0:0:0:0:0:1 + * ::1 => 0:0:0:0:0:0:0:1 + * ::1.2.3.4 => 0:0:0:0:1.2.3.4 + * + * returns 0 on success, returns -1 on invalid address. + */ + +int +pgm_inet6_network ( + const char* restrict s, /* NULL terminated */ + struct in6_addr* restrict in6 + ) +{ + pgm_return_val_if_fail (NULL != s, -1); + pgm_return_val_if_fail (NULL != in6, -1); + + pgm_debug ("pgm_inet6_network (s:\"%s\" in6:%p)", + s, (const void*)in6); + +/* inet_pton cannot parse IPv6 addresses with subnet declarations, so + * chop them off. + * + * as we are dealing with network addresses IPv6 zone indices are not important + * so we can use the inet_xtoy functions. + */ + char s2[INET6_ADDRSTRLEN]; + const char *p = s; + char* p2 = s2; + while (*p) { + if (*p == '/') break; + *p2++ = *p++; + } + if (*p == 0) { + if (pgm_inet_pton (AF_INET6, s, in6)) return 0; + pgm_debug ("pgm_inet_pton(AF_INET6) failed on '%s'", s); + memcpy (in6, &in6addr_any, sizeof(in6addr_any)); + return -1; + } + + *p2 = 0; + pgm_debug ("net part %s", s2); + if (!pgm_inet_pton (AF_INET6, s2, in6)) { + pgm_debug ("pgm_inet_pton(AF_INET) failed parsing network part '%s'", s2); + memcpy (in6, &in6addr_any, sizeof(in6addr_any)); + return -1; + } + +#ifdef INET_NETWORK_DEBUG + char sdebug[INET6_ADDRSTRLEN]; + pgm_debug ("IPv6 network address: %s", pgm_inet_ntop(AF_INET6, in6, sdebug, sizeof(sdebug))); +#endif + + p++; + unsigned val = 0; + while (*p) + { + if (isdigit(*p)) { + val = 10 * val + (*p - '0'); + } else { + pgm_debug ("failed parsing subnet size due to character '%c'", *p); + memcpy (in6, &in6addr_any, sizeof(in6addr_any)); + return -1; + } + p++; + } + if (val == 0 || val > 128) { + pgm_debug ("subnet size invalid (%d)", val); + memcpy (in6, &in6addr_any, sizeof(in6addr_any)); + return -1; + } + pgm_debug ("subnet size %i", val); + +/* zero out host bits */ + const unsigned suffix_length = 128 - val; + for (int i = suffix_length, j = 15; i > 0; i -= 8, --j) + { + in6->s6_addr[ j ] &= i >= 8 ? 0x00 : (unsigned)(( 0xffU << i ) & 0xffU ); + } + + pgm_debug ("effective IPv6 network address after subnet mask: %s", pgm_inet_ntop(AF_INET6, in6, s2, sizeof(s2))); + + return 0; +} + +/* eof */ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/inet_network.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/inet_network.c.c89.patch new file mode 100644 index 0000000..3dbe298 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/inet_network.c.c89.patch @@ -0,0 +1,76 @@ +--- inet_network.c 2010-05-21 11:32:20.000000000 +0800 ++++ inet_network.c89 2010-08-04 12:18:21.000000000 +0800 +@@ -70,6 +70,7 @@ + pgm_debug ("pgm_inet_network (s:\"%s\" in:%p)", + s, (const void*)in); + ++ { + const char *p = s; + unsigned val = 0; + int shift = 24; +@@ -121,13 +122,16 @@ + //g_trace ("bit mask %i", val); + + /* zero out host bits */ +- const struct in_addr netaddr = { .s_addr = cidr_to_netmask (val) }; ++ { ++ struct in_addr netaddr; ++ netaddr.s_addr = cidr_to_netmask (val); + #ifdef INET_NETWORK_DEBUG + { + g_debug ("netaddr %s", inet_ntoa (netaddr)); + } + #endif + in->s_addr &= netaddr.s_addr; ++ } + return 0; + + } else if (*p == 'x' || *p == 'X') { /* skip number, e.g. 1.x.x.x */ +@@ -145,6 +149,7 @@ + + in->s_addr |= val << shift; + return 0; ++ } + } + + /* Converts a numbers-and-dots notation string into an IPv6 network number. +@@ -174,6 +179,7 @@ + * as we are dealing with network addresses IPv6 zone indices are not important + * so we can use the inet_xtoy functions. + */ ++ { + char s2[INET6_ADDRSTRLEN]; + const char *p = s; + char* p2 = s2; +@@ -202,6 +208,7 @@ + #endif + + p++; ++ { + unsigned val = 0; + while (*p) + { +@@ -222,15 +229,22 @@ + pgm_debug ("subnet size %i", val); + + /* zero out host bits */ ++ { + const unsigned suffix_length = 128 - val; +- for (int i = suffix_length, j = 15; i > 0; i -= 8, --j) ++ { ++ int i, j; ++ for (i = suffix_length, j = 15; i > 0; i -= 8, --j) + { + in6->s6_addr[ j ] &= i >= 8 ? 0x00 : (unsigned)(( 0xffU << i ) & 0xffU ); + } ++ } + + pgm_debug ("effective IPv6 network address after subnet mask: %s", pgm_inet_ntop(AF_INET6, in6, s2, sizeof(s2))); + + return 0; ++ } ++ } ++ } + } + + /* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/inet_network_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/inet_network_unittest.c new file mode 100644 index 0000000..2739215 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/inet_network_unittest.c @@ -0,0 +1,203 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for portable implementations of inet_network and inet_network6. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* mock state */ + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + + +#define INET_NETWORK_DEBUG +#include "inet_network.c" + + +/* target: + * int + * pgm_inet_network ( + * const char* s, + * struct in_addr* in -- in host byte order + * ) + */ + +struct test_case_t { + const char* network; + const char* answer; +}; + +static const struct test_case_t cases_001[] = { + { "127", "127.0.0.0" }, /* different to inet_addr/inet_network */ + { "127/8", "127.0.0.0" }, + { "127.1/8", "127.0.0.0" }, + { "127.1", "127.1.0.0" }, /* different to inet_addr/inet_network */ + { "127.x.x.x", "127.0.0.0" }, + { "127.X.X.X", "127.0.0.0" }, + { "127.0.0.0", "127.0.0.0" }, + { "127.0.0.1/8", "127.0.0.0" }, + { "127.0.0.1/32", "127.0.0.1" }, + { "10.0.0.0/8", "10.0.0.0" }, /* RFC1918 class A */ + { "10.255.255.255/8", "10.0.0.0" }, + { "172.16.0.0/12", "172.16.0.0" }, /* RFC1918 class B */ + { "172.31.255.255/12", "172.16.0.0" }, + { "192.168.0.0/16", "192.168.0.0" }, /* RFC1918 class C */ + { "192.168.255.255/16", "192.168.0.0" }, + { "169.254.0.0/16", "169.254.0.0" }, /* RFC3927 link-local */ + { "192.88.99.0/24", "192.88.99.0" }, /* RFC3068 6to4 relay anycast */ + { "224.0.0.0/4", "224.0.0.0" }, /* RFC3171 multicast */ + { "0.0.0.0", "0.0.0.0" }, + { "255.255.255.255", "255.255.255.255" }, +}; + +START_TEST (test_inet_network_pass_001) +{ + const char* network = cases_001[_i].network; + const char* answer = cases_001[_i].answer; + + struct in_addr host_order, network_order; + fail_unless (0 == pgm_inet_network (network, &host_order)); + network_order.s_addr = g_htonl (host_order.s_addr); + + g_message ("Resolved \"%s\" to \"%s\"", + network, inet_ntoa (network_order)); + +{ +struct in_addr t = { .s_addr = g_htonl (inet_network (network)) }; +g_message ("inet_network (%s) = %s", network, inet_ntoa (t)); +} + + fail_unless (0 == strcmp (answer, inet_ntoa (network_order))); +} +END_TEST + +START_TEST (test_inet_network_fail_001) +{ + fail_unless (-1 == pgm_inet_network (NULL, NULL)); +} +END_TEST + +START_TEST (test_inet_network_fail_002) +{ + const char* network = "192.168.0.1/0"; + + struct in_addr host_order; + fail_unless (-1 == pgm_inet_network (network, &host_order)); +} +END_TEST + +/* target: + * int + * pgm_inet6_network ( + * const char* s, + * struct in6_addr* in6 + * ) + */ + +static const struct test_case_t cases6_001[] = { + { "::1/128", "::1" }, + { "2002:dec8:d28e::36/64", "2002:dec8:d28e::" }, /* 6to4 */ + { "fe80::203:baff:fe4e:6cc8/10", "fe80::" }, /* link-local */ + { "ff02::1/8", "ff00::" }, /* multicast */ + { "fc00:6::61/7", "fc00::" }, /* ULA */ +}; + +START_TEST (test_inet6_network_pass_001) +{ + const char* network = cases6_001[_i].network; + const char* answer = cases6_001[_i].answer; + + char snetwork[INET6_ADDRSTRLEN]; + struct in6_addr addr; + fail_unless (0 == pgm_inet6_network (network, &addr)); + g_message ("Resolved \"%s\" to \"%s\"", + network, pgm_inet_ntop (AF_INET6, &addr, snetwork, sizeof(snetwork))); + + fail_unless (0 == strcmp (answer, snetwork)); +} +END_TEST + +START_TEST (test_inet6_network_fail_001) +{ + fail_unless (-1 == pgm_inet6_network (NULL, NULL)); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_inet_network = tcase_create ("inet-network"); + suite_add_tcase (s, tc_inet_network); + tcase_add_loop_test (tc_inet_network, test_inet_network_pass_001, 0, G_N_ELEMENTS(cases_001)); + tcase_add_test (tc_inet_network, test_inet_network_fail_001); + + TCase* tc_inet6_network = tcase_create ("inet6-network"); + suite_add_tcase (s, tc_inet6_network); + tcase_add_loop_test (tc_inet6_network, test_inet6_network_pass_001, 0, G_N_ELEMENTS(cases6_001)); + tcase_add_test (tc_inet6_network, test_inet6_network_fail_001); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/ip_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/ip_unittest.c new file mode 100644 index 0000000..692fb55 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/ip_unittest.c @@ -0,0 +1,367 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for ip stack. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* getsockopt(3SOCKET) + * level is the protocol number of the protocl that controls the option. + */ +#ifndef SOL_IP +# define SOL_IP IPPROTO_IP +#endif +#ifndef SOL_IPV6 +# define SOL_IPV6 IPPROTO_IPV6 +#endif + +/* mock state */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + + +#define PGM_COMPILATION +#include "impl/sockaddr.h" +#include "impl/indextoaddr.h" +#include "impl/ip.h" + + +/* target: + * testing platform capability to loop send multicast packets to a listening + * receive socket. + */ + +START_TEST (test_multicast_loop_pass_001) +{ + struct sockaddr_in addr; + memset (&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr ("239.192.0.1"); + + int recv_sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); + fail_if (-1 == recv_sock, "socket failed"); + struct sockaddr_in recv_addr; + memcpy (&recv_addr, &addr, sizeof(addr)); + recv_addr.sin_port = 7500; + fail_unless (0 == bind (recv_sock, (struct sockaddr*)&recv_addr, pgm_sockaddr_len ((struct sockaddr*)&recv_addr)), "bind failed"); + struct group_req gr; + memset (&gr, 0, sizeof(gr)); + ((struct sockaddr*)&gr.gr_group)->sa_family = addr.sin_family; + ((struct sockaddr_in*)&gr.gr_group)->sin_addr.s_addr = addr.sin_addr.s_addr; + fail_unless (0 == setsockopt (recv_sock, SOL_IP, MCAST_JOIN_GROUP, (const char*)&gr, sizeof(gr)), "setsockopt failed"); + fail_unless (0 == pgm_sockaddr_multicast_loop (recv_sock, AF_INET, FALSE), "multicast_loop failed"); + + int send_sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); + fail_if (-1 == send_sock, "socket failed"); + struct sockaddr_in send_addr; + memcpy (&send_addr, &addr, sizeof(addr)); + fail_unless (0 == bind (send_sock, (struct sockaddr*)&send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)), "bind failed"); + struct sockaddr_in if_addr; + fail_unless (TRUE == pgm_if_indextoaddr (0, AF_INET, 0, (struct sockaddr*)&if_addr, NULL), "if_indextoaddr failed"); + fail_unless (0 == pgm_sockaddr_multicast_if (send_sock, (struct sockaddr*)&if_addr, 0), "multicast_if failed"); + fail_unless (0 == pgm_sockaddr_multicast_loop (send_sock, AF_INET, TRUE), "multicast_loop failed"); + + const char data[] = "apple pie"; + addr.sin_port = 7500; + ssize_t bytes_sent = sendto (send_sock, data, sizeof(data), 0, (struct sockaddr*)&addr, pgm_sockaddr_len ((struct sockaddr*)&addr)); + if (-1 == bytes_sent) + g_message ("sendto: %s", strerror (errno)); + fail_unless (sizeof(data) == bytes_sent, "sendto underrun"); + + char recv_data[1024]; + ssize_t bytes_read = recv (recv_sock, recv_data, sizeof(recv_data), MSG_DONTWAIT); + if (-1 == bytes_read) + g_message ("sendto: %s", strerror (errno)); + fail_unless (sizeof(data) == bytes_read, "recv underrun"); + + fail_unless (0 == close (recv_sock), "close failed"); + fail_unless (0 == close (send_sock), "close failed"); +} +END_TEST + +/* target: + * testing whether unicast bind accepts packets to multicast join on a + * different port. + */ + +START_TEST (test_port_bind_pass_001) +{ + struct sockaddr_in addr; + memset (&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr ("239.192.0.1"); + + int recv_sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); + fail_if (-1 == recv_sock, "socket failed"); + struct sockaddr_in recv_addr; + memcpy (&recv_addr, &addr, sizeof(addr)); + recv_addr.sin_port = 3056; + fail_unless (0 == bind (recv_sock, (struct sockaddr*)&recv_addr, pgm_sockaddr_len ((struct sockaddr*)&recv_addr)), "bind failed"); + struct group_req gr; + memset (&gr, 0, sizeof(gr)); + ((struct sockaddr*)&gr.gr_group)->sa_family = addr.sin_family; + ((struct sockaddr_in*)&gr.gr_group)->sin_addr.s_addr = addr.sin_addr.s_addr; + ((struct sockaddr_in*)&gr.gr_group)->sin_port = 3055; + fail_unless (0 == setsockopt (recv_sock, SOL_IP, MCAST_JOIN_GROUP, (const char*)&gr, sizeof(gr)), "setsockopt failed"); + fail_unless (0 == pgm_sockaddr_multicast_loop (recv_sock, AF_INET, FALSE), "multicast_loop failed"); + + int send_sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); + fail_if (-1 == send_sock, "socket failed"); + struct sockaddr_in send_addr; + memcpy (&send_addr, &addr, sizeof(addr)); + fail_unless (0 == bind (send_sock, (struct sockaddr*)&send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)), "bind failed"); + struct sockaddr_in if_addr; + fail_unless (TRUE == pgm_if_indextoaddr (0, AF_INET, 0, (struct sockaddr*)&if_addr, NULL), "if_indextoaddr failed"); + fail_unless (0 == pgm_sockaddr_multicast_if (send_sock, (struct sockaddr*)&if_addr, 0), "multicast_if failed"); + fail_unless (0 == pgm_sockaddr_multicast_loop (send_sock, AF_INET, TRUE), "multicast_loop failed"); + + const char data[] = "apple pie"; + addr.sin_port = 3056; + ssize_t bytes_sent = sendto (send_sock, data, sizeof(data), 0, (struct sockaddr*)&addr, pgm_sockaddr_len ((struct sockaddr*)&addr)); + if (-1 == bytes_sent) + g_message ("sendto: %s", strerror (errno)); + fail_unless (sizeof(data) == bytes_sent, "sendto underrun"); + + char recv_data[1024]; + ssize_t bytes_read = recv (recv_sock, recv_data, sizeof(recv_data), MSG_DONTWAIT); + if (-1 == bytes_read) + g_message ("recv: %s", strerror (errno)); + if (sizeof(data) != bytes_read) + g_message ("recv returned %d bytes expected %d.", bytes_read, sizeof(data)); + fail_unless (sizeof(data) == bytes_read, "recv underrun"); + + fail_unless (0 == close (recv_sock), "close failed"); + fail_unless (0 == close (send_sock), "close failed"); +} +END_TEST + +/* target: + * test setting hop limit, aka time-to-live. + * + * NB: whilst convenient, we cannot use SOCK_RAW & IPPROTO_UDP on Solaris 10 + * as it crashes the IP stack. + */ + +START_TEST (test_hop_limit_pass_001) +{ + struct sockaddr_in addr; + memset (&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr ("239.192.0.1"); + + int recv_sock = socket (AF_INET, SOCK_RAW, 113); + fail_if (-1 == recv_sock, "socket failed"); + struct sockaddr_in recv_addr; + memcpy (&recv_addr, &addr, sizeof(addr)); + recv_addr.sin_port = 7500; + fail_unless (0 == bind (recv_sock, (struct sockaddr*)&recv_addr, pgm_sockaddr_len ((struct sockaddr*)&recv_addr)), "bind failed"); + struct group_req gr; + memset (&gr, 0, sizeof(gr)); + ((struct sockaddr*)&gr.gr_group)->sa_family = addr.sin_family; + ((struct sockaddr_in*)&gr.gr_group)->sin_addr.s_addr = addr.sin_addr.s_addr; + fail_unless (0 == setsockopt (recv_sock, SOL_IP, MCAST_JOIN_GROUP, (const char*)&gr, sizeof(gr)), "setsockopt failed"); + fail_unless (0 == pgm_sockaddr_multicast_loop (recv_sock, AF_INET, FALSE), "multicast_loop failed"); + fail_unless (0 == pgm_sockaddr_hdrincl (recv_sock, AF_INET, TRUE), "hdrincl failed"); + + int send_sock = socket (AF_INET, SOCK_RAW, 113); + fail_if (-1 == send_sock, "socket failed"); + struct sockaddr_in send_addr; + memcpy (&send_addr, &addr, sizeof(addr)); + fail_unless (0 == bind (send_sock, (struct sockaddr*)&send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)), "bind failed"); + struct sockaddr_in if_addr; + fail_unless (TRUE == pgm_if_indextoaddr (0, AF_INET, 0, (struct sockaddr*)&if_addr, NULL), "if_indextoaddr failed"); + fail_unless (0 == pgm_sockaddr_multicast_if (send_sock, (struct sockaddr*)&if_addr, 0), "multicast_if failed"); + fail_unless (0 == pgm_sockaddr_multicast_loop (send_sock, AF_INET, TRUE), "multicast_loop failed"); + fail_unless (0 == pgm_sockaddr_multicast_hops (send_sock, AF_INET, 16), "multicast_hops failed"); + + const char data[] = "apple pie"; + addr.sin_port = 7500; + ssize_t bytes_sent = sendto (send_sock, data, sizeof(data), 0, (struct sockaddr*)&addr, pgm_sockaddr_len ((struct sockaddr*)&addr)); + if (-1 == bytes_sent) + g_message ("sendto: %s", strerror (errno)); + fail_unless (sizeof(data) == bytes_sent, "sendto underrun"); + + char recv_data[1024]; + ssize_t bytes_read = recv (recv_sock, recv_data, sizeof(recv_data), MSG_DONTWAIT); + if (-1 == bytes_read) + g_message ("recv: %s", strerror (errno)); + const size_t pkt_len = sizeof(struct pgm_ip) + sizeof(data); + if (pkt_len != bytes_read) + g_message ("recv returned %zd bytes expected %zu.", bytes_read, pkt_len); + fail_unless (pkt_len == bytes_read, "recv underrun"); + const struct pgm_ip* iphdr = (void*)recv_data; + fail_unless (4 == iphdr->ip_v, "Incorrect IP version, found %u expecting 4.", iphdr->ip_v); + fail_unless (16 == iphdr->ip_ttl, "hop count mismatch, found %u expecting 16.", iphdr->ip_ttl); + + fail_unless (0 == close (recv_sock), "close failed"); + fail_unless (0 == close (send_sock), "close failed"); +} +END_TEST + +/* target: + * router alert. + */ + +START_TEST (test_router_alert_pass_001) +{ + struct sockaddr_in addr; + memset (&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr ("239.192.0.1"); + + int recv_sock = socket (AF_INET, SOCK_RAW, 113); + fail_if (-1 == recv_sock, "socket failed"); + struct sockaddr_in recv_addr; + memcpy (&recv_addr, &addr, sizeof(addr)); + recv_addr.sin_port = 7500; + fail_unless (0 == bind (recv_sock, (struct sockaddr*)&recv_addr, pgm_sockaddr_len ((struct sockaddr*)&recv_addr)), "bind failed"); + struct group_req gr; + memset (&gr, 0, sizeof(gr)); + ((struct sockaddr*)&gr.gr_group)->sa_family = addr.sin_family; + ((struct sockaddr_in*)&gr.gr_group)->sin_addr.s_addr = addr.sin_addr.s_addr; + fail_unless (0 == setsockopt (recv_sock, SOL_IP, MCAST_JOIN_GROUP, (const char*)&gr, sizeof(gr)), "setsockopt failed"); + fail_unless (0 == pgm_sockaddr_multicast_loop (recv_sock, AF_INET, FALSE), "multicast_loop failed"); + fail_unless (0 == pgm_sockaddr_hdrincl (recv_sock, AF_INET, TRUE), "hdrincl failed"); + + int send_sock = socket (AF_INET, SOCK_RAW, 113); + fail_if (-1 == send_sock, "socket failed"); + struct sockaddr_in send_addr; + memcpy (&send_addr, &addr, sizeof(addr)); + fail_unless (0 == bind (send_sock, (struct sockaddr*)&send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)), "bind failed"); + struct sockaddr_in if_addr; + fail_unless (TRUE == pgm_if_indextoaddr (0, AF_INET, 0, (struct sockaddr*)&if_addr, NULL), "if_indextoaddr failed"); + fail_unless (0 == pgm_sockaddr_multicast_if (send_sock, (struct sockaddr*)&if_addr, 0), "multicast_if failed"); + fail_unless (0 == pgm_sockaddr_multicast_loop (send_sock, AF_INET, TRUE), "multicast_loop failed"); + fail_unless (0 == pgm_sockaddr_router_alert (send_sock, AF_INET, TRUE), "router_alert failed"); + + const char data[] = "apple pie"; + addr.sin_port = 7500; + ssize_t bytes_sent = sendto (send_sock, data, sizeof(data), 0, (struct sockaddr*)&addr, pgm_sockaddr_len ((struct sockaddr*)&addr)); + if (-1 == bytes_sent) + g_message ("sendto: %s", strerror (errno)); + fail_unless (sizeof(data) == bytes_sent, "sendto underrun"); + + char recv_data[1024]; + ssize_t bytes_read = recv (recv_sock, recv_data, sizeof(recv_data), MSG_DONTWAIT); + if (-1 == bytes_read) + g_message ("recv: %s", strerror (errno)); + const size_t ra_iphdr_len = sizeof(uint32_t) + sizeof(struct pgm_ip); + const size_t ra_pkt_len = ra_iphdr_len + sizeof(data); + if (ra_pkt_len != bytes_read) + g_message ("recv returned %zd bytes expected %zu.", bytes_read, ra_pkt_len); + fail_unless (ra_pkt_len == bytes_read, "recv underrun"); + const struct pgm_ip* iphdr = (void*)recv_data; + fail_unless (4 == iphdr->ip_v, "Incorrect IP version, found %u expecting 4.", iphdr->ip_v); + if (ra_iphdr_len != (iphdr->ip_hl << 2)) { + g_message ("IP header length mismatch, found %zu expecting %zu.", + (size_t)(iphdr->ip_hl << 2), ra_iphdr_len); + } + g_message ("IP header length = %zu", (size_t)(iphdr->ip_hl << 2)); + const uint32_t* ipopt = (const void*)&recv_data[ iphdr->ip_hl << 2 ]; + const uint32_t ipopt_ra = ((uint32_t)PGM_IPOPT_RA << 24) | (0x04 << 16); + const uint32_t router_alert = htonl(ipopt_ra); + if (router_alert == *ipopt) { + g_message ("IP option router alert found after IP header length."); + ipopt += sizeof(uint32_t); + } else { + ipopt = (const void*)&recv_data[ sizeof(struct pgm_ip) ]; + fail_unless (router_alert == *ipopt, "IP router alert option not found."); + g_message ("IP option router alert found before end of IP header length."); + } + g_message ("Final IP header length = %zu", (size_t)((const char*)ipopt - (const char*)recv_data)); + + fail_unless (0 == close (recv_sock), "close failed"); + fail_unless (0 == close (send_sock), "close failed"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_multicast_loop = tcase_create ("multicast loop"); + suite_add_tcase (s, tc_multicast_loop); + tcase_add_test (tc_multicast_loop, test_multicast_loop_pass_001); + + TCase* tc_port_bind = tcase_create ("port bind"); + suite_add_tcase (s, tc_port_bind); + tcase_add_test (tc_port_bind, test_port_bind_pass_001); + + TCase* tc_hop_limit = tcase_create ("hop limit"); + suite_add_tcase (s, tc_hop_limit); + tcase_add_test (tc_hop_limit, test_hop_limit_pass_001); + + TCase* tc_router_alert = tcase_create ("router alert"); + suite_add_tcase (s, tc_router_alert); + tcase_add_test (tc_router_alert, test_router_alert_pass_001); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + if (0 != getuid()) { + fprintf (stderr, "This test requires super-user privileges to run.\n"); + return EXIT_FAILURE; + } + + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/list.c b/3rdparty/openpgm-svn-r1135/pgm/list.c new file mode 100644 index 0000000..7b22f17 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/list.c @@ -0,0 +1,146 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable doubly-linked list. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + + +//#define LIST_DEBUG + +pgm_list_t* +pgm_list_append ( + pgm_list_t* restrict list, + void* restrict data + ) +{ + pgm_list_t* new_list; + pgm_list_t* last; + + new_list = pgm_new (pgm_list_t, 1); + new_list->data = data; + new_list->next = NULL; + + if (list) + { + last = pgm_list_last (list); + last->next = new_list; + new_list->prev = last; + return list; + } + else + { + new_list->prev = NULL; + return new_list; + } +} + +pgm_list_t* +pgm_list_prepend_link ( + pgm_list_t* restrict list, + pgm_list_t* restrict link_ + ) +{ + pgm_list_t* new_list = link_; + + pgm_return_val_if_fail (NULL != link_, list); + + new_list->next = list; + new_list->prev = NULL; + + if (list) + list->prev = new_list; + return new_list; +} + +static inline +pgm_list_t* +_pgm_list_remove_link ( + pgm_list_t* list, /* list and link_ may be the same */ + pgm_list_t* link_ + ) +{ + if (PGM_LIKELY (NULL != link_)) + { + if (link_->prev) + link_->prev->next = link_->next; + if (link_->next) + link_->next->prev = link_->prev; + + if (link_ == list) + list = list->next; + + link_->next = link_->prev = NULL; + } + return list; +} + +pgm_list_t* +pgm_list_remove_link ( + pgm_list_t* list, /* list and link_ may be the same */ + pgm_list_t* link_ + ) +{ + return _pgm_list_remove_link (list, link_); +} + +pgm_list_t* +pgm_list_delete_link ( + pgm_list_t* list, /* list and link_ may be the same */ + pgm_list_t* link_ + ) +{ + pgm_list_t* new_list = _pgm_list_remove_link (list, link_); + pgm_free (link_); + + return new_list; +} + +/* Has pure attribute as NULL is a valid list + */ + +pgm_list_t* +pgm_list_last ( + pgm_list_t* list + ) +{ + if (PGM_LIKELY (NULL != list)) { + while (list->next) + list = list->next; + } + return list; +} + +unsigned +pgm_list_length ( + pgm_list_t* list + ) +{ + unsigned length = 0; + + while (list) + { + length++; + list = list->next; + } + + return length; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/log.c b/3rdparty/openpgm-svn-r1135/pgm/log.c new file mode 100644 index 0000000..af2aec5 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/log.c @@ -0,0 +1,151 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * basic logging. + * + * Copyright (c) 2006-2007 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#ifndef G_OS_WIN32 +# include +#endif +#include +#include "pgm/log.h" + + +/* globals */ + +#define TIME_FORMAT "%Y-%m-%d %H:%M:%S " + +static int log_timezone PGM_GNUC_READ_MOSTLY = 0; +static char log_hostname[NI_MAXHOST + 1] PGM_GNUC_READ_MOSTLY; + +static void glib_log_handler (const gchar*, GLogLevelFlags, const gchar*, gpointer); +static void pgm_log_handler (const int, const char*, void*); + + +/* calculate time zone offset in seconds + */ + +bool +log_init ( void ) +{ +/* time zone offset */ + time_t t = time(NULL); + struct tm sgmt, *gmt = &sgmt; + *gmt = *gmtime(&t); + struct tm* loc = localtime(&t); + log_timezone = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + + (loc->tm_min - gmt->tm_min) * 60; + int dir = loc->tm_year - gmt->tm_year; + if (!dir) dir = loc->tm_yday - gmt->tm_yday; + log_timezone += dir * 24 * 60 * 60; +// printf ("timezone offset %u seconds.\n", log_timezone); + gethostname (log_hostname, sizeof(log_hostname)); + g_log_set_handler ("Pgm", G_LOG_LEVEL_MASK, glib_log_handler, NULL); + g_log_set_handler ("Pgm-Http", G_LOG_LEVEL_MASK, glib_log_handler, NULL); + g_log_set_handler ("Pgm-Snmp", G_LOG_LEVEL_MASK, glib_log_handler, NULL); + g_log_set_handler (NULL, G_LOG_LEVEL_MASK, glib_log_handler, NULL); + pgm_log_set_handler (pgm_log_handler, NULL); + return 0; +} + +/* log callback + */ +static void +glib_log_handler ( + const gchar* log_domain, + G_GNUC_UNUSED GLogLevelFlags log_level, + const gchar* message, + G_GNUC_UNUSED gpointer unused_data + ) +{ +#ifdef G_OS_UNIX + struct iovec iov[7]; + struct iovec* v = iov; + time_t now; + time (&now); + const struct tm* time_ptr = localtime(&now); + char tbuf[1024]; + strftime(tbuf, sizeof(tbuf), TIME_FORMAT, time_ptr); + v->iov_base = tbuf; + v->iov_len = strlen(tbuf); + v++; + v->iov_base = log_hostname; + v->iov_len = strlen(log_hostname); + v++; + if (log_domain) { + v->iov_base = " "; + v->iov_len = 1; + v++; + v->iov_base = log_domain; + v->iov_len = strlen(log_domain); + v++; + } + v->iov_base = ": "; + v->iov_len = 2; + v++; + v->iov_base = message; + v->iov_len = strlen(message); + v++; + v->iov_base = "\n"; + v->iov_len = 1; + v++; + writev (STDOUT_FILENO, iov, v - iov); +#else + time_t now; + time (&now); + const struct tm* time_ptr = localtime(&now); + char s[1024]; + strftime(s, sizeof(s), TIME_FORMAT, time_ptr); + write (STDOUT_FILENO, s, strlen(s)); + write (STDOUT_FILENO, log_hostname, strlen(log_hostname)); + if (log_domain) { + write (STDOUT_FILENO, " ", 1); + write (STDOUT_FILENO, log_domain, strlen(log_domain)); + } + write (STDOUT_FILENO, ": ", 2); + write (STDOUT_FILENO, message, strlen(message)); + write (STDOUT_FILENO, "\n", 1); +#endif +} + +static void +pgm_log_handler ( + const int pgm_log_level, + const char* message, + G_GNUC_UNUSED void* closure + ) +{ + GLogLevelFlags glib_log_level; + + switch (pgm_log_level) { + case PGM_LOG_LEVEL_DEBUG: glib_log_level = G_LOG_LEVEL_DEBUG; break; + case PGM_LOG_LEVEL_TRACE: glib_log_level = G_LOG_LEVEL_DEBUG; break; + case PGM_LOG_LEVEL_MINOR: glib_log_level = G_LOG_LEVEL_INFO; break; + case PGM_LOG_LEVEL_NORMAL: glib_log_level = G_LOG_LEVEL_MESSAGE; break; + case PGM_LOG_LEVEL_WARNING: glib_log_level = G_LOG_LEVEL_WARNING; break; + case PGM_LOG_LEVEL_ERROR: glib_log_level = G_LOG_LEVEL_CRITICAL; break; + case PGM_LOG_LEVEL_FATAL: glib_log_level = G_LOG_LEVEL_ERROR; break; + } + + g_log ("Pgm", glib_log_level, message, NULL); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/math.c b/3rdparty/openpgm-svn-r1135/pgm/math.c new file mode 100644 index 0000000..c2a1b4e --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/math.c @@ -0,0 +1,75 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable math. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + + +//#define MATH_DEBUG + + +static const unsigned primes[] = +{ + 11, + 19, + 37, + 73, + 109, + 163, + 251, + 367, + 557, + 823, + 1237, + 1861, + 2777, + 4177, + 6247, + 9371, + 14057, + 21089, + 31627, + 47431, + 71143, + 106721, + 160073, + 240101, + 360163, + 540217, + 810343, + 1215497, + 1823231, + 2734867, + 4102283, + 6153409, + 9230113, + 13845163, +}; + +unsigned +pgm_spaced_primes_closest (unsigned num) +{ + for (unsigned i = 0; i < PGM_N_ELEMENTS(primes); i++) + if (primes[i] > num) + return primes[i]; + return primes[PGM_N_ELEMENTS(primes) - 1]; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/math.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/math.c.c89.patch new file mode 100644 index 0000000..f6746fc --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/math.c.c89.patch @@ -0,0 +1,16 @@ +--- math.c 2010-05-21 11:32:22.000000000 +0800 ++++ math.c89 2010-08-03 17:25:54.000000000 +0800 +@@ -66,9 +66,12 @@ + unsigned + pgm_spaced_primes_closest (unsigned num) + { +- for (unsigned i = 0; i < PGM_N_ELEMENTS(primes); i++) ++ { ++ unsigned i; ++ for (i = 0; i < PGM_N_ELEMENTS(primes); i++) + if (primes[i] > num) + return primes[i]; ++ } + return primes[PGM_N_ELEMENTS(primes) - 1]; + } + diff --git a/3rdparty/openpgm-svn-r1135/pgm/md5.c b/3rdparty/openpgm-svn-r1135/pgm/md5.c new file mode 100644 index 0000000..9761113 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/md5.c @@ -0,0 +1,368 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * MD5 hashing algorithm. + * + * MD5 original source GNU C Library: + * Includes functions to compute MD5 message digest of files or memory blocks + * according to the definition of MD5 in RFC 1321 from April 1992. + * + * Copyright (C) 1995, 1996, 2001, 2003 Free Software Foundation, Inc. + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this file; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + + +//#define MD5_DEBUG + + +/* locals */ + +static void _pgm_md5_process_block (struct pgm_md5_t*restrict, const void*restrict, size_t); +static void* _pgm_md5_read_ctx (const struct pgm_md5_t*, void*restrict); + + +/* This array contains the bytes used to pad the buffer to the next + * 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +#if __BYTE_ORDER == __BIG_ENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ + +void +pgm_md5_init_ctx ( + struct pgm_md5_t* ctx + ) +{ +/* pre-conditions */ + pgm_assert (NULL != ctx); + + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +static +void +_pgm_md5_process_block ( + struct pgm_md5_t* restrict ctx, + const void* restrict buffer, + size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != buffer); + pgm_assert (len > 0); + pgm_assert (NULL != ctx); + + uint32_t correct_words[16]; + const uint32_t *words = buffer; + const size_t nwords = len / sizeof (uint32_t); + const uint32_t *endp = words + nwords; + uint32_t A = ctx->A; + uint32_t B = ctx->B; + uint32_t C = ctx->C; + uint32_t D = ctx->D; + +/* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + +/* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + uint32_t *cwp = correct_words; + uint32_t A_save = A; + uint32_t B_save = B; + uint32_t C_save = C; + uint32_t D_save = D; + +/* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + +/* It is unfortunate that C does not provide an operator for + * cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + +/* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64, or + perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}' + */ + +/* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + +/* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + +/* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + +/* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + +/* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + +/* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + +/* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} + +void +pgm_md5_process_bytes ( + struct pgm_md5_t* restrict ctx, + const void* restrict buffer, + size_t len + ) +{ +/* pre-conditions */ + if (len > 0) { + pgm_assert (NULL != buffer); + } + pgm_assert (NULL != ctx); + + if (len >= 64) + { +#ifndef _STRING_ARCH_unaligned +/* To check alignment gcc has an appropriate operator. Other + compilers don't. */ +# if __GNUC__ >= 2 +# define UNALIGNED_P(p) (((uintptr_t)p) % __alignof__ (uint32_t) != 0) +# else +# define UNALIGNED_P(p) (((uintptr_t)p) % sizeof(uint32_t) != 0) +# endif + if (UNALIGNED_P (buffer)) + while (len > 64) + { + _pgm_md5_process_block (ctx, memcpy (ctx->buffer, buffer, 64), 64); + buffer = (const char*)buffer + 64; + len -= 64; + } + else +#endif + { + _pgm_md5_process_block (ctx, buffer, len & ~63); + buffer = (const char*)buffer + (len & ~63); + len &= 63; + } + } + +/* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&ctx->buffer[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + _pgm_md5_process_block (ctx, ctx->buffer, 64); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[64], left_over); + } + ctx->buflen = left_over; + } +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result + must be in little endian byte order. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ + +static +void* +_pgm_md5_read_ctx ( + const struct pgm_md5_t* restrict ctx, + void* restrict resbuf + ) +{ +/* pre-conditions */ + pgm_assert (NULL != ctx); + pgm_assert (NULL != resbuf); + + ((uint32_t*)resbuf)[0] = SWAP (ctx->A); + ((uint32_t*)resbuf)[1] = SWAP (ctx->B); + ((uint32_t*)resbuf)[2] = SWAP (ctx->C); + ((uint32_t*)resbuf)[3] = SWAP (ctx->D); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ + +void* +pgm_md5_finish_ctx ( + struct pgm_md5_t* restrict ctx, + void* restrict resbuf + ) +{ +/* pre-conditions */ + pgm_assert (NULL != ctx); + pgm_assert (NULL != resbuf); + +/* Take yet unprocessed bytes into account. */ + const uint32_t bytes = ctx->buflen; + size_t pad; + +/* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy (&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + *(uint32_t*) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3); + *(uint32_t*) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) | + (ctx->total[0] >> 29)); + +/* Process last bytes. */ + _pgm_md5_process_block (ctx, ctx->buffer, bytes + pad + 8); + + return _pgm_md5_read_ctx (ctx, resbuf); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/md5.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/md5.c.c89.patch new file mode 100644 index 0000000..14d8971 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/md5.c.c89.patch @@ -0,0 +1,34 @@ +--- md5.c 2010-05-21 11:32:21.000000000 +0800 ++++ md5.c89 2010-08-04 12:19:52.000000000 +0800 +@@ -92,6 +92,7 @@ + pgm_assert (len > 0); + pgm_assert (NULL != ctx); + ++ { + uint32_t correct_words[16]; + const uint32_t *words = buffer; + const size_t nwords = len / sizeof (uint32_t); +@@ -243,6 +244,7 @@ + ctx->B = B; + ctx->C = C; + ctx->D = D; ++ } + } + + void +@@ -343,6 +345,7 @@ + pgm_assert (NULL != resbuf); + + /* Take yet unprocessed bytes into account. */ ++ { + const uint32_t bytes = ctx->buflen; + size_t pad; + +@@ -363,6 +366,7 @@ + _pgm_md5_process_block (ctx, ctx->buffer, bytes + pad + 8); + + return _pgm_md5_read_ctx (ctx, resbuf); ++ } + } + + /* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/md5_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/md5_unittest.c new file mode 100644 index 0000000..836af1f --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/md5_unittest.c @@ -0,0 +1,189 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for MD5 hashing (not actual algorithm). + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* mock state */ + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + + +#define MD5_DEBUG +#include "md5.c" + + +/* target: + * void + * pgm_md5_init_ctx ( + * struct pgm_md5_t* ctx + * ) + */ + +START_TEST (test_init_ctx_pass_001) +{ + struct pgm_md5_t ctx; + memset (&ctx, 0, sizeof(ctx)); + pgm_md5_init_ctx (&ctx); +} +END_TEST + +START_TEST (test_init_ctx_fail_001) +{ + pgm_md5_init_ctx (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_md5_process_bytes ( + * struct pgm_md5_t* ctx, + * const void* buffer, + * size_t len + * ) + */ + +START_TEST (test_process_bytes_pass_001) +{ + const char buffer[] = "i am not a string."; + struct pgm_md5_t ctx; + memset (&ctx, 0, sizeof(ctx)); + pgm_md5_init_ctx (&ctx); + pgm_md5_process_bytes (&ctx, buffer, sizeof(buffer)); +} +END_TEST + +START_TEST (test_process_bytes_fail_001) +{ + const char buffer[] = "i am not a string."; + pgm_md5_process_bytes (NULL, buffer, sizeof(buffer)); +} +END_TEST + +/* target: + * void* + * pgm_md5_finish_ctx ( + * struct pgm_md5_t* ctx, + * void* resbuf + * ) + */ + +START_TEST (test_finish_ctx_pass_001) +{ + const char* buffer = "i am not a string."; + const char* answer = "ef71-1617-4eef-9737-5e2b-5d7a-d015-b064"; + + char md5[1024]; + char resblock[16]; + struct pgm_md5_t ctx; + memset (&ctx, 0, sizeof(ctx)); + memset (resblock, 0, sizeof(resblock)); + pgm_md5_init_ctx (&ctx); + pgm_md5_process_bytes (&ctx, buffer, strlen(buffer)+1); + pgm_md5_finish_ctx (&ctx, resblock); + sprintf (md5, "%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx-%02.2hhx%02.2hhx", + resblock[0], resblock[1], + resblock[2], resblock[3], + resblock[4], resblock[5], + resblock[6], resblock[7], + resblock[8], resblock[9], + resblock[10], resblock[11], + resblock[12], resblock[13], + resblock[14], resblock[15]); + g_message ("md5: %s", md5); + + fail_unless (0 == strcmp (md5, answer), "md5 mismatch"); +} +END_TEST + +START_TEST (test_finish_ctx_fail_001) +{ + char resblock[16]; + pgm_md5_finish_ctx (NULL, resblock); + fail ("reached"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_init_ctx = tcase_create ("init-ctx"); + suite_add_tcase (s, tc_init_ctx); + tcase_add_test (tc_init_ctx, test_init_ctx_pass_001); + tcase_add_test_raise_signal (tc_init_ctx, test_init_ctx_fail_001, SIGABRT); + + TCase* tc_process_bytes = tcase_create ("process_bytes"); + suite_add_tcase (s, tc_process_bytes); + tcase_add_test (tc_process_bytes, test_process_bytes_pass_001); + tcase_add_test_raise_signal (tc_process_bytes, test_process_bytes_fail_001, SIGABRT); + + TCase* tc_finish_ctx = tcase_create ("finish-ctx"); + suite_add_tcase (s, tc_finish_ctx); + tcase_add_test (tc_finish_ctx, test_finish_ctx_pass_001); + tcase_add_test_raise_signal (tc_finish_ctx, test_finish_ctx_fail_001, SIGABRT); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/mem.c b/3rdparty/openpgm-svn-r1135/pgm/mem.c new file mode 100644 index 0000000..ac98fe6 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/mem.c @@ -0,0 +1,250 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable fail fast memory allocation. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#ifdef _WIN32 +# define strcasecmp stricmp +#endif +#include +#include + + +//#define MEM_DEBUG + + +/* globals */ + +bool pgm_mem_gc_friendly PGM_GNUC_READ_MOSTLY = FALSE; + + +/* locals */ + +struct pgm_debug_key_t { + const char* key; + unsigned value; +}; +typedef struct pgm_debug_key_t pgm_debug_key_t; + +static volatile uint32_t mem_ref_count = 0; + + +static +bool +debug_key_matches ( + const char* restrict key, + const char* restrict token, + unsigned length + ) +{ + for (; length; length--, key++, token++) + { + const char k = (*key == '_') ? '-' : tolower (*key ); + const char t = (*token == '_') ? '-' : tolower (*token); + if (k != t) + return FALSE; + } + return *key == '\0'; +} + +static +unsigned +pgm_parse_debug_string ( + const char* restrict string, + const pgm_debug_key_t* restrict keys, + const unsigned nkeys + ) +{ + unsigned result = 0; + + if (NULL == string) + return result; + + if (!strcasecmp (string, "all")) + { + for (unsigned i = 0; i < nkeys; i++) + result |= keys[i].value; + } + else if (!strcasecmp (string, "help")) + { + fprintf (stderr, "Supported debug values:"); + for (unsigned i = 0; i < nkeys; i++) + fprintf (stderr, " %s", keys[i].key); + fprintf (stderr, "\n"); + } + else + { + while (string) { + const char* q = strpbrk (string, ":;, \t"); + if (!q) + q = string + strlen (string); + for (unsigned i = 0; i < nkeys; i++) + if (debug_key_matches (keys[i].key, string, q - string)) + result |= keys[i].value; + string = q; + if (*string) + string++; + } + } + return result; +} + +void +pgm_mem_init (void) +{ + static const pgm_debug_key_t keys[] = { + { "gc-friendly", 1 }, + }; + + if (pgm_atomic_exchange_and_add32 (&mem_ref_count, 1) > 0) + return; + + const char *val = getenv ("PGM_DEBUG"); + const unsigned flags = !val ? 0 : pgm_parse_debug_string (val, keys, PGM_N_ELEMENTS (keys)); + if (flags & 1) + pgm_mem_gc_friendly = TRUE; +} + +void +pgm_mem_shutdown (void) +{ + pgm_return_if_fail (pgm_atomic_read32 (&mem_ref_count) > 0); + + if (pgm_atomic_exchange_and_add32 (&mem_ref_count, (uint32_t)-1) != 1) + return; + + /* nop */ +} + +/* malloc wrappers to hard fail */ +void* +pgm_malloc ( + const size_t n_bytes + ) +{ + if (PGM_LIKELY (n_bytes)) + { + void* mem = malloc (n_bytes); + if (mem) + return mem; + + pgm_fatal ("file %s: line %d (%s): failed to allocate %zu bytes", + __FILE__, __LINE__, __PRETTY_FUNCTION__, + n_bytes); + abort (); + } + return NULL; +} + +#define SIZE_OVERFLOWS(a,b) (PGM_UNLIKELY ((a) > SIZE_MAX / (b))) + +void* +pgm_malloc_n ( + const size_t n_blocks, + const size_t block_bytes + ) +{ + if (SIZE_OVERFLOWS (n_blocks, block_bytes)) { + pgm_fatal ("file %s: line %d (%s): overflow allocating %zu*%zu bytes", + __FILE__, __LINE__, __PRETTY_FUNCTION__, + n_blocks, block_bytes); + } + return pgm_malloc (n_blocks * block_bytes); +} + +void* +pgm_malloc0 ( + const size_t n_bytes + ) +{ + if (PGM_LIKELY (n_bytes)) + { + void* mem = calloc (1, n_bytes); + if (mem) + return mem; + + pgm_fatal ("file %s: line %d (%s): failed to allocate %zu bytes", + __FILE__, __LINE__, __PRETTY_FUNCTION__, + n_bytes); + abort (); + } + return NULL; +} + +void* +pgm_malloc0_n ( + const size_t n_blocks, + const size_t block_bytes + ) +{ + if (PGM_LIKELY (n_blocks && block_bytes)) + { + void* mem = calloc (n_blocks, block_bytes); + if (mem) + return mem; + + pgm_fatal ("file %s: line %d (%s): failed to allocate %zu*%zu bytes", + __FILE__, __LINE__, __PRETTY_FUNCTION__, + n_blocks, block_bytes); + abort (); + } + return NULL; +} + +void* +pgm_memdup ( + const void* mem, + const size_t n_bytes + ) +{ + void* new_mem; + + if (PGM_LIKELY (NULL != mem)) + { + new_mem = pgm_malloc (n_bytes); + memcpy (new_mem, mem, n_bytes); + } + else + new_mem = NULL; + + return new_mem; +} + +void* +pgm_realloc ( + void* mem, + const size_t n_bytes + ) +{ + return realloc (mem, n_bytes); +} + +void +pgm_free ( + void* mem + ) +{ + if (PGM_LIKELY (NULL != mem)) + free (mem); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/mem.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/mem.c.c89.patch new file mode 100644 index 0000000..5673af3 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/mem.c.c89.patch @@ -0,0 +1,145 @@ +--- mem.c 2010-05-23 16:49:21.000000000 +0800 ++++ mem.c89 2010-08-05 12:19:31.000000000 +0800 +@@ -78,16 +78,24 @@ + if (NULL == string) + return result; + ++/* C++ warning completely irrelevant for C */ ++#pragma warning( disable : 4996 ) + if (!strcasecmp (string, "all")) + { +- for (unsigned i = 0; i < nkeys; i++) ++ { ++ unsigned i; ++ for (i = 0; i < nkeys; i++) + result |= keys[i].value; ++ } + } + else if (!strcasecmp (string, "help")) + { + fprintf (stderr, "Supported debug values:"); +- for (unsigned i = 0; i < nkeys; i++) ++ { ++ unsigned i; ++ for (i = 0; i < nkeys; i++) + fprintf (stderr, " %s", keys[i].key); ++ } + fprintf (stderr, "\n"); + } + else +@@ -96,14 +104,18 @@ + const char* q = strpbrk (string, ":;, \t"); + if (!q) + q = string + strlen (string); +- for (unsigned i = 0; i < nkeys; i++) ++ { ++ unsigned i; ++ for (i = 0; i < nkeys; i++) + if (debug_key_matches (keys[i].key, string, q - string)) + result |= keys[i].value; ++ } + string = q; + if (*string) + string++; + } + } ++#pragma warning( default : 4996 ) + return result; + } + +@@ -117,10 +129,27 @@ + if (pgm_atomic_exchange_and_add32 (&mem_ref_count, 1) > 0) + return; + ++ { ++#ifdef _MSC_VER ++/* _dupenv_s is recommended replacement for getenv which is not thread-safe */ ++ char *val; ++ size_t len; ++ errno_t err; ++ unsigned flags; ++ err = _dupenv_s (&val, &len, "PGM_DEBUG"); ++ if (err || 0 == len) { ++ flags = 0; ++ } else { ++ flags = pgm_parse_debug_string (val, keys, PGM_N_ELEMENTS (keys)); ++ free (val); ++ } ++#else + const char *val = getenv ("PGM_DEBUG"); + const unsigned flags = !val ? 0 : pgm_parse_debug_string (val, keys, PGM_N_ELEMENTS (keys)); ++#endif + if (flags & 1) + pgm_mem_gc_friendly = TRUE; ++ } + } + + void +@@ -146,9 +175,15 @@ + if (mem) + return mem; + +- pgm_fatal ("file %s: line %d (%s): failed to allocate %zu bytes", ++#ifdef __PRETTY_FUNCTION__ ++ pgm_fatal ("file %s: line %d (%s): failed to allocate %lu bytes", + __FILE__, __LINE__, __PRETTY_FUNCTION__, + n_bytes); ++#else ++ pgm_fatal ("file %s: line %d): failed to allocate %lu bytes", ++ __FILE__, __LINE__, ++ n_bytes); ++#endif + abort (); + } + return NULL; +@@ -163,9 +198,15 @@ + ) + { + if (SIZE_OVERFLOWS (n_blocks, block_bytes)) { +- pgm_fatal ("file %s: line %d (%s): overflow allocating %zu*%zu bytes", ++#ifdef __PRETTY_FUNCTION__ ++ pgm_fatal ("file %s: line %d (%s): overflow allocating %lu*%lu bytes", + __FILE__, __LINE__, __PRETTY_FUNCTION__, + n_blocks, block_bytes); ++#else ++ pgm_fatal ("file %s: line %d: overflow allocating %lu*%lu bytes", ++ __FILE__, __LINE__, ++ n_blocks, block_bytes); ++#endif + } + return pgm_malloc (n_blocks * block_bytes); + } +@@ -181,9 +222,15 @@ + if (mem) + return mem; + +- pgm_fatal ("file %s: line %d (%s): failed to allocate %zu bytes", ++#ifdef __PRETTY_FUNCTION__ ++ pgm_fatal ("file %s: line %d (%s): failed to allocate %lu bytes", + __FILE__, __LINE__, __PRETTY_FUNCTION__, + n_bytes); ++#else ++ pgm_fatal ("file %s: line %d: failed to allocate %lu bytes", ++ __FILE__, __LINE__, ++ n_bytes); ++#endif + abort (); + } + return NULL; +@@ -201,9 +248,15 @@ + if (mem) + return mem; + +- pgm_fatal ("file %s: line %d (%s): failed to allocate %zu*%zu bytes", ++#ifdef __PRETTY_FUNCTION__ ++ pgm_fatal ("file %s: line %d (%s): failed to allocate %lu*%lu bytes", + __FILE__, __LINE__, __PRETTY_FUNCTION__, + n_blocks, block_bytes); ++#else ++ pgm_fatal ("file %s: line %d: failed to allocate %lu*%lu bytes", ++ __FILE__, __LINE__, ++ n_blocks, block_bytes); ++#endif + abort (); + } + return NULL; diff --git a/3rdparty/openpgm-svn-r1135/pgm/memcheck b/3rdparty/openpgm-svn-r1135/pgm/memcheck new file mode 100755 index 0000000..fbfe59c --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/memcheck @@ -0,0 +1,13 @@ +#!/bin/sh + +G_SLICE=always-malloc \ +G_DEBUG=gc-friendly \ + valgrind \ + -v \ + --tool=memcheck \ + --leak-check=full \ + --num-callers=40 \ + --gen-suppressions=no \ + --show-reachable=yes \ + --suppressions=valgrind.supp \ + $* diff --git a/3rdparty/openpgm-svn-r1135/pgm/messages.c b/3rdparty/openpgm-svn-r1135/pgm/messages.c new file mode 100644 index 0000000..2c13662 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/messages.c @@ -0,0 +1,173 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * basic message reporting. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + + +/* globals */ + +/* bit mask for trace role modules */ +int pgm_log_mask PGM_GNUC_READ_MOSTLY = 0xffff; +int pgm_min_log_level PGM_GNUC_READ_MOSTLY = PGM_LOG_LEVEL_NORMAL; + + +/* locals */ + +static const char log_levels[8][7] = { + "Uknown", + "Debug", + "Trace", + "Minor", + "Info", + "Warn", + "Error", + "Fatal" +}; + +static volatile uint32_t messages_ref_count = 0; +static pgm_mutex_t messages_mutex; +static pgm_log_func_t log_handler PGM_GNUC_READ_MOSTLY = NULL; +static void* log_handler_closure PGM_GNUC_READ_MOSTLY = NULL; + +static inline const char* log_level_text (const int) PGM_GNUC_PURE; + + +static inline +const char* +log_level_text ( + const int log_level + ) +{ + switch (log_level) { + default: return log_levels[0]; + case PGM_LOG_LEVEL_DEBUG: return log_levels[1]; + case PGM_LOG_LEVEL_TRACE: return log_levels[2]; + case PGM_LOG_LEVEL_MINOR: return log_levels[3]; + case PGM_LOG_LEVEL_NORMAL: return log_levels[4]; + case PGM_LOG_LEVEL_WARNING: return log_levels[5]; + case PGM_LOG_LEVEL_ERROR: return log_levels[6]; + case PGM_LOG_LEVEL_FATAL: return log_levels[7]; + } +} + +/* reference counted init and shutdown + */ + +void +pgm_messages_init (void) +{ + if (pgm_atomic_exchange_and_add32 (&messages_ref_count, 1) > 0) + return; + + pgm_mutex_init (&messages_mutex); + + const char* log_mask = getenv ("PGM_LOG_MASK"); + if (NULL != log_mask) { + unsigned int value = 0; + if (1 == sscanf (log_mask, "0x%4x", &value)) + pgm_log_mask = value; + } + const char *min_log_level = getenv ("PGM_MIN_LOG_LEVEL"); + if (NULL != min_log_level) { + switch (min_log_level[0]) { + case 'D': pgm_min_log_level = PGM_LOG_LEVEL_DEBUG; break; + case 'T': pgm_min_log_level = PGM_LOG_LEVEL_TRACE; break; + case 'M': pgm_min_log_level = PGM_LOG_LEVEL_MINOR; break; + case 'N': pgm_min_log_level = PGM_LOG_LEVEL_NORMAL; break; + case 'W': pgm_min_log_level = PGM_LOG_LEVEL_WARNING; break; + case 'E': pgm_min_log_level = PGM_LOG_LEVEL_ERROR; break; + case 'F': pgm_min_log_level = PGM_LOG_LEVEL_FATAL; break; + default: break; + } + } +} + +void +pgm_messages_shutdown (void) +{ + pgm_return_if_fail (pgm_atomic_read32 (&messages_ref_count) > 0); + + if (pgm_atomic_exchange_and_add32 (&messages_ref_count, (uint32_t)-1) != 1) + return; + + pgm_mutex_free (&messages_mutex); +} + +/* set application handler for log messages, returns previous value, + * default handler value is NULL. + */ + +pgm_log_func_t +pgm_log_set_handler ( + pgm_log_func_t handler, + void* closure + ) +{ + pgm_log_func_t previous_handler; + pgm_mutex_lock (&messages_mutex); + previous_handler = log_handler; + log_handler = handler; + log_handler_closure = closure; + pgm_mutex_unlock (&messages_mutex); + return previous_handler; +} + +void +pgm__log ( + const int log_level, + const char* format, + ... + ) +{ + va_list args; + + va_start (args, format); + pgm__logv (log_level, format, args); + va_end (args); +} + +void +pgm__logv ( + const int log_level, + const char* format, + va_list args + ) +{ + char tbuf[ 1024 ]; + + pgm_mutex_lock (&messages_mutex); + const int offset = sprintf (tbuf, "%s: ", log_level_text (log_level)); + vsnprintf (tbuf+offset, sizeof(tbuf)-offset, format, args); + tbuf[ sizeof(tbuf) ] = '\0'; + if (log_handler) + log_handler (log_level, tbuf, log_handler_closure); + else { +/* ignore return value */ + write (STDOUT_FILENO, tbuf, strlen (tbuf)); + write (STDOUT_FILENO, "\n", 1); + } + + pgm_mutex_unlock (&messages_mutex); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/messages.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/messages.c.c89.patch new file mode 100644 index 0000000..157bd40 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/messages.c.c89.patch @@ -0,0 +1,91 @@ +--- messages.c 2010-05-23 16:50:35.000000000 +0800 ++++ messages.c89 2010-08-05 12:18:49.000000000 +0800 +@@ -19,6 +19,9 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + ++#ifdef _MSC_VER ++# include ++#endif + #include + #include + #include +@@ -81,14 +84,37 @@ + + pgm_mutex_init (&messages_mutex); + ++ { ++#ifdef _MSC_VER ++ char* log_mask; ++ size_t len; ++ errno_t err = _dupenv_s (&log_mask, &len, "PGM_LOG_MASK"); ++ if (!err && len > 0) { ++ unsigned int value = 0; ++ if (1 == sscanf_s (log_mask, "0x%4x", &value)) ++ pgm_log_mask = value; ++ free (log_mask); ++ } ++#else + const char* log_mask = getenv ("PGM_LOG_MASK"); + if (NULL != log_mask) { + unsigned int value = 0; + if (1 == sscanf (log_mask, "0x%4x", &value)) + pgm_log_mask = value; + } ++#endif ++ } ++ { ++#ifdef _MSC_VER ++ char *min_log_level; ++ size_t len; ++ errno_t err = _dupenv_s (&min_log_level, &len, "PGM_MIN_LOG_LEVEL"); ++ if (!err && len > 0) ++#else + const char *min_log_level = getenv ("PGM_MIN_LOG_LEVEL"); +- if (NULL != min_log_level) { ++ if (NULL != min_log_level) ++#endif ++ { + switch (min_log_level[0]) { + case 'D': pgm_min_log_level = PGM_LOG_LEVEL_DEBUG; break; + case 'T': pgm_min_log_level = PGM_LOG_LEVEL_TRACE; break; +@@ -99,6 +125,10 @@ + case 'F': pgm_min_log_level = PGM_LOG_LEVEL_FATAL; break; + default: break; + } ++#ifdef _MSC_VER ++ free (min_log_level); ++#endif ++ } + } + } + +@@ -156,15 +186,28 @@ + char tbuf[ 1024 ]; + + pgm_mutex_lock (&messages_mutex); ++ { ++#ifdef _MSC_VER ++ const int offset = sprintf_s (tbuf, sizeof(tbuf), "%s: ", log_level_text (log_level)); ++ vsnprintf_s (tbuf+offset, sizeof(tbuf)-offset, _TRUNCATE, format, args); ++#else + const int offset = sprintf (tbuf, "%s: ", log_level_text (log_level)); + vsnprintf (tbuf+offset, sizeof(tbuf)-offset, format, args); + tbuf[ sizeof(tbuf) ] = '\0'; ++#endif ++ } + if (log_handler) + log_handler (log_level, tbuf, log_handler_closure); + else { + /* ignore return value */ ++#ifdef _MSC_VER ++ const int stdoutfd = _fileno (stdout); ++ _write (stdoutfd, tbuf, strlen (tbuf)); ++ _write (stdoutfd, "\n", 1); ++#else + write (STDOUT_FILENO, tbuf, strlen (tbuf)); + write (STDOUT_FILENO, "\n", 1); ++#endif + } + + pgm_mutex_unlock (&messages_mutex); diff --git a/3rdparty/openpgm-svn-r1135/pgm/mibs/PGM-MIB-petrova-01.txt b/3rdparty/openpgm-svn-r1135/pgm/mibs/PGM-MIB-petrova-01.txt new file mode 100644 index 0000000..28ff72c --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/mibs/PGM-MIB-petrova-01.txt @@ -0,0 +1,5459 @@ +---------------------------------------------------------------- +-- +-- Pragmatic General Multicast (PGM) MIB +-- +---------------------------------------------------------------- +-- +-- +-- Full MIB for the PGM protocol incorporating Network Element +-- (router), source, receiver and DLR functionality +-- +-- extracted from draft-petrova-pgmmib-01.txt + +PGM-MIB DEFINITIONS ::= BEGIN +IMPORTS + OBJECT-TYPE, Counter32, Integer32, Unsigned32, NOTIFICATION-TYPE, + MODULE-IDENTITY, IpAddress, TimeTicks, experimental, BITS + FROM SNMPv2-SMI + MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP + FROM SNMPv2-CONF + InterfaceIndex + FROM IF-MIB; + +pgmMIB MODULE-IDENTITY + LAST-UPDATED "200205010000Z" + ORGANIZATION + "Cisco Systems + Tibco Software Inc + Nortel Networks" + CONTACT-INFO + " Richard Edmonstone + redmonst@cisco.com + +44 131 561 3621 + Cisco Systems, Inc. + 170 West Tasman Drive, + San Jose, CA 95134 + USA + + Rajiv Raghunarayan + raraghun@cisco.com + +91 80 532 1300 + Cisco Systems, Inc. + 170 West Tasman Drive, + San Jose, CA 95134 + USA + + Devendra Raut + draut@nortelnetworks.com + (408)495-2859 + Nortel Networks + 4401 Great America Parkway, + Santa Clara, CA 95052 + + Moses Sun + mosun@nortelnetworks.com + (979)694-7156 + Nortel Networks + 4401 Great America Parkway + Santa Clara, CA, + USA + + Todd L. Montgomery + tmontgomery@tibco.com + (304)291-5972 + Tibco Software Inc. + 29W110 Butterfield Rd, Suite 205 + Warrenville, IL 60555 + USA + + Michael Garwood + mgarwood@tibco.com + (630)393-7363 ext.275 + Tibco Software Inc. + 29W110 Butterfield Rd, Suite 205 + Warrenville, IL 60555 + USA + + Luna Petrova + lpetrova@tibco.com + (630)393-7363 ext.330 + Tibco Software Inc. + 29W110 Butterfield Rd, Suite 205 + Warrenville, IL 60555 + USA" + DESCRIPTION + "The MIB module for managing PGM implementations." + REVISION "200205010000Z" + DESCRIPTION + "Rev 2.0: SNMP Notifications added to the MIB." + ::= { experimental 112 } -- assigned by IANA. + +pgm OBJECT IDENTIFIER ::= { pgmMIB 1 } +pgmNetworkElement OBJECT IDENTIFIER ::= { pgm 1 } +pgmSource OBJECT IDENTIFIER ::= { pgm 2 } +pgmReceiver OBJECT IDENTIFIER ::= { pgm 3 } +pgmDLR OBJECT IDENTIFIER ::= { pgm 4 } +pgmNotificationPrefix OBJECT IDENTIFIER ::= { pgmMIB 2 } + +-- PGM Network Element + +pgmNeEnable OBJECT-TYPE + SYNTAX INTEGER { + enable(1), + disable(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Enable/Disable Parameter indicates whether + this PGM operation is enabled or disabled." + DEFVAL { enable } + ::= { pgmNetworkElement 1 } + +pgmNeSessionLifeTime OBJECT-TYPE + SYNTAX Unsigned32(0..2147483647) + UNITS "seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The length of the idle time (seconds) following + which a PGM session will be aged out. An idle PGM + session means there is no SPM message received + from the upstream. + Value of 0 indicates no timeout." + DEFVAL { 300 } + ::= { pgmNetworkElement 2 } + +pgmNeMaxReXmitStates OBJECT-TYPE + SYNTAX Integer32(-2..2147483647) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The Maximum number of retransmission state entries. + The value of -1 means network element has no + limitation. + The value of -2 means not supported by this + implementation." + ::= { pgmNetworkElement 3 } + +pgmNeMaxSessions OBJECT-TYPE + SYNTAX Integer32(-2..2147483647) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The maximum number of state sessions supported. + The value of -1 means network element has no + limitation. + The value of -2 means not supported by this + implementation." + ::= { pgmNetworkElement 4 } + +-- The PGM NE Network Interface + +-- The PGM NE Network Interface tables contain +-- per-interface information about the PGM protocol. +-- The information is grouped into three major categories: +-- fault, configuration and performance management. + +pgmNeInterface OBJECT IDENTIFIER ::= { pgmNetworkElement 100 } + +pgmNeTotalInterfacesNumberOfEntries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of entries in the PGM Interface + table." + ::= { pgmNeInterface 1 } + +-- The PGM NE Network Interface configuration table + +pgmNeIfConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmNeIfConfigEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per interface configuration + information relating to PGM Network Element + operation." + ::= {pgmNeInterface 3} + +pgmNeIfConfigEntry OBJECT-TYPE + SYNTAX PgmNeIfConfigEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per Interface Configuration Information." + INDEX { pgmNeIfConfigIndex } + ::= { pgmNeIfConfigTable 1 } + +PgmNeIfConfigEntry ::= SEQUENCE { + pgmNeIfConfigIndex + InterfaceIndex, + pgmNeIfPgmEnable + INTEGER, + pgmNeIfNakRptInterval + Unsigned32, + pgmNeIfNakRptRate + Unsigned32, + pgmNeIfNakRdataInterval + Unsigned32, + pgmNeIfNakEliminateInterval + Unsigned32 + } + +pgmNeIfConfigIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A unique value for each interface. Its value + ranges between 1 and the value of ifNumber. The + value for each interface must remain constant at + least from one re-initialization of the entity's + network management system to the next + re-initialization." + ::= { pgmNeIfConfigEntry 1 } + +pgmNeIfPgmEnable OBJECT-TYPE + SYNTAX INTEGER { + enable(1), + disable(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Allows PGM to be enabled and disabled per + Network Interface. + + PGM can be enabled or disabled per Network + Interface, only if PGM is enabled for this + Network Element." + ::= { pgmNeIfConfigEntry 2 } + +pgmNeIfNakRptInterval OBJECT-TYPE + SYNTAX Unsigned32(1..4294967295) + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The length of time (milliseconds) for which a + network element will repeat a NAK while waiting + for a corresponding NCF. This interval is counted + down from the transmission of a NAK." + DEFVAL { 100 } + ::= { pgmNeIfConfigEntry 3 } + +pgmNeIfNakRptRate OBJECT-TYPE + SYNTAX Unsigned32(1..4294967295) + UNITS "number of NAKs per second" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The rate at which NAKs are repeated." + DEFVAL { 2 } + ::= { pgmNeIfConfigEntry 4 } + +pgmNeIfNakRdataInterval OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The length of time (milliseconds) for which + a network element will wait for the + corresponding RDATA. This interval is counted + down from the time a matching NCF is received. + This value must be greater than the + pgmNeIfNakEliminateInterval." + DEFVAL { 10000 } + ::= { pgmNeIfConfigEntry 5 } + +pgmNeIfNakEliminateInterval OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The length of time (milliseconds) for which + a network element will eliminate NAKs for + a specific TSI/SQN. This interval is counted + down from the time the first NAK is + established. This value must + be smaller than pgmNeIfNakRdataInterval." + DEFVAL { 5000 } + ::= { pgmNeIfConfigEntry 6 } + +-- The PGM NE Interface performance table. +-- This is primarily statistical information +-- about packets received and sent on the interface + +pgmNeIfPerformanceTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmNeIfPerformanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per interface performance + information related to PGM Network Element + operation." + ::= {pgmNeInterface 4} + +pgmNeIfPerformanceEntry OBJECT-TYPE + SYNTAX PgmNeIfPerformanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per Interface Information for Network Elements." + INDEX { pgmNeIfPerformanceIndex } + ::= { pgmNeIfPerformanceTable 1 } + +PgmNeIfPerformanceEntry ::= SEQUENCE { + pgmNeIfPerformanceIndex + InterfaceIndex, + pgmNeIfReXmitStates + Counter32, + pgmNeIfReXmitTimedOut + Counter32, + pgmNeIfInSpms + Counter32, + pgmNeIfOutSpms + Counter32, + pgmNeIfInParitySpms + Counter32, + pgmNeIfOutParitySpms + Counter32, + pgmNeIfInRdata + Counter32, + pgmNeIfOutRdata + Counter32, + pgmNeIfInParityRdata + Counter32, + pgmNeIfOutParityRdata + Counter32, + pgmNeIfInRdataNoSessionErrors + Counter32, + pgmNeIfUniqueNaks + Counter32, + pgmNeIfInNaks + Counter32, + pgmNeIfOutNaks + Counter32, + pgmNeIfUniqueParityNaks + Counter32, + pgmNeIfInParityNaks + Counter32, + pgmNeIfOutParityNaks + Counter32, + pgmNeIfInNakNoSessionErrors + Counter32, + pgmNeIfInNakSeqErrors + Counter32, + pgmNeIfInParityNakTgErrors + Counter32, + pgmNeIfInNnaks + Counter32, + pgmNeIfOutNnaks + Counter32, + pgmNeIfInParityNnaks + Counter32, + pgmNeIfOutParityNnaks + Counter32, + pgmNeIfInNnakNoSessionErrors + Counter32, + pgmNeIfInNcfs + Counter32, + pgmNeIfOutNcfs + Counter32, + pgmNeIfInParityNcfs + Counter32, + pgmNeIfOutParityNcfs + Counter32, + pgmNeIfInNcfNoSessionErrors + Counter32, + pgmNeIfInRedirectNcfs + Counter32, + pgmNeIfMalformed + Counter32, + pgmNeIfSpmFromSource + Counter32, + pgmNeIfSpmBadSqn + Counter32, + pgmNeIfSpmError + Counter32, + pgmNeIfPollRandomIgnore + Counter32, + pgmNeIfPollTsiStateError + Counter32, + pgmNeIfPollParentError + Counter32, + pgmNeIfPollTypeError + Counter32, + pgmNeIfPollError + Counter32, + pgmNeIfPollSuccess + Counter32, + pgmNeIfPollOriginated + Counter32, + pgmNeIfPolrNoState + Counter32, + pgmNeIfPolrError + Counter32, + pgmNeIfPolrParityError + Counter32, + pgmNeIfPolrSuccess + Counter32, + pgmNeIfPolrOriginated + Counter32, + pgmNeIfNcfError + Counter32, + pgmNeIfNcfParityError + Counter32, + pgmNeIfNcfPartialParity + Counter32, + pgmNeIfNcfReceived + Counter32, + pgmNeIfNcfAnticipated + Counter32, + pgmNeIfNcfRedirecting + Counter32, + pgmNeIfNakEliminated + Counter32, + pgmNeIfNakError + Counter32, + pgmNeIfNakParityError + Counter32, + pgmNeIfNNakEliminated + Counter32, + pgmNeIfNNakError + Counter32, + pgmNeIfNNakParityError + Counter32, + pgmNeIfNNakCongestionReports + Counter32, + pgmNeIfNakRetryExpired + Counter32, + pgmNeIfNakRetryExpiredDLR + Counter32, + pgmNeIfNakForwardedDLR + Counter32, + pgmNeIfNakRetransmitted + Counter32, + pgmNeIfRdataEliminatedOIF + Counter32, + pgmNeIfRdataEliminatedSqn + Counter32, + pgmNeIfInRdataFragments + Counter32, + pgmNeIfRdataFragmentsNoSessionErrors + Counter32, + pgmNeIfRdataFragmentsEliminatedOIF + Counter32, + pgmNeIfRdataFragmentsEliminatedSqn + Counter32, + pgmNeIfOutRdataFragments + Counter32 +} + +pgmNeIfPerformanceIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A unique value for each interface. Its value + ranges between 1 and the value of ifNumber. + The value for each interface must remain + constant at least from one re-initialization + of the entity's network management system + to the next re-initialization." + ::= { pgmNeIfPerformanceEntry 1 } + +pgmNeIfReXmitStates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total retransmit state entries for this + interface." + ::= { pgmNeIfPerformanceEntry 2 } + +pgmNeIfReXmitTimedOut OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of timed-out retransmit state + entries for this interface." + ::= { pgmNeIfPerformanceEntry 3 } + +pgmNeIfInSpms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of SPMs received on the PGM + interface." + ::= { pgmNeIfPerformanceEntry 4 } + +pgmNeIfOutSpms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of SPMs sent out from the PGM + interface." + ::= { pgmNeIfPerformanceEntry 5 } + +pgmNeIfInParitySpms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity SPMs received on the + PGM interface." + ::= { pgmNeIfPerformanceEntry 6 } + +pgmNeIfOutParitySpms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity SPMs sent out from the + PGM interface." + ::= { pgmNeIfPerformanceEntry 7 } + +pgmNeIfInRdata OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of RDATA received on the PGM + interface." + ::= { pgmNeIfPerformanceEntry 8 } + +pgmNeIfOutRdata OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of RDATA sent out from the + PGM interface." + ::= { pgmNeIfPerformanceEntry 9 } + +pgmNeIfInParityRdata OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity RDATA received on the + PGM interface." + ::= { pgmNeIfPerformanceEntry 10 } + +pgmNeIfOutParityRdata OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity RDATA sent out from + the PGM interface." + ::= { pgmNeIfPerformanceEntry 11 } + +pgmNeIfInRdataNoSessionErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of received RDATA discarded because + of no session." + ::= { pgmNeIfPerformanceEntry 12 } + +pgmNeIfUniqueNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of unique NAKs received on + this interface." + ::= { pgmNeIfPerformanceEntry 13 } + +pgmNeIfInNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NAKs received on the PGM + interface." + ::= { pgmNeIfPerformanceEntry 14 } + +pgmNeIfOutNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NAKs sent out from the + PGM interface." + ::= { pgmNeIfPerformanceEntry 15 } + +pgmNeIfUniqueParityNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of unique parity NAKs received + on this interface." + ::= { pgmNeIfPerformanceEntry 16 } + +pgmNeIfInParityNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity NAKs received on the + PGM interface." + ::= { pgmNeIfPerformanceEntry 17 } + +pgmNeIfOutParityNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity NAKs sent out from + the PGM interface." + ::= { pgmNeIfPerformanceEntry 18 } + +pgmNeIfInNakNoSessionErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of received NAKs discarded because of + no session." + ::= { pgmNeIfPerformanceEntry 19 } + +pgmNeIfInNakSeqErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of received NAKs discarded because + of out of sequence (out of retransmit window)." + ::= { pgmNeIfPerformanceEntry 20 } + +pgmNeIfInParityNakTgErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of received parity NAKs discarded + because out of parity TG window." + ::= { pgmNeIfPerformanceEntry 21 } + +pgmNeIfInNnaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NNAKs received on the PGM + interface." + ::= { pgmNeIfPerformanceEntry 22 } + +pgmNeIfOutNnaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NNAKs sent out from the + PGM interface." + ::= { pgmNeIfPerformanceEntry 23 } + +pgmNeIfInParityNnaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity NNAKs received on + the PGM interface." + ::= { pgmNeIfPerformanceEntry 24 } + +pgmNeIfOutParityNnaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity NNAKs sent out from + the PGM interface." + ::= { pgmNeIfPerformanceEntry 25 } + +pgmNeIfInNnakNoSessionErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of received NNAKs discarded because + of no session." + ::= { pgmNeIfPerformanceEntry 26 } + +pgmNeIfInNcfs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NCFs received on the PGM + interface." + ::= { pgmNeIfPerformanceEntry 27 } + +pgmNeIfOutNcfs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NCFs sent out from the PGM + interface." + ::= { pgmNeIfPerformanceEntry 28 } + +pgmNeIfInParityNcfs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity NCFs received on the + PGM interface." + ::= { pgmNeIfPerformanceEntry 29 } + +pgmNeIfOutParityNcfs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity NCFs sent out from + the PGM interface." + ::= { pgmNeIfPerformanceEntry 30 } + +pgmNeIfInNcfNoSessionErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of received NCFs discarded because + of no session." + ::= { pgmNeIfPerformanceEntry 31 } + +pgmNeIfInRedirectNcfs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of redirected NCFs received on the + PGM interface." + ::= { pgmNeIfPerformanceEntry 32 } + +pgmNeIfMalformed OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of malformed PGM packets." + ::= { pgmNeIfPerformanceEntry 33 } + +pgmNeIfSpmFromSource OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of SPM packets received from source." + ::= { pgmNeIfPerformanceEntry 34 } + +pgmNeIfSpmBadSqn OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of SPM packets discarded due to bad + SQN." + ::= { pgmNeIfPerformanceEntry 35 } + +pgmNeIfSpmError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of SPM packets discarded due to + operational error. Some examples of operational + errors are failure to create TSI state for SPM, + parity SPM for a TSI with no parity." + ::= { pgmNeIfPerformanceEntry 36 } + +pgmNeIfPollRandomIgnore OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of POLL packets not replied due to random + condition failing." + ::= { pgmNeIfPerformanceEntry 37 } + +pgmNeIfPollTsiStateError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of POLL packets discarded due to no + matching TSI state." + ::= { pgmNeIfPerformanceEntry 38 } + +pgmNeIfPollParentError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of POLL packets discarded due to + unknown parent." + ::= { pgmNeIfPerformanceEntry 39 } + +pgmNeIfPollTypeError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of POLL packets discarded due to failed + type matching." + ::= { pgmNeIfPerformanceEntry 40 } + +pgmNeIfPollError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of POLL packets discarded due to + operational error." + ::= { pgmNeIfPerformanceEntry 41 } + +pgmNeIfPollSuccess OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of successfully scheduled POLRs." + ::= { pgmNeIfPerformanceEntry 42 } + +pgmNeIfPollOriginated OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of polls originated on this interface." + ::= { pgmNeIfPerformanceEntry 43 } + +pgmNeIfPolrNoState OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of POLRs discarded due to no matching + state." + ::= { pgmNeIfPerformanceEntry 44 } + +pgmNeIfPolrError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of POLRs discarded due to operational + error." + ::= { pgmNeIfPerformanceEntry 45 } + +pgmNeIfPolrParityError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of parity POLRs received for non-parity + TSI." + ::= { pgmNeIfPerformanceEntry 46 } + +pgmNeIfPolrSuccess OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of POLRs recorded successfully." + ::= { pgmNeIfPerformanceEntry 47 } + +pgmNeIfPolrOriginated OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of POLRs originated by this interface." + ::= { pgmNeIfPerformanceEntry 48 } + +pgmNeIfNcfError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NCFs ignored due to no packet memory, + due to packet processing errors." + ::= { pgmNeIfPerformanceEntry 49 } + +pgmNeIfNcfParityError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NCFs ignored. Incremented when a parity + NCF is received on a session for which no parity + capability has been advertised in the session's + SPMs." + ::= { pgmNeIfPerformanceEntry 50 } + +pgmNeIfNcfPartialParity OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NCFs ignored due to not enough parity + blocks acknowledged." + ::= { pgmNeIfPerformanceEntry 51 } + +pgmNeIfNcfReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NCFs that confirm an outstanding NAK." + ::= { pgmNeIfPerformanceEntry 52 } + +pgmNeIfNcfAnticipated OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NCFs that cause NAK anticipation." + ::= { pgmNeIfPerformanceEntry 53 } + +pgmNeIfNcfRedirecting OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NCFs received as consequence of + redirected NAK." + ::= { pgmNeIfPerformanceEntry 54 } + +pgmNeIfNakEliminated OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAKs eliminated by retransmission + state." + ::= { pgmNeIfPerformanceEntry 55 } + +pgmNeIfNakError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of errors creating retransmission state + or NAK, due to NAK packet processing." + ::= { pgmNeIfPerformanceEntry 56 } + +pgmNeIfNakParityError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAKs ignored, due to no parity + available. Incremented when parity NAK is + received on this session, for which no parity + capability has been advartised." + ::= { pgmNeIfPerformanceEntry 57 } + +pgmNeIfNNakEliminated OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NNAKs eliminated by retransmission + state." + ::= { pgmNeIfPerformanceEntry 58 } + +pgmNeIfNNakError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of errors encountered creating + retransmission state OR nak." + ::= { pgmNeIfPerformanceEntry 59 } + +pgmNeIfNNakParityError OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of Null NAKs ignored, due to no parity + available. Incremented when parity NNAK is + received on this session, for which no parity + capability has been advartised." + ::= { pgmNeIfPerformanceEntry 60 } + +pgmNeIfNNakCongestionReports OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAKs forwarded as NNAK as congestion + report only." + ::= { pgmNeIfPerformanceEntry 61 } + +pgmNeIfNakRetryExpired OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NAKs timed out after + retrying." + ::= { pgmNeIfPerformanceEntry 62 } + +pgmNeIfNakRetryExpiredDLR OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAKs unconfirmed by DLR." + ::= { pgmNeIfPerformanceEntry 63 } + +pgmNeIfNakForwardedDLR OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAKs forwarded out this i/f to DLR + with retransmission state." + ::= { pgmNeIfPerformanceEntry 64 } + +pgmNeIfNakRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of NAKs retransmitted out this i/f." + ::= { pgmNeIfPerformanceEntry 65 } + +pgmNeIfRdataEliminatedOIF OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of RDATA packets eliminated by lack of + OIF's." + ::= { pgmNeIfPerformanceEntry 66 } + +pgmNeIfRdataEliminatedSqn OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of RDATA packets eliminated by lack of + SQN." + ::= { pgmNeIfPerformanceEntry 67 } + +pgmNeIfInRdataFragments OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of RDATA fragments received." + ::= { pgmNeIfPerformanceEntry 68 } + +pgmNeIfRdataFragmentsNoSessionErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of RDATA fragments eliminated by lack of + GSI." + ::= { pgmNeIfPerformanceEntry 69 } + +pgmNeIfRdataFragmentsEliminatedOIF OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of RDATA fragments eliminated by lack of + OIFs." + ::= { pgmNeIfPerformanceEntry 70 } + +pgmNeIfRdataFragmentsEliminatedSqn OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of RDATA fragments eliminated by lack of + SQN." + ::= { pgmNeIfPerformanceEntry 71 } + +pgmNeIfOutRdataFragments OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of RDATA fragments forwarded." + ::= { pgmNeIfPerformanceEntry 72 } + +-- +-- PGM Network Element Transport Session Identifier +-- +pgmNeTsi OBJECT IDENTIFIER ::= { pgmNetworkElement 101 } + +pgmNeTotalTsiNumberOfEntries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of sessions in the PGM NE TSI + table." + ::= { pgmNeTsi 1 } + +-- The PGM Transport Session Identifier (TSI) table +-- The TSI information is grouped into three major categories: +-- fault, configuration and performance management. + +-- The PGM NE TSI fault management table +-- This table contains state and some general +-- per TSI information + +pgmNeTsiTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmNeTsiEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per-tsi state information." + ::= {pgmNeTsi 2} + +pgmNeTsiEntry OBJECT-TYPE + SYNTAX PgmNeTsiEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Transport Session is identified by Global ID and + Source Port." + INDEX { pgmNeTsiGlobalId, pgmNeTsiDataSourcePort } + ::= { pgmNeTsiTable 1 } + +PgmNeTsiEntry ::= SEQUENCE { + pgmNeTsiGlobalId + OCTET STRING, + pgmNeTsiDataSourcePort + Unsigned32, + pgmNeTsiStateBits + BITS, + pgmNeTsiDataDestinationPort + Unsigned32, + pgmNeTsiSourceAddress + IpAddress, + pgmNeTsiGroupAddress + IpAddress, + pgmNeTsiUpstreamAddress + IpAddress, + pgmNeTsiUpstreamIfIndex + InterfaceIndex, + pgmNeTsiDlrAddress + IpAddress + } + +pgmNeTsiGlobalId OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Globally unique source identifier for this + transport session." + ::= {pgmNeTsiEntry 1 } + +pgmNeTsiDataSourcePort OBJECT-TYPE + SYNTAX Unsigned32 (0..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Data source port." + ::= {pgmNeTsiEntry 2} + +pgmNeTsiStateBits OBJECT-TYPE + SYNTAX BITS { initialising(0), + spmSqnStateValid(1), + dlrCanProvideParity(2) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "State associated with the TSI." + ::= {pgmNeTsiEntry 3 } + +pgmNeTsiDataDestinationPort OBJECT-TYPE + SYNTAX Unsigned32 (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Data destination port." + ::= {pgmNeTsiEntry 4 } + +pgmNeTsiSourceAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "IP address of the source." + ::= {pgmNeTsiEntry 5 } + +pgmNeTsiGroupAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Multicast group destination address." + ::= {pgmNeTsiEntry 6 } + +pgmNeTsiUpstreamAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The IP address of the upstream PGM neighbouring + element for this TSI." + ::= { pgmNeTsiEntry 7 } + +pgmNeTsiUpstreamIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The index of the upstream PGM element for the + entry." + ::= { pgmNeTsiEntry 8 } + +pgmNeTsiDlrAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "IP Address of a known DLR that will be used if + required." + ::= {pgmNeTsiEntry 9 } + + +-- PGM Network Element TSI Configuration Management Table +-- Since the Network Element cannot be configured +-- per TSI, configuration table is not implemented + + +-- PGM Network Element TSI Performance Management Table + +pgmNeTsiPerformanceTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmNeTsiPerformanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding details of every transport + flow known by the Network Element." + ::= {pgmNeTsi 4} + +pgmNeTsiPerformanceEntry OBJECT-TYPE + SYNTAX PgmNeTsiPerformanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Transport session description." + INDEX { pgmNeTsiPerformanceGlobalId, + pgmNeTsiPerformanceDataSourcePort } + ::= { pgmNeTsiPerformanceTable 1 } + +PgmNeTsiPerformanceEntry ::= SEQUENCE { + pgmNeTsiPerformanceGlobalId + OCTET STRING, + pgmNeTsiPerformanceDataSourcePort + Unsigned32, + pgmNeTsiSessionTrailEdgeSeq + Counter32, + pgmNeTsiSessionIncrSeq + Counter32, + pgmNeTsiLeadEdgeSeq + Counter32, + pgmNeTsiInSpms + Counter32, + pgmNeTsiOutSpms + Counter32, + pgmNeTsiInParitySpms + Counter32, + pgmNeTsiOutParitySpms + Counter32, + pgmNeTsiTotalReXmitStates + Counter32, + pgmNeTsiTotalReXmitTimedOut + Counter32, + pgmNeTsiInRdata + Counter32, + pgmNeTsiOutRdata + Counter32, + pgmNeTsiInParityRdata + Counter32, + pgmNeTsiOutParityRdata + Counter32, + pgmNeTsiInRdataNoStateErrors + Counter32, + pgmNeTsiUniqueNaks + Counter32, + pgmNeTsiInNaks + Counter32, + pgmNeTsiOutNaks + Counter32, + pgmNeTsiUniqueParityNaks + Counter32, + pgmNeTsiInParityNaks + Counter32, + pgmNeTsiOutParityNaks + Counter32, + pgmNeTsiInNakSeqErrors + Counter32, + pgmNeTsiInNnaks + Counter32, + pgmNeTsiOutNnaks + Counter32, + pgmNeTsiInParityNnaks + Counter32, + pgmNeTsiOutParityNnaks + Counter32, + pgmNeTsiInNcfs + Counter32, + pgmNeTsiOutNcfs + Counter32, + pgmNeTsiInParityNcfs + Counter32, + pgmNeTsiOutParityNcfs + Counter32, + pgmNeTsiSpmSequenceNumber + Unsigned32, + pgmNeTsiTransmissionGroupSize + Unsigned32, + pgmNeTsiTimeout + TimeTicks, + pgmNeTsiLastTtl + Unsigned32, + pgmNeTsiLinkLossRate + Unsigned32, + pgmNeTsiPathLossRate + Unsigned32, + pgmNeTsiReceiverLossRate + Unsigned32, + pgmNeTsiCongestionReportLead + Unsigned32, + pgmNeTsiCongestionReportWorstReceiver + IpAddress +} + +pgmNeTsiPerformanceGlobalId OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The Globally unique source identifier for this + transport session." + ::= {pgmNeTsiPerformanceEntry 1 } + +pgmNeTsiPerformanceDataSourcePort OBJECT-TYPE + SYNTAX Unsigned32 (0..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Data source port." + ::= {pgmNeTsiPerformanceEntry 2} + +pgmNeTsiSessionTrailEdgeSeq OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The trailing edge sequence of the transmit + window." + ::= { pgmNeTsiPerformanceEntry 3 } + +pgmNeTsiSessionIncrSeq OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The sequence number defining the leading edge of + the increment window." + ::= { pgmNeTsiPerformanceEntry 4 } + +pgmNeTsiLeadEdgeSeq OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The leading edge sequence of the transmit + window." + ::= { pgmNeTsiPerformanceEntry 5 } + +pgmNeTsiInSpms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of SPMs received for this + session." + ::= { pgmNeTsiPerformanceEntry 6 } + +pgmNeTsiOutSpms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of SPMs sent out for this + session." + ::= { pgmNeTsiPerformanceEntry 7 } + +pgmNeTsiInParitySpms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Parity SPMs received for + this session." + ::= { pgmNeTsiPerformanceEntry 8 } + +pgmNeTsiOutParitySpms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Parity SPMs sent out for + this session." + ::= { pgmNeTsiPerformanceEntry 9 } + +pgmNeTsiTotalReXmitStates OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total retransmit states for this session." + ::= { pgmNeTsiPerformanceEntry 10 } + +pgmNeTsiTotalReXmitTimedOut OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total timed-out retransmit state entries for + this session." + ::= { pgmNeTsiPerformanceEntry 11 } + +pgmNeTsiInRdata OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of RDATAs received for this + session." + ::= { pgmNeTsiPerformanceEntry 12 } + +pgmNeTsiOutRdata OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of RDATAs sent out from this + session." + ::= { pgmNeTsiPerformanceEntry 13 } + +pgmNeTsiInParityRdata OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity RDATAs received for + this session." + ::= { pgmNeTsiPerformanceEntry 14 } + +pgmNeTsiOutParityRdata OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity RDATAs sent out from + this session." + ::= { pgmNeTsiPerformanceEntry 15 } + +pgmNeTsiInRdataNoStateErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of received RDATA discarded + due to no retransmit state." + ::= { pgmNeTsiPerformanceEntry 16 } + +pgmNeTsiUniqueNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of unique NAKs received for + this session." + ::= { pgmNeTsiPerformanceEntry 17 } + +pgmNeTsiInNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NAKs received for this + session." + ::= { pgmNeTsiPerformanceEntry 18 } + +pgmNeTsiOutNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NAKs sent out from this + session." + ::= { pgmNeTsiPerformanceEntry 19 } + +pgmNeTsiUniqueParityNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of unique parity NAKs received + for this session." + ::= { pgmNeTsiPerformanceEntry 20 } + +pgmNeTsiInParityNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity NAKs received for + this session." + ::= { pgmNeTsiPerformanceEntry 21 } + +pgmNeTsiOutParityNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity NAKs sent out from + this session." + ::= { pgmNeTsiPerformanceEntry 22 } + +pgmNeTsiInNakSeqErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of received NAKs discarded + because of out of sequence (out of retransmit + window)." + ::= { pgmNeTsiPerformanceEntry 23 } + +pgmNeTsiInNnaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NNAKs received for this + session." + ::= { pgmNeTsiPerformanceEntry 24 } + +pgmNeTsiOutNnaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NNAKs sent out from this + session." + ::= { pgmNeTsiPerformanceEntry 25 } + +pgmNeTsiInParityNnaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity NNAKs received for + this session." + ::= { pgmNeTsiPerformanceEntry 26 } + +pgmNeTsiOutParityNnaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity NNAKs sent out from + this session." + ::= { pgmNeTsiPerformanceEntry 27 } + +pgmNeTsiInNcfs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NCFs received for this + session." + ::= { pgmNeTsiPerformanceEntry 28 } + +pgmNeTsiOutNcfs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of NCFs sent out from this + session." + ::= { pgmNeTsiPerformanceEntry 29 } + +pgmNeTsiInParityNcfs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of parity NCFs received for + this session." + ::= { pgmNeTsiPerformanceEntry 30 } + +pgmNeTsiOutParityNcfs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of Parity NCFs sent out from + this session." + ::= { pgmNeTsiPerformanceEntry 31 } + +pgmNeTsiSpmSequenceNumber OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Sequence number of the last seen SPM." + ::= {pgmNeTsiPerformanceEntry 32 } + +pgmNeTsiTransmissionGroupSize OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Advertised size of the transmission group for + this transport session." + ::= {pgmNeTsiPerformanceEntry 33 } + +pgmNeTsiTimeout OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Time left for this entry to expire." + ::= {pgmNeTsiPerformanceEntry 34 } + +pgmNeTsiLastTtl OBJECT-TYPE + SYNTAX Unsigned32(1..255) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "IP TTL of last seen valid SPM." + ::= {pgmNeTsiPerformanceEntry 35 } + +pgmNeTsiLinkLossRate OBJECT-TYPE + SYNTAX Unsigned32(0..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Worst reported link loss rate for congestion + control. This is reported as a percentage." + ::= {pgmNeTsiPerformanceEntry 36 } + +pgmNeTsiPathLossRate OBJECT-TYPE + SYNTAX Unsigned32 (0..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Worst reported path loss rate for congestion + control. This is reported as a percentage." + ::= {pgmNeTsiPerformanceEntry 37 } + +pgmNeTsiReceiverLossRate OBJECT-TYPE + SYNTAX Unsigned32 (0..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Worst reported receiver loss rate for congestion + control. This is reported as a percentage." + ::= {pgmNeTsiPerformanceEntry 38 } + +pgmNeTsiCongestionReportLead OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Data lead sequence number associated with the + worst reported receiver loss rate." + ::= {pgmNeTsiPerformanceEntry 39 } + +pgmNeTsiCongestionReportWorstReceiver OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "IP address of the receiver that reported the + worst receiver loss rate." + ::= {pgmNeTsiPerformanceEntry 40 } + +-- The PGM Retransmission table + +-- The PGM Retransmission table contains +-- information about current retransmission requests. +-- This information is held per sequence number, or in +-- the case of FEC, every transmission group, for which +-- retransmission has been requested. + +pgmNeTsiRtxNumberOfEntries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of entries in the retransmission table." + ::= { pgmNeTsi 5 } + +pgmNeTsiRtxTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmNeTsiRtxEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding information for every sequence + number, or in the case of FEC, every + transmission group, for which retransmission has + been requested." + ::= {pgmNeTsi 6 } + +pgmNeTsiRtxEntry OBJECT-TYPE + SYNTAX PgmNeTsiRtxEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per sequence number / transmission group + information." + INDEX { pgmNeTsiGlobalId, + pgmNeTsiDataSourcePort, + pgmNeTsiRtxSequenceNumber, + pgmNeTsiRtxSequenceNumberType } + ::= { pgmNeTsiRtxTable 1 } + +PgmNeTsiRtxEntry ::= SEQUENCE { + pgmNeTsiRtxSequenceNumber + Unsigned32, + pgmNeTsiRtxSequenceNumberType + INTEGER, + pgmNeTsiRtxReqParityTgCount + Counter32, + pgmNeTsiRtxTimeout + TimeTicks, + pgmNeTsiRtxStateBits + BITS +} + +pgmNeTsiRtxSequenceNumber OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "For non-parity retransmission, a sequence number. + For parity retransmission, a transmission group + and packet count." + ::= {pgmNeTsiRtxEntry 1 } + +pgmNeTsiRtxSequenceNumberType OBJECT-TYPE + SYNTAX INTEGER { + selective(1), + tg(2) + } + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Selective Sequence Number and TG Sequence + Number." + ::= {pgmNeTsiRtxEntry 2 } + +pgmNeTsiRtxReqParityTgCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The Requested number of missing parity packets + of specific Tg. The largest counter of the + received NAK will be stored in this mib. This + variable is valid for parity packets only." + ::= { pgmNeTsiRtxEntry 4 } + +pgmNeTsiRtxTimeout OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "When this state will expire." + ::= {pgmNeTsiRtxEntry 5 } + +pgmNeTsiRtxStateBits OBJECT-TYPE + SYNTAX BITS { + initialising(0), + eliminating(1), + redirecting(2), + stateCreatedByNullNAK(3), + listNAKentry(4), + parityState(5) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "State associated with retransmission entry." + ::= {pgmNeTsiRtxEntry 6 } + +-- The PGM Retransmission interfaces table + +-- The PGM Retransmission interfaces table contains +-- information about what interfaces will be sent +-- retransmitted data for a particular +-- retransmission entry + +pgmNeTsiRtxIfNumberOfEntries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of entries in the retransmission + interfaces table." + ::= { pgmNeTsi 7 } + +pgmNeTsiRtxIfTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmNeTsiRtxIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding information of every + interface for which retransmit state for + a particular sequence number or transmission + group has to be sent." + ::= {pgmNeTsi 8} + +pgmNeTsiRtxIfEntry OBJECT-TYPE + SYNTAX PgmNeTsiRtxIfEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Destination interfaces for a particular + retransmit state." + INDEX { pgmNeTsiGlobalId, + pgmNeTsiDataSourcePort, + pgmNeTsiRtxSequenceNumber, + pgmNeTsiRtxSequenceNumberType, + pgmNeTsiRtxIfIndex } + ::= { pgmNeTsiRtxIfTable 1 } + +PgmNeTsiRtxIfEntry ::= SEQUENCE { + pgmNeTsiRtxIfIndex + InterfaceIndex, + pgmNeTsiRtxIfPacketCount + Counter32 +} + +pgmNeTsiRtxIfIndex OBJECT-TYPE + SYNTAX InterfaceIndex + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A unique value for each interface. Its value + ranges between 1 and the value of ifNumber. + The value for each interface must remain + constant at least from one re-initialization + of the entity's network management system to + the next re-initialization." + ::= { pgmNeTsiRtxIfEntry 1 } + +pgmNeTsiRtxIfPacketCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of repair data packets still to be + retransmitted on this interface. For non-parity + retransmission this will never have a value + greater than 1. For parity retransmission, + any number can be present." + ::= { pgmNeTsiRtxIfEntry 2 } + +-- The PGM Poll Response table + +-- The PGM Poll Response table contains information +-- about PGM parent's of this network element who are +-- currently polling it. + +pgmNeTsiPolrNumberOfEntries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of entries in the poll response table." + ::= { pgmNeTsi 9 } + +pgmNeTsiPolrTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmNeTsiPolrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding state information about what + PGM parents are polling this Network Element." + ::= { pgmNeTsi 10 } + +pgmNeTsiPolrEntry OBJECT-TYPE + SYNTAX PgmNeTsiPolrEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "State information for a Network Element that + is being polled by its parents" + INDEX { pgmNeTsiGlobalId, + pgmNeTsiDataSourcePort, + pgmNeTsiPolrSource } + ::= { pgmNeTsiPolrTable 1 } + +PgmNeTsiPolrEntry ::= SEQUENCE { + pgmNeTsiPolrSource + IpAddress, + pgmNeTsiPolrSequenceNumber + Unsigned32 +} + +pgmNeTsiPolrSource OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "IP Address of parent who is polling this + device." + ::= { pgmNeTsiPolrEntry 1 } + +pgmNeTsiPolrSequenceNumber OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Sequence number of last POLR from the source." + ::= { pgmNeTsiPolrEntry 2 } + +-- The PGM Poll table + +-- The PGM Poll table contains information related to +-- polling that this Network Element is doing for +-- its children + +pgmNeTsiPollNumberOfEntries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of entries in the poll table." + ::= { pgmNeTsi 11 } + +pgmNeTsiPollTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmNeTsiPollEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding state information related + to polling that this Network Element is doing + for its children." + ::= { pgmNeTsi 12 } + +pgmNeTsiPollEntry OBJECT-TYPE + SYNTAX PgmNeTsiPollEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "State information for a Network Element that + is polling its children." + INDEX { pgmNeTsiGlobalId, + pgmNeTsiDataSourcePort, + pgmNeTsiPollType } + ::= { pgmNeTsiPollTable 1 } + +PgmNeTsiPollEntry ::= SEQUENCE { + pgmNeTsiPollType + INTEGER, + pgmNeTsiPollSequence + Unsigned32, + pgmNeTsiPollChildBackoff + Unsigned32, + pgmNeTsiPollMask + Unsigned32, + pgmNeTsiPollPeriod + Unsigned32, + pgmNeTsiPollCount + Counter32, + pgmNeTsiPollTimeout + TimeTicks +} + +pgmNeTsiPollType OBJECT-TYPE + SYNTAX INTEGER { + general(1), + dlr(2) + } + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Type of Poll." + ::= { pgmNeTsiPollEntry 1 } + +pgmNeTsiPollSequence OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Sequence number of the most recent POLL packet + that we sent." + ::= { pgmNeTsiPollEntry 2 } + +pgmNeTsiPollChildBackoff OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Backoff advertised to be used by child of poll." + ::= { pgmNeTsiPollEntry 3 } + +pgmNeTsiPollMask OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Mask being used in poll." + ::= { pgmNeTsiPollEntry 4 } + +pgmNeTsiPollPeriod OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Period of poll." + ::= { pgmNeTsiPollEntry 5 } + +pgmNeTsiPollCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of Poll responses (POLRs) received." + ::= { pgmNeTsiPollEntry 6 } + +pgmNeTsiPollTimeout OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Remaining Time Ticks to next poll." + ::= { pgmNeTsiPollEntry 7 } + + +-- +-- PGM Source +-- + +-- PGM Source general management information + + +pgmSourceSaveDefaults OBJECT-TYPE + SYNTAX INTEGER { initial (1), + save (2), + pending (3), + success (4), + failure (5) } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Flag used to initiate the storing + of all default variable values to + non-volatile storage and to report the + result of the operation. + The following values can only be read, + never written : + initial(1) - returned prior to any requests + for saving the default configuration + pending(3) - saving in progress + success(4) - returned when a save(2) request + is successful + failure(5) - returned when a save(2) request + is unsuccessful + + The following values can only be written, + never read : + save(2) - to indicate that the default + configuration should be saved." + ::= { pgmSource 1 } + +pgmSourceLastUpdateTime OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of TimeTicks since the last update + of the non-volatile storage." + ::= { pgmSource 2 } + +pgmSourceDefaultTtl OBJECT-TYPE + SYNTAX Unsigned32(1..255) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Default TTL used by the PGM Source." + ::= { pgmSource 3 } + +pgmSourceDefaultAdvMode OBJECT-TYPE + SYNTAX INTEGER { data(1), + time(2), + applctrl(3), + other(4) } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Flag to indicate that the transmit window is + advanced with data, by time, under application + control, or any other method." + ::= { pgmSource 4 } + +pgmSourceDefaultLateJoin OBJECT-TYPE + SYNTAX INTEGER { + enable(1), + disable(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Flag to indicate whether or not the sender will + accept late joiners." + ::= { pgmSource 5 } + +pgmSourceDefaultTxwMaxRte OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Maximum transmit rate in bytes/second." + ::= { pgmSource 6 } + +pgmSourceDefaultTxwSecs OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Transmit window size in seconds." + ::= { pgmSource 7 } + +pgmSourceDefaultTxwAdvSecs OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Transmit window advance in seconds. This value + should always be set to a value smaller than + the pgmSourceTxwSecs." + ::= { pgmSource 8 } + +pgmSourceDefaultAdvIvl OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Advance interval in milliseconds. Always a + valid parameter when advancing with time. + Valid only in cases of absence of lost data + when advancing with data." + ::= { pgmSource 9 } + +pgmSourceDefaultSpmIvl OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "SPM interval in milliseconds." + ::= { pgmSource 10 } + +pgmSourceDefaultSpmHeartBeatIvlMin OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "SPM heartbeat interval in milliseconds." + ::= { pgmSource 11 } + +pgmSourceDefaultSpmHeartBeatIvlMax OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Maximum SPM heartbeat interval in milliseconds." + ::= { pgmSource 12 } + +pgmSourceDefaultRdataBackoffIvl OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "RDATA backoff interval in milliseconds." + ::= { pgmSource 13 } + +pgmSourceDefaultFECProactiveParitySize OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Number of proactive parity messages per FEC + block." + ::= { pgmSource 14 } + +pgmSourceDefaultGroupAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The default IP Multicast group address + used by the sender." + ::= { pgmSource 15 } + +pgmSourceUpdateSinceLastSave OBJECT-TYPE + SYNTAX INTEGER + { + notUpdated(1), + updated(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Specifies if any of the Source Default + variables have been updated or not, + since the last successful pgmSourceSaveDefaults. + notUpdated - none of the default Source + variables were set after the last + successful save to a non-volatile + storage. + updated - at least one of the default Source + variables were set after the last + successful save to a non-volatile + storage." + ::= { pgmSource 16 } + +-- PGM Source per TSI management information + +pgmSourceTsi OBJECT IDENTIFIER ::= { pgmSource 100 } + +pgmSourceNumberOfEntries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of PGM Source sessions." + ::= { pgmSourceTsi 1 } + +-- PGM Source Fault Management Table + +pgmSourceTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmSourceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per TSI fault + management and general information + related to PGM Source." + ::= {pgmSourceTsi 2} + +pgmSourceEntry OBJECT-TYPE + SYNTAX PgmSourceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per PGM sender information." + INDEX { pgmSourceGlobalId, + pgmSourceSourcePort } + ::= { pgmSourceTable 1 } + +PgmSourceEntry ::= SEQUENCE { + pgmSourceGlobalId + OCTET STRING, + pgmSourceSourcePort + Unsigned32, + pgmSourceSourceAddress + IpAddress, + pgmSourceGroupAddress + IpAddress, + pgmSourceDestPort + Unsigned32, + pgmSourceSourceGsi + OCTET STRING, + pgmSourceSourcePortNumber + Unsigned32 + } + +pgmSourceGlobalId OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Globally unique session identifier (GSI)." + ::= { pgmSourceEntry 1 } + +pgmSourceSourcePort OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmSourceEntry 2 } + +pgmSourceSourceAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Source IP address." + ::= { pgmSourceEntry 3 } + +pgmSourceGroupAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "IP Multicast group address used by the + sender." + ::= { pgmSourceEntry 4 } + +pgmSourceDestPort OBJECT-TYPE + SYNTAX Unsigned32 (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Destination port number." + ::= { pgmSourceEntry 5 } + +pgmSourceSourceGsi OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Globally unique session identifier (GSI)." + ::= { pgmSourceEntry 6 } + +pgmSourceSourcePortNumber OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmSourceEntry 7 } + + +-- PGM Source Configuration Management Table + +pgmSourceConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmSourceConfigEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per TSI + configuration information + related to the PGM Source." + ::= {pgmSourceTsi 3} + +pgmSourceConfigEntry OBJECT-TYPE + SYNTAX PgmSourceConfigEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per PGM sender information." + INDEX { pgmSourceConfigGlobalId, + pgmSourceConfigSourcePort } + ::= { pgmSourceConfigTable 1 } + +PgmSourceConfigEntry ::= SEQUENCE { + pgmSourceConfigGlobalId + OCTET STRING, + pgmSourceConfigSourcePort + Unsigned32, + pgmSourceTtl + Unsigned32, + pgmSourceAdvMode + INTEGER, + pgmSourceLateJoin + INTEGER, + pgmSourceTxwMaxRte + Unsigned32, + pgmSourceTxwSecs + Unsigned32, + pgmSourceTxwAdvSecs + Unsigned32, + pgmSourceAdvIvl + Unsigned32, + pgmSourceSpmIvl + Unsigned32, + pgmSourceSpmHeartBeatIvlMin + Unsigned32, + pgmSourceSpmHeartBeatIvlMax + Unsigned32, + pgmSourceRdataBackoffIvl + Unsigned32, + pgmSourceFEC + INTEGER, + pgmSourceFECTransmissionGrpSize + Unsigned32, + pgmSourceFECProactiveParitySize + Unsigned32, + pgmSourceSpmPathAddress + IpAddress + } + +pgmSourceConfigGlobalId OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Globally unique session identifier (GSI)." + ::= { pgmSourceConfigEntry 1 } + +pgmSourceConfigSourcePort OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmSourceConfigEntry 2 } + +pgmSourceTtl OBJECT-TYPE + SYNTAX Unsigned32(1..255) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "TTL used by sender." + ::= { pgmSourceConfigEntry 3 } + +pgmSourceAdvMode OBJECT-TYPE + SYNTAX INTEGER { data(1), + time(2), + applctrl(3), + other(4) } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Flag to indicate that the transmit window is + advanced with data, by time, under application + control, or any other method." + ::= { pgmSourceConfigEntry 4 } + +pgmSourceLateJoin OBJECT-TYPE + SYNTAX INTEGER { + enable(1), + disable(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Flag to indicate whether or not the sender will + accept late joiners." + ::= { pgmSourceConfigEntry 5 } + +pgmSourceTxwMaxRte OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Maximum transmit rate in bytes/second." + ::= { pgmSourceConfigEntry 6 } + +pgmSourceTxwSecs OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Transmit window size in seconds." + ::= { pgmSourceConfigEntry 7 } + +pgmSourceTxwAdvSecs OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Transmit window advance in seconds. This value + should always be set to a value smaller than + the pgmSourceTxwSecs." + ::= { pgmSourceConfigEntry 8 } + +pgmSourceAdvIvl OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Advance interval in milliseconds. Always a + valid parameter when advancing with time. + Valid only in cases of absence of lost data + when advancing with data." + ::= { pgmSourceConfigEntry 9 } + +pgmSourceSpmIvl OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "SPM interval in milliseconds." + ::= { pgmSourceConfigEntry 10 } + +pgmSourceSpmHeartBeatIvlMin OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "SPM heartbeat interval in milliseconds." + ::= { pgmSourceConfigEntry 11 } + +pgmSourceSpmHeartBeatIvlMax OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Maximum SPM heartbeat interval in milliseconds." + ::= { pgmSourceConfigEntry 12 } + +pgmSourceRdataBackoffIvl OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "RDATA backoff interval in milliseconds." + ::= { pgmSourceConfigEntry 13 } + +pgmSourceFEC OBJECT-TYPE + SYNTAX INTEGER { disabled(1), + enabledFixedPacketSize(2), + enabledVariablePacketSize(3) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Flag to indicate whether or not FEC is enabled + and whether it supports variable or fixed size + messages." + ::= { pgmSourceConfigEntry 14 } + +pgmSourceFECTransmissionGrpSize OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "FEC transmission group size." + ::= { pgmSourceConfigEntry 15 } + +pgmSourceFECProactiveParitySize OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Number of proactive parity messages per FEC + block." + ::= { pgmSourceConfigEntry 16 } + +pgmSourceSpmPathAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Ip Address for the NAKs to be sent, + in case that NE is not set." + ::= { pgmSourceConfigEntry 17 } + +-- PGM Source Performance Management Table + +pgmSourcePerformanceTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmSourcePerformanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per TSI performance + information related to the PGM Source." + ::= {pgmSourceTsi 4} + +pgmSourcePerformanceEntry OBJECT-TYPE + SYNTAX PgmSourcePerformanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per PGM sender information." + INDEX { pgmSourcePerformanceGlobalId, + pgmSourcePerformanceSourcePort } + ::= { pgmSourcePerformanceTable 1 } + +PgmSourcePerformanceEntry ::= SEQUENCE { + pgmSourcePerformanceGlobalId + OCTET STRING, + pgmSourcePerformanceSourcePort + Unsigned32, + pgmSourceDataBytesSent + Counter32, + pgmSourceDataMsgsSent + Counter32, + pgmSourceBytesBuffered + Counter32, + pgmSourceMsgsBuffered + Counter32, + pgmSourceBytesRetransmitted + Counter32, + pgmSourceMsgsRetransmitted + Counter32, + pgmSourceBytesSent + Counter32, + pgmSourceRawNaksReceived + Counter32, + pgmSourceNaksIgnored + Counter32, + pgmSourceCksumErrors + Counter32, + pgmSourceMalformedNaks + Counter32, + pgmSourcePacketsDiscarded + Counter32, + pgmSourceNaksRcvd + Counter32, + pgmSourceParityBytesRetransmitted + Counter32, + pgmSourceSelectiveBytesRetransmited + Counter32, + pgmSourceParityMsgsRetransmitted + Counter32, + pgmSourceSelectiveMsgsRetransmitted + Counter32, + pgmSourceBytesAdmit + Counter32, + pgmSourceMsgsAdmit + Counter32, + pgmSourceParityNakPacketsReceived + Counter32, + pgmSourceSelectiveNakPacketsReceived + Counter32, + pgmSourceParityNaksReceived + Counter32, + pgmSourceSelectiveNaksReceived + Counter32, + pgmSourceParityNaksIgnored + Counter32, + pgmSourceSelectiveNaksIgnored + Counter32, + pgmSourceAckErrors + Counter32, + pgmSourcePgmCCAcker + IpAddress, + pgmSourceTransmissionCurrentRate + Counter32, + pgmSourceAckPacketsReceived + Counter32, + pgmSourceNNakPacketsReceived + Counter32, + pgmSourceParityNNakPacketsReceived + Counter32, + pgmSourceSelectiveNNakPacketsReceived + Counter32, + pgmSourceNNaksReceived + Counter32, + pgmSourceParityNNaksReceived + Counter32, + pgmSourceSelectiveNNaksReceived + Counter32, + pgmSourceNNakErrors + Counter32 +} + +pgmSourcePerformanceGlobalId OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Globally unique source identifier (GSI)." + ::= { pgmSourcePerformanceEntry 1 } + +pgmSourcePerformanceSourcePort OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmSourcePerformanceEntry 2 } + +pgmSourceDataBytesSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of data bytes sent for this TSI." + ::= { pgmSourcePerformanceEntry 3 } + +pgmSourceDataMsgsSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of data messages sent for this TSI." + ::= { pgmSourcePerformanceEntry 4 } + +pgmSourceBytesBuffered OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes currently buffered for this + TSI." + ::= { pgmSourcePerformanceEntry 5 } + +pgmSourceMsgsBuffered OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages currently buffered for + this TSI." + ::= { pgmSourcePerformanceEntry 6 } + +pgmSourceBytesRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes retransmitted for this TSI." + ::= { pgmSourcePerformanceEntry 7 } + +pgmSourceMsgsRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages retransmitted for this TSI." + ::= { pgmSourcePerformanceEntry 8 } + +pgmSourceBytesSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of bytes send for this TSI. Includes + IP header and non-data messages." + ::= { pgmSourcePerformanceEntry 9 } + +pgmSourceRawNaksReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Raw number of NAK packets received." + ::= { pgmSourcePerformanceEntry 10 } + +pgmSourceNaksIgnored OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of ignored Naks for this TSI, due to + duplicate NAKs reception." + ::= { pgmSourcePerformanceEntry 11 } + +pgmSourceCksumErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of checksum errors for this TSI." + ::= { pgmSourcePerformanceEntry 12 } + +pgmSourceMalformedNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of malformed NAK packets." + ::= { pgmSourcePerformanceEntry 13 } + +pgmSourcePacketsDiscarded OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of discarded data packets. This counter + is used to count all discarded incoming packets + per TSI in cases of duplicates, header and + packet errors, etc." + ::= { pgmSourcePerformanceEntry 14 } + +pgmSourceNaksRcvd OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of Sequence Numbers NAKed." + ::= { pgmSourcePerformanceEntry 15 } + +pgmSourceParityBytesRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes sent in parity retransmissions." + ::= { pgmSourcePerformanceEntry 16 } + +pgmSourceSelectiveBytesRetransmited OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes sent in selective retransmissions." + ::= { pgmSourcePerformanceEntry 17 } + +pgmSourceParityMsgsRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of parity retransmissions sent." + ::= { pgmSourcePerformanceEntry 18 } + +pgmSourceSelectiveMsgsRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of selective retransmissions sent." + ::= { pgmSourcePerformanceEntry 19 } + +pgmSourceBytesAdmit OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes currently in the rate controled + admit queue. Includes IP header, UDP header if + encapsulated, PGM header, and data." + ::= { pgmSourcePerformanceEntry 20 } + +pgmSourceMsgsAdmit OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages currently in the rate controled + admit queue. Includes data messages, retransmissions, + and SPMs." + ::= { pgmSourcePerformanceEntry 21 } + +pgmSourceParityNakPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of parity NAK packets received." + ::= { pgmSourcePerformanceEntry 22 } + +pgmSourceSelectiveNakPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of selective NAK packets received." + ::= { pgmSourcePerformanceEntry 23 } + +pgmSourceParityNaksReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual parity NAKs received." + ::= { pgmSourcePerformanceEntry 24 } + +pgmSourceSelectiveNaksReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual selective NAKs received." + ::= { pgmSourcePerformanceEntry 25 } + +pgmSourceParityNaksIgnored OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual parity NAKs ignored." + ::= { pgmSourcePerformanceEntry 26 } + +pgmSourceSelectiveNaksIgnored OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual selective NAKs ignored." + ::= { pgmSourcePerformanceEntry 27 } + +pgmSourceAckErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of ACK packets received with error in + them, different than checksum error." + ::= { pgmSourcePerformanceEntry 28 } + +pgmSourcePgmCCAcker OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Ip Address of the currently designated pgm + congestion control ACKER." + ::= { pgmSourcePerformanceEntry 29 } + +pgmSourceTransmissionCurrentRate OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current transmission rate." + ::= { pgmSourcePerformanceEntry 30 } + +pgmSourceAckPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of ACK packets received." + ::= { pgmSourcePerformanceEntry 31 } + +pgmSourceNNakPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of Null NAKs received." + ::= { pgmSourcePerformanceEntry 32 } + +pgmSourceParityNNakPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of parity Null NAK packets received." + ::= { pgmSourcePerformanceEntry 33 } + +pgmSourceSelectiveNNakPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of selective Null NAK packets received." + ::= { pgmSourcePerformanceEntry 34 } + +pgmSourceNNaksReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual NAKs, received in Null + NAK packets." + ::= { pgmSourcePerformanceEntry 35 } + +pgmSourceParityNNaksReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual parity NAKs, + received in Null NAK packets." + ::= { pgmSourcePerformanceEntry 36 } + +pgmSourceSelectiveNNaksReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual NAKs, + received in Null NAK packets." + ::= { pgmSourcePerformanceEntry 37 } + +pgmSourceNNakErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of Null NAK packets received that contain + error, different than checksum error." + ::= { pgmSourcePerformanceEntry 38 } + +-- +-- PGM Receiver +-- + +-- PGM Receiver general management information + +pgmReceiverSaveDefaults OBJECT-TYPE + SYNTAX INTEGER { initial (1), + save (2), + pending (3), + success (4), + failure (5) } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Flag used to initiate the storing + of all default variable values to + non-volatile storage and to report the + result of the operation. + The following values can only be read, + never written : + initial(1) - returned prior to any requests + for saving the default configuration + pending(3) - saving in progress + success(4) - returned when a save(2) request + is successful + failure(5) - returned when a save(2) request + is unsuccessful + + The following values can only be written, + never read : + save(2) - to indicate that the default + configuration should be saved." + ::= { pgmReceiver 1 } + +pgmReceiverLastUpdateTime OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of TimeTicks since the last update + of the non-volatile storage." + ::= { pgmReceiver 2 } + +pgmReceiverDefaultNakBackoffIvl OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "NAK random backoff interval." + ::= { pgmReceiver 3 } + +pgmReceiverDefaultNakRepeatIvl OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "NAK repeat interval." + ::= { pgmReceiver 4 } + +pgmReceiverDefaultNakNcfRetries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Max NAK retries while witing for matching NCF." + ::= { pgmReceiver 5 } + +pgmReceiverDefaultNakRdataIvl OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Default NAK RDATA interval, i.e the amount of + time to cease NAKs for a particular piece of + data after a corresponding NCF has been received." + ::= { pgmReceiver 6 } + +pgmReceiverDefaultNakDataRetries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Max NAK retries while waiting for missing data." + ::= { pgmReceiver 7 } + +pgmReceiverDefaultSendNaks OBJECT-TYPE + SYNTAX INTEGER { + enabled(1), + disabled(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Flag to indicate whether or not receiver should + send NAKs or be totally passive." + ::= { pgmReceiver 8 } + +pgmReceiverDefaultLateJoin OBJECT-TYPE + SYNTAX INTEGER { + enabled(1), + disabled(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Flag to indicate whether or not the receiver + should wait for a OPT_JOIN SPM before + attempting to late join." + ::= { pgmReceiver 9 } + +pgmReceiverDefaultNakTtl OBJECT-TYPE + SYNTAX Unsigned32(1..255) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "TTL on NAK packets sent for loss." + ::= { pgmReceiver 10 } + +pgmReceiverDefaultDeliveryOrder OBJECT-TYPE + SYNTAX INTEGER { + unordered(1), + ordered(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Packet Delivery Order for the receiving + application." + ::= { pgmReceiver 11 } + +pgmReceiverDefaultNextPgmHop OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Next hop PGM router address. This option + sets the default address to send NAKs to, + instead of sending to the last hop address." + ::= { pgmReceiver 12 } + +pgmReceiverDefaultGroupAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Default IP Multicast group address + used by the sender." + ::= { pgmReceiver 13 } + +pgmReceiverUpdateSinceLastSave OBJECT-TYPE + SYNTAX INTEGER + { + notUpdated(1), + updated(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Specifies if any of the Receiver Default + variables have been updated or not, + since the last successful pgmSourceSaveDefaults. + notUpdated - none of the default Receiver + variables were set after the last + successful save to a non-volatile + storage. + updated - at least one of the default Receiver + variables were set after the last + successful save to a non-volatile + storage." + ::= { pgmReceiver 14 } + +pgmReceiverDefaultNakFailureThresholdTimer OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Timer that defines the default + interval of time during which unrecoverable + lost packets are monitored + for purposes of SNMP trap generation." + ::= { pgmReceiver 15 } + +pgmReceiverDefaultNakFailureThreshold OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The default number of unrecoverable + lost packets within the defined interval + after which an SNMP trap is generated." + ::= { pgmReceiver 16 } + + +-- PGM Receiver per Receiver management information + +pgmReceiverTsi OBJECT IDENTIFIER ::= { pgmReceiver 100 } + +pgmReceiverNumberOfEntries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of PGM Receivers." + ::= { pgmReceiverTsi 1 } + +-- PGM Receiver Fault Management Table + +pgmReceiverTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmReceiverEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per TSI fault + management and general information + related to the PGM Receiver." + ::= {pgmReceiverTsi 2} + +pgmReceiverEntry OBJECT-TYPE + SYNTAX PgmReceiverEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per PGM receiver fault management + and general information." + INDEX { pgmReceiverGlobalId, + pgmReceiverSourcePort, + pgmReceiverInstance } + ::= { pgmReceiverTable 1 } + +PgmReceiverEntry ::= SEQUENCE { + pgmReceiverGlobalId + OCTET STRING, + pgmReceiverSourcePort + Unsigned32, + pgmReceiverInstance + Unsigned32, + pgmReceiverGroupAddress + IpAddress, + pgmReceiverDestPort + Unsigned32, + pgmReceiverSourceAddress + IpAddress, + pgmReceiverLastHop + IpAddress, + pgmReceiverSourceGsi + OCTET STRING, + pgmReceiverSourcePortNumber + Unsigned32, + pgmReceiverUniqueInstance + Unsigned32 + } + +pgmReceiverGlobalId OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Globally unique source identifier (GSI)." + ::= { pgmReceiverEntry 1 } + +pgmReceiverSourcePort OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmReceiverEntry 2 } + +pgmReceiverInstance OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Positive number, uniquely identifying + a Receiver." + ::= { pgmReceiverEntry 3 } + +pgmReceiverGroupAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "IP Multicast group address used by the sender." + ::= { pgmReceiverEntry 4 } + +pgmReceiverDestPort OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Destination port number." + ::= { pgmReceiverEntry 5 } + +pgmReceiverSourceAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Source IP address number." + ::= { pgmReceiverEntry 6 } + +pgmReceiverLastHop OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Last hop PGM router address." + ::= { pgmReceiverEntry 7 } + +pgmReceiverSourceGsi OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Globally unique source identifier (GSI)." + ::= { pgmReceiverEntry 8 } + +pgmReceiverSourcePortNumber OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmReceiverEntry 9 } + +pgmReceiverUniqueInstance OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Positive number, uniquely identifying + a Receiver." + ::= { pgmReceiverEntry 10 } + +-- PGM Receiver Configuration Management Table + +pgmReceiverConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmReceiverConfigEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per TSI configuration + management information related + to the PGM Receiver." + ::= {pgmReceiverTsi 3 } + +pgmReceiverConfigEntry OBJECT-TYPE + SYNTAX PgmReceiverConfigEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per PGM receiver configuration management + information." + INDEX { pgmReceiverConfigGlobalId, + pgmReceiverConfigSourcePort, + pgmReceiverConfigInstance } + ::= { pgmReceiverConfigTable 1 } + +PgmReceiverConfigEntry ::= SEQUENCE { + pgmReceiverConfigGlobalId + OCTET STRING, + pgmReceiverConfigSourcePort + Unsigned32, + pgmReceiverConfigInstance + Unsigned32, + pgmReceiverNakBackoffIvl + Unsigned32, + pgmReceiverNakRepeatIvl + Unsigned32, + pgmReceiverNakNcfRetries + Unsigned32, + pgmReceiverNakRdataIvl + Unsigned32, + pgmReceiverNakDataRetries + Unsigned32, + pgmReceiverSendNaks + INTEGER, + pgmReceiverLateJoin + INTEGER, + pgmReceiverNakTtl + Unsigned32, + pgmReceiverDeliveryOrder + INTEGER, + pgmReceiverMcastNaks + INTEGER, + pgmReceiverNakFailureThresholdTimer + Unsigned32, + pgmReceiverNakFailureThreshold + Unsigned32 + } + +pgmReceiverConfigGlobalId OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Globally unique source identifier (GSI)." + ::= { pgmReceiverConfigEntry 1 } + +pgmReceiverConfigSourcePort OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmReceiverConfigEntry 2 } + +pgmReceiverConfigInstance OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Positive number, uniquely identifying + a Receiver." + ::= { pgmReceiverConfigEntry 3 } + +pgmReceiverNakBackoffIvl OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "NAK random backoff interval." + ::= { pgmReceiverConfigEntry 4 } + +pgmReceiverNakRepeatIvl OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "NAK repeat interval." + ::= { pgmReceiverConfigEntry 5 } + +pgmReceiverNakNcfRetries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Max NAK retries while witing for matching NCF." + ::= { pgmReceiverConfigEntry 6 } + +pgmReceiverNakRdataIvl OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "NAK RDATA interval." + ::= { pgmReceiverConfigEntry 7 } + +pgmReceiverNakDataRetries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Max NAK retries while waiting for missing data." + ::= { pgmReceiverConfigEntry 8 } + +pgmReceiverSendNaks OBJECT-TYPE + SYNTAX INTEGER { + enabled(1), + disabled(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Flag to indicate whether or not receiver should + send NAKs or be totally passive." + ::= { pgmReceiverConfigEntry 9 } + +pgmReceiverLateJoin OBJECT-TYPE + SYNTAX INTEGER { + enabled(1), + disabled(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Flag to indicate whether or not the receiver + should wait for a OPT_JOIN SPM before + attempting to late join." + ::= { pgmReceiverConfigEntry 10 } + +pgmReceiverNakTtl OBJECT-TYPE + SYNTAX Unsigned32(1..255) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "TTL on NAK packets sent for loss." + ::= { pgmReceiverConfigEntry 11 } + +pgmReceiverDeliveryOrder OBJECT-TYPE + SYNTAX INTEGER { + unordered(1), + ordered(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Packet Delivery Order for the receiving + application." + ::= { pgmReceiverConfigEntry 12 } + +pgmReceiverMcastNaks OBJECT-TYPE + SYNTAX INTEGER { + enabled(1), + disabled(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Flag to indicate whether or not receiver should + send multicast NAKs." + ::= { pgmReceiverConfigEntry 13 } + +pgmReceiverNakFailureThresholdTimer OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "seconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Timer that defines per receiver + interval of time during which unrecoverable + lost packets are monitored + for purposes of SNMP trap generation." + ::= { pgmReceiverConfigEntry 14 } + +pgmReceiverNakFailureThreshold OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The number of unrecoverable lost packets + within the defined interval + after which an SNMP trap is generated." + ::= { pgmReceiverConfigEntry 15 } + + +-- PGM Receiver Performance Management Table + +pgmReceiverPerformanceTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmReceiverPerformanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per TSI + performance management information + related to the PGM Receiver." + ::= {pgmReceiverTsi 4} + +pgmReceiverPerformanceEntry OBJECT-TYPE + SYNTAX PgmReceiverPerformanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per PGM Receiver session performance + management information." + INDEX { pgmReceiverPerformanceGlobalId, + pgmReceiverPerformanceSourcePort, + pgmReceiverPerformanceInstance } + ::= { pgmReceiverPerformanceTable 1 } + +PgmReceiverPerformanceEntry ::= SEQUENCE { + pgmReceiverPerformanceGlobalId + OCTET STRING, + pgmReceiverPerformanceSourcePort + Unsigned32, + pgmReceiverPerformanceInstance + Unsigned32, + pgmReceiverDataBytesReceived + Counter32, + pgmReceiverDataMsgsReceived + Counter32, + pgmReceiverNaksSent + Counter32, + pgmReceiverNaksRetransmitted + Counter32, + pgmReceiverNakFailures + Counter32, + pgmReceiverBytesReceived + Counter32, + pgmReceiverNaksSuppressed + Counter32, + pgmReceiverCksumErrors + Counter32, + pgmReceiverMalformedSpms + Counter32, + pgmReceiverMalformedOdata + Counter32, + pgmReceiverMalformedRdata + Counter32, + pgmReceiverMalformedNcfs + Counter32, + pgmReceiverPacketsDiscarded + Counter32, + pgmReceiverLosses + Counter32, + pgmReceiverBytesDeliveredToApp + Counter32, + pgmReceiverMsgsDeliveredToApp + Counter32, + pgmReceiverDupSpms + Counter32, + pgmReceiverDupDatas + Counter32, + pgmReceiverDupParities + Counter32, + pgmReceiverNakPacketsSent + Counter32, + pgmReceiverParityNakPacketsSent + Counter32, + pgmReceiverSelectiveNakPacketsSent + Counter32, + pgmReceiverParityNaksSent + Counter32, + pgmReceiverSelectiveNaksSent + Counter32, + pgmReceiverParityNaksRetransmitted + Counter32, + pgmReceiverSelectiveNaksRetransmitted + Counter32, + pgmReceiverNaksFailed + Counter32, + pgmReceiverParityNaksFailed + Counter32, + pgmReceiverSelectiveNaksFailed + Counter32, + pgmReceiverNaksFailedRxwAdvanced + Counter32, + pgmReceiverNaksFaledNcfRetriesExceeded + Counter32, + pgmReceiverNaksFailedDataRetriesExceeded + Counter32, + pgmReceiverNaksFailedGenExpired + Counter32, + pgmReceiverNakFailuresDelivered + Counter32, + pgmReceiverParityNaksSuppressed + Counter32, + pgmReceiverSelectiveNaksSuppressed + Counter32, + pgmReceiverNakErrors + Counter32, + pgmReceiverOutstandingParityNaks + Counter32, + pgmReceiverOutstandingSelectiveNaks + Counter32, + pgmReceiverLastActivity + Counter32, + pgmReceiverNakSvcTimeMin + Counter32, + pgmReceiverNakSvcTimeMean + Counter32, + pgmReceiverNakSvcTimeMax + Counter32, + pgmReceiverNakFailTimeMin + Counter32, + pgmReceiverNakFailTimeMean + Counter32, + pgmReceiverNakFailTimeMax + Counter32, + pgmReceiverNakTransmitMin + Counter32, + pgmReceiverNakTransmitMean + Counter32, + pgmReceiverNakTransmitMax + Counter32, + pgmReceiverAcksSent + Counter32, + pgmReceiverRxwTrail + Counter32, + pgmReceiverRxwLead + Counter32, + pgmReceiverNakFailuresLastInterval + Counter32, + pgmReceiverLastIntervalNakFailures + Counter32 +} + +pgmReceiverPerformanceGlobalId OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Globally unique source identifier (GSI)." + ::= { pgmReceiverPerformanceEntry 1 } + +pgmReceiverPerformanceSourcePort OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmReceiverPerformanceEntry 2 } + +pgmReceiverPerformanceInstance OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Positive number, uniquely identifying + a Receiver." + ::= { pgmReceiverPerformanceEntry 3 } + +pgmReceiverDataBytesReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of data bytes received for this PGM + Receiver session." + ::= { pgmReceiverPerformanceEntry 4 } + +pgmReceiverDataMsgsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of data messages received for this + PGM Receiver session." + ::= { pgmReceiverPerformanceEntry 5 } + +pgmReceiverNaksSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAKs sent for this session." + ::= { pgmReceiverPerformanceEntry 6 } + +pgmReceiverNaksRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAKs retransmitted for this + session." + ::= { pgmReceiverPerformanceEntry 7 } + +pgmReceiverNakFailures OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAK failures for this session. + This counter represents the number of + unrecoverable/unrepairable data packets." + ::= { pgmReceiverPerformanceEntry 8 } + +pgmReceiverBytesReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes received for this session. + It counts all bytes received, including IP + and PGM header and non-data messages." + ::= { pgmReceiverPerformanceEntry 9 } + +pgmReceiverNaksSuppressed OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of suppressed NAKs." + ::= { pgmReceiverPerformanceEntry 10 } + +pgmReceiverCksumErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of checksum errors for this session." + ::= { pgmReceiverPerformanceEntry 11 } + +pgmReceiverMalformedSpms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of malformed SPMs for this session." + ::= { pgmReceiverPerformanceEntry 12 } + +pgmReceiverMalformedOdata OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of malformed ODATA packets for this + session." + ::= { pgmReceiverPerformanceEntry 13 } + +pgmReceiverMalformedRdata OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of malformed RDATA packets for this + session." + ::= { pgmReceiverPerformanceEntry 14 } + +pgmReceiverMalformedNcfs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of malformed NCF packets for this + session." + ::= { pgmReceiverPerformanceEntry 15 } + +pgmReceiverPacketsDiscarded OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of discarded packets for this + session." + ::= { pgmReceiverPerformanceEntry 16 } + +pgmReceiverLosses OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of detected missed packets for + this session. This counter is incremented + every time a Receiver detects a missing + packet." + ::= { pgmReceiverPerformanceEntry 17 } + +pgmReceiverBytesDeliveredToApp OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes, delivered to the + application." + ::= { pgmReceiverPerformanceEntry 18 } + +pgmReceiverMsgsDeliveredToApp OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages, delivered to the + application." + ::= { pgmReceiverPerformanceEntry 19 } + +pgmReceiverDupSpms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of duplicate SPMs." + ::= { pgmReceiverPerformanceEntry 20 } + +pgmReceiverDupDatas OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of duplicate RDATA/ODATA." + ::= { pgmReceiverPerformanceEntry 21 } + +pgmReceiverDupParities OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of duplicate parities seen." + ::= { pgmReceiverPerformanceEntry 22 } + +pgmReceiverNakPacketsSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAK packets sent. + Includes parity and selective." + ::= { pgmReceiverPerformanceEntry 23 } + +pgmReceiverParityNakPacketsSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of parity NAK packets sent." + ::= { pgmReceiverPerformanceEntry 24 } + +pgmReceiverSelectiveNakPacketsSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of selective NAK packets sent." + ::= { pgmReceiverPerformanceEntry 25 } + +pgmReceiverParityNaksSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual parity NAK packets sent." + ::= { pgmReceiverPerformanceEntry 26 } + +pgmReceiverSelectiveNaksSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual selective NAK packets sent." + ::= { pgmReceiverPerformanceEntry 27 } + +pgmReceiverParityNaksRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual parity NAKs retransmitted." + ::= { pgmReceiverPerformanceEntry 28 } + +pgmReceiverSelectiveNaksRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual selective NAKs retransmitted." + ::= { pgmReceiverPerformanceEntry 29 } + +pgmReceiverNaksFailed OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual NAKs that failed." + ::= { pgmReceiverPerformanceEntry 30 } + +pgmReceiverParityNaksFailed OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual parity NAKs that failed." + ::= { pgmReceiverPerformanceEntry 31 } + +pgmReceiverSelectiveNaksFailed OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual selective NAKs that failed." + ::= { pgmReceiverPerformanceEntry 32 } + +pgmReceiverNaksFailedRxwAdvanced OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual NAKs that failed, due to the + window being advanced over them." + ::= { pgmReceiverPerformanceEntry 33 } + +pgmReceiverNaksFaledNcfRetriesExceeded OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual NAKs that failed, due to ncf + retry limit exceeded." + ::= { pgmReceiverPerformanceEntry 34 } + +pgmReceiverNaksFailedDataRetriesExceeded OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual NAKs that failed, due to data + retry limit exceeded." + ::= { pgmReceiverPerformanceEntry 35 } + +pgmReceiverNaksFailedGenExpired OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual NAKs that failed, due to NAK + generation interval expiring before it + could be repaired." + ::= { pgmReceiverPerformanceEntry 36 } + +pgmReceiverNakFailuresDelivered OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAK failures delivered to application." + ::= { pgmReceiverPerformanceEntry 37 } + +pgmReceiverParityNaksSuppressed OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual parity NAKs that were + suppressed from being sent due to reception + of an NCF or ODATA/RDATA for the loss." + ::= { pgmReceiverPerformanceEntry 38 } + +pgmReceiverSelectiveNaksSuppressed OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual selective NAKs that were + suppressed from being sent due to reception + of an NCF or ODATA/RDATA for the loss." + ::= { pgmReceiverPerformanceEntry 39 } + +pgmReceiverNakErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAK packets, that contained + errors in them." + ::= { pgmReceiverPerformanceEntry 40 } + +pgmReceiverOutstandingParityNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current number of outstanding individual parity + NAKs that are waiting to be repaired." + ::= { pgmReceiverPerformanceEntry 41 } + +pgmReceiverOutstandingSelectiveNaks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current number of outstanding individual selective + NAKs that are waiting to be repaired." + ::= { pgmReceiverPerformanceEntry 42 } + +pgmReceiverLastActivity OBJECT-TYPE + SYNTAX Counter32 + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Last time activity was observed from + the Source. In seconds since the epoch, + January 1, 1970." + ::= { pgmReceiverPerformanceEntry 43 } + +pgmReceiverNakSvcTimeMin OBJECT-TYPE + SYNTAX Counter32 + UNITS "miliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The min time that it took for a loss + to be repaired." + ::= { pgmReceiverPerformanceEntry 44 } + +pgmReceiverNakSvcTimeMean OBJECT-TYPE + SYNTAX Counter32 + UNITS "miliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The mean time that it took for all losses + to be repaired." + ::= { pgmReceiverPerformanceEntry 45 } + +pgmReceiverNakSvcTimeMax OBJECT-TYPE + SYNTAX Counter32 + UNITS "miliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The max time that it took for a loss + to be repaired." + ::= { pgmReceiverPerformanceEntry 46 } + +pgmReceiverNakFailTimeMin OBJECT-TYPE + SYNTAX Counter32 + UNITS "miliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The min time it took for a loss + to be considered unrecoverable." + ::= { pgmReceiverPerformanceEntry 47 } + +pgmReceiverNakFailTimeMean OBJECT-TYPE + SYNTAX Counter32 + UNITS "miliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The mean time it took for all losses + to be considered unrecoverable." + ::= { pgmReceiverPerformanceEntry 48 } + +pgmReceiverNakFailTimeMax OBJECT-TYPE + SYNTAX Counter32 + UNITS "miliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The max time it took for a loss + to be considered unrecoverable." + ::= { pgmReceiverPerformanceEntry 49 } + +pgmReceiverNakTransmitMin OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The min number of times an individual NAK + needed to be retransmitted before it was repaired." + ::= { pgmReceiverPerformanceEntry 50 } + +pgmReceiverNakTransmitMean OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The mean number of times an individual NAK + needed to be retransmitted before it was repaired." + ::= { pgmReceiverPerformanceEntry 51 } + +pgmReceiverNakTransmitMax OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The max number of times an individual NAK + needed to be retransmitted before it was repaired." + ::= { pgmReceiverPerformanceEntry 52 } + +pgmReceiverAcksSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of ACKs sent from the congestion + control operation." + ::= { pgmReceiverPerformanceEntry 53 } + +pgmReceiverRxwTrail OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Sequence number of the trailing edge of + the transmission window as is being advertised + by the sender." + ::= { pgmReceiverPerformanceEntry 54 } + +pgmReceiverRxwLead OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Sequence number of the leading edge of + the transmission window as is being advertised + by the sender." + ::= { pgmReceiverPerformanceEntry 55 } + +pgmReceiverNakFailuresLastInterval OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The actual number of seconds since the + last pgmReceiverLastIntervalNakFailures + counter reset due to number of nak failures + threshold exceeded." + ::= { pgmReceiverPerformanceEntry 56 } + +pgmReceiverLastIntervalNakFailures OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of actual unrecoverable failures for + the requested threshold interval for this session." + ::= { pgmReceiverPerformanceEntry 57 } + +-- +-- Designated Local Repairer (DLR) +-- + +-- Designated Local Repairer (DLR) Default Configuration + +pgmDlrSaveDefaults OBJECT-TYPE + SYNTAX INTEGER { initial (1), + save (2), + pending (3), + success (4), + failure (5) } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Flag used to initiate the storing + of all default variable values to + non-volatile storage and to report the + result of the operation. + The following values can only be read, + never written : + initial(1) - returned prior to any requests + for saving the default configuration + pending(3) - saving in progress + success(4) - returned when a save(2) request + is successful + failure(5) - returned when a save(2) request + is unsuccessful + + The following values can only be written, + never read : + save(2) - to indicate that the default + configuration should be saved." + ::= { pgmDLR 1 } + +pgmDlrLastUpdateTime OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of TimeTicks since the last update + of the non-volatile storage." + ::= { pgmDLR 2 } + +pgmDlrGroupAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Multicast group address to listen for traffic + on." + ::= { pgmDLR 3 } + +pgmDlrCacheRtx OBJECT-TYPE + SYNTAX INTEGER + { + cacheOFF(1), + cacheON(2) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Specifies if the NE should also cache data for + retransmission or simply suppress duplicate + NAKs and forward the NAKs to it's parent NE or + sender." + ::= { pgmDLR 4 } + +pgmDlrActivityIvl OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Specifies the delay between activity checks + for specific PGM sessions." + ::= { pgmDLR 5 } + +pgmDlrMaxRate OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Specifies the maximum rate (in bps) for + retransmissions." + ::= { pgmDLR 6 } + +pgmDlrParentNeAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Ip Address of the NE to send all NAKs to." + ::= { pgmDLR 7 } + +pgmDlrUpdateSinceLastSave OBJECT-TYPE + SYNTAX INTEGER + { + notUpdated(1), + updated(2) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Specifies if any of the Dlr Default + variables have been updated or not, + since the last successful pgmDlrSaveDefaults. + notUpdated - none of the default Dlr + variables were set after the last + successful save to a non-volatile + storage. + updated - at least one of the default Dlr + variables were set after the last + successful save to a non-volatile + storage." + ::= { pgmDLR 8 } + + +-- +-- PGM DLR Source/Re-transmitter Sessions +-- +pgmDlrSource OBJECT IDENTIFIER ::= { pgmDLR 100 } + +pgmDlrSourceNumberOfEntries OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The total number of PGM Source sessions for + the PGM DLR." + ::= { pgmDlrSource 1 } + +-- PGM Dlr Source Fault Management Table + +pgmDlrSourceTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmDlrSourceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per TSI fault + management and general information + related to the PGM DLR Source sessions." + ::= {pgmDlrSource 2} + +pgmDlrSourceEntry OBJECT-TYPE + SYNTAX PgmDlrSourceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per PGM DLR Source sessions fault + management information." + INDEX { pgmDlrSourceGlobalId, + pgmDlrSourceSourcePort } + ::= { pgmDlrSourceTable 1 } + +PgmDlrSourceEntry ::= SEQUENCE { + pgmDlrSourceGlobalId + OCTET STRING, + pgmDlrSourceSourcePort + Unsigned32, + pgmDlrSourceGroupAddress + IpAddress, + pgmDlrSourceSourceGsi + OCTET STRING, + pgmDlrSourceSourcePortNumber + Unsigned32 + } + +pgmDlrSourceGlobalId OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Globally unique source identifier (GSI)." + ::= { pgmDlrSourceEntry 1 } + +pgmDlrSourceSourcePort OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmDlrSourceEntry 2 } + +pgmDlrSourceGroupAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Multicast group interface address + to send multicast packets on." + ::= { pgmDlrSourceEntry 3 } + +pgmDlrSourceSourceGsi OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Globally unique source identifier (GSI)." + ::= { pgmDlrSourceEntry 4 } + +pgmDlrSourceSourcePortNumber OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmDlrSourceEntry 5 } + +-- PGM DLR Source Configuration Management Table + +pgmDlrSourceConfigTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmDlrSourceConfigEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per TSI configuration + management information related to the + PGM DLR Source sessions." + ::= {pgmDlrSource 3} + +pgmDlrSourceConfigEntry OBJECT-TYPE + SYNTAX PgmDlrSourceConfigEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per PGM DLR Source sessions configuration + management information." + INDEX { pgmDlrSourceConfigGlobalId, + pgmDlrSourceConfigSourcePort } + ::= { pgmDlrSourceConfigTable 1 } + +PgmDlrSourceConfigEntry ::= SEQUENCE { + pgmDlrSourceConfigGlobalId + OCTET STRING, + pgmDlrSourceConfigSourcePort + Unsigned32, + pgmDlrSourceGroupTtl + Unsigned32, + pgmDlrSourceRdataBackoffIvl + Unsigned32 + } + +pgmDlrSourceConfigGlobalId OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Globally unique source identifier (GSI)." + ::= { pgmDlrSourceConfigEntry 1 } + +pgmDlrSourceConfigSourcePort OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmDlrSourceConfigEntry 2 } + +pgmDlrSourceGroupTtl OBJECT-TYPE + SYNTAX Unsigned32(1..255) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "This option sets the default TTL to use for + multicast packets. " + ::= { pgmDlrSourceConfigEntry 3 } + +pgmDlrSourceRdataBackoffIvl OBJECT-TYPE + SYNTAX Unsigned32 + UNITS "milliseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "This option sets the default RDATA backoff + interval. The value is expressed in milliseconds. + The value of 0 indicates no backoff." + ::= { pgmDlrSourceConfigEntry 4 } + + +-- PGM DLR Source Performance Management Table + +pgmDlrSourcePerformanceTable OBJECT-TYPE + SYNTAX SEQUENCE OF PgmDlrSourcePerformanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The table holding per TSI performance + management information related to the + PGM DLR Source sessions." + ::= {pgmDlrSource 4} + +pgmDlrSourcePerformanceEntry OBJECT-TYPE + SYNTAX PgmDlrSourcePerformanceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Per PGM DLR Source performance management + information." + INDEX { pgmDlrSourcePerformanceGlobalId, + pgmDlrSourcePerformanceSourcePort } + ::= { pgmDlrSourcePerformanceTable 1 } + +PgmDlrSourcePerformanceEntry ::= SEQUENCE { + pgmDlrSourcePerformanceGlobalId + OCTET STRING, + pgmDlrSourcePerformanceSourcePort + Unsigned32, + pgmDlrSourceRdataMsgsSent + Counter32, + pgmDlrSourceRdataBytesSent + Counter32, + pgmDlrSourceBytesSent + Counter32, + pgmDlrSourceNaksRcvd + Counter32, + pgmDlrSourceNaksIgnored + Counter32, + pgmDlrSourceNakErrors + Counter32, + pgmDlrSourceDiscards + Counter32, + pgmDlrSourceCksumErrors + Counter32, + pgmDlrSourceNNaksSent + Counter32, + pgmDlrSourceBytesBuffered + Counter32, + pgmDlrSourceMsgsBuffered + Counter32, + pgmDlrSourceParityBytesRetransmitted + Counter32, + pgmDlrSourceSelectiveBytesRetransmited + Counter32, + pgmDlrSourceParityMsgsRetransmitted + Counter32, + pgmDlrSourceSelectiveMsgsRetransmitted + Counter32, + pgmDlrSourceBytesAdmit + Counter32, + pgmDlrSourceMsgsAdmit + Counter32, + pgmDlrSourceNakPacketsReceived + Counter32, + pgmDlrSourceParityNakPacketsReceived + Counter32, + pgmDlrSourceSelectiveNakPacketsReceived + Counter32, + pgmDlrSourceParityNaksReceived + Counter32, + pgmDlrSourceSelectiveNaksReceived + Counter32, + pgmDlrSourceParityNaksIgnored + Counter32, + pgmDlrSourceSelectiveNaksIgnored + Counter32, + pgmDlrSourceAckErrors + Counter32, + pgmDlrSourceNNakErrors + Counter32, + pgmDlrSourceAckPacketsReceived + Counter32, + pgmDlrSourceNNakPacketsReceived + Counter32, + pgmDlrSourceParityNNakPacketsReceived + Counter32, + pgmDlrSourceSelectiveNNakPacketsReceived + Counter32, + pgmDlrSourceNNaksReceived + Counter32, + pgmDlrSourceParityNNaksReceived + Counter32, + pgmDlrSourceSelectiveNNaksReceived + Counter32 + } + +pgmDlrSourcePerformanceGlobalId OBJECT-TYPE + SYNTAX OCTET STRING (SIZE (12)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Globally unique source identifier (GSI)." + ::= { pgmDlrSourcePerformanceEntry 1 } + +pgmDlrSourcePerformanceSourcePort OBJECT-TYPE + SYNTAX Unsigned32(0..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Source port number." + ::= { pgmDlrSourcePerformanceEntry 2 } + +pgmDlrSourceRdataMsgsSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of Repair Data (RDATA) packets sent for + this PGM DLR." + ::= { pgmDlrSourcePerformanceEntry 3 } + +pgmDlrSourceRdataBytesSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of RDATA bytes sent." + ::= { pgmDlrSourcePerformanceEntry 4 } + +pgmDlrSourceBytesSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes sent. This includes IP and + PGM header and non-data msgs." + ::= { pgmDlrSourcePerformanceEntry 5 } + +pgmDlrSourceNaksRcvd OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAKs received on this TSI." + ::= { pgmDlrSourcePerformanceEntry 6 } + +pgmDlrSourceNaksIgnored OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAKs ignored on this TSI, due to + duplicates." + ::= { pgmDlrSourcePerformanceEntry 7 } + +pgmDlrSourceNakErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of malformed NAKs on this TSI." + ::= { pgmDlrSourcePerformanceEntry 8 } + +pgmDlrSourceDiscards OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of discarded packets on this TSI. + This counter is used to count all discarded + incoming packets per TSI in cases of + duplicates, header and packet errors, etc." + ::= { pgmDlrSourcePerformanceEntry 9 } + +pgmDlrSourceCksumErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of checksum errors on this TSI." + ::= { pgmDlrSourcePerformanceEntry 10 } + +pgmDlrSourceNNaksSent OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of Null NAKs (in number of packets) + sent by this PGM DLR session." + ::= { pgmDlrSourcePerformanceEntry 11 } + +pgmDlrSourceBytesBuffered OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes currently buffered for this + TSI." + ::= { pgmDlrSourcePerformanceEntry 12 } + +pgmDlrSourceMsgsBuffered OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages currently buffered for + this TSI." + ::= { pgmDlrSourcePerformanceEntry 13 } + +pgmDlrSourceParityBytesRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes sent in parity retransmissions." + ::= { pgmDlrSourcePerformanceEntry 14 } + +pgmDlrSourceSelectiveBytesRetransmited OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes sent in selective retransmissions." + ::= { pgmDlrSourcePerformanceEntry 15 } + +pgmDlrSourceParityMsgsRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of parity retransmissions sent." + ::= { pgmDlrSourcePerformanceEntry 16 } + +pgmDlrSourceSelectiveMsgsRetransmitted OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of selective retransmissions sent." + ::= { pgmDlrSourcePerformanceEntry 17 } + +pgmDlrSourceBytesAdmit OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of bytes currently in the rate controled + admit queue. Includes IP header, UDP header if + encapsulated, PGM header, and data." + ::= { pgmDlrSourcePerformanceEntry 18 } + +pgmDlrSourceMsgsAdmit OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages currently in the rate controled + admit queue. Includes data messages, retransmissions, + and SPMs." + ::= { pgmDlrSourcePerformanceEntry 19 } + +pgmDlrSourceNakPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of NAK packets received." + ::= { pgmDlrSourcePerformanceEntry 20 } + +pgmDlrSourceParityNakPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of parity NAK packets received." + ::= { pgmDlrSourcePerformanceEntry 21 } + +pgmDlrSourceSelectiveNakPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of selective NAK packets received." + ::= { pgmDlrSourcePerformanceEntry 22 } + +pgmDlrSourceParityNaksReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual parity NAKs received." + ::= { pgmDlrSourcePerformanceEntry 23 } + +pgmDlrSourceSelectiveNaksReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual selective NAKs received." + ::= { pgmDlrSourcePerformanceEntry 24 } + +pgmDlrSourceParityNaksIgnored OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual parity NAKs ignored." + ::= { pgmDlrSourcePerformanceEntry 25 } + +pgmDlrSourceSelectiveNaksIgnored OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual selective NAKs ignored." + ::= { pgmDlrSourcePerformanceEntry 26 } + +pgmDlrSourceAckErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of ACK packets received with error in + them, different than checksum error." + ::= { pgmDlrSourcePerformanceEntry 27 } + +pgmDlrSourceNNakErrors OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of Null NAK packets received that contain + error, rSifferent than checksum error." + ::= { pgmDlrSourcePerformanceEntry 28 } + +pgmDlrSourceAckPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of ACK packets received." + ::= { pgmDlrSourcePerformanceEntry 29 } + +pgmDlrSourceNNakPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of Null NAKs received." + ::= { pgmDlrSourcePerformanceEntry 30 } + +pgmDlrSourceParityNNakPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of parity Null NAK packets received." + ::= { pgmDlrSourcePerformanceEntry 31 } + +pgmDlrSourceSelectiveNNakPacketsReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of selective Null NAK packets received." + ::= { pgmDlrSourcePerformanceEntry 32 } + +pgmDlrSourceNNaksReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual NAKs, received in Null + NAK packets." + ::= { pgmDlrSourcePerformanceEntry 33 } + +pgmDlrSourceParityNNaksReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual parity NAKs, + received in Null NAK packets." + ::= { pgmDlrSourcePerformanceEntry 34 } + +pgmDlrSourceSelectiveNNaksReceived OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of individual NAKs, + received in Null NAK packets." + ::= { pgmDlrSourcePerformanceEntry 35 } + +-- Notifications + +pgmNotifications OBJECT IDENTIFIER ::= + { pgmNotificationPrefix 0 } + +pgmStart NOTIFICATION-TYPE + STATUS current + DESCRIPTION + "This trap is sent when the pgm snmp agent starts" + ::= { pgmNotifications 1 } + +pgmStop NOTIFICATION-TYPE + STATUS current + DESCRIPTION + "This trap is sent when the pgm snmp agent terminates" + ::= { pgmNotifications 2 } + +-- PGM Source Specific Traps + +pgmNewSourceTrap NOTIFICATION-TYPE + OBJECTS { + pgmSourceSourceGsi, + pgmSourceSourcePortNumber + } + STATUS current + DESCRIPTION + "New Source Session created." + ::= { pgmNotifications 3 } + +pgmClosedSourceTrap NOTIFICATION-TYPE + OBJECTS { + pgmSourceSourceGsi, + pgmSourceSourcePortNumber + } + STATUS current + DESCRIPTION + "Source Session closed." + ::= { pgmNotifications 4 } + +-- PGM Receiver Specific Traps + +pgmNewReceiverTrap NOTIFICATION-TYPE + OBJECTS { + pgmReceiverSourceGsi, + pgmReceiverSourcePortNumber, + pgmReceiverUniqueInstance + } + STATUS current + DESCRIPTION + "New Receiver Session created. + This trap is optional." + ::= { pgmNotifications 5 } + +pgmClosedReceiverTrap NOTIFICATION-TYPE + OBJECTS { + pgmReceiverSourceGsi, + pgmReceiverSourcePortNumber, + pgmReceiverUniqueInstance + } + STATUS current + DESCRIPTION + "Receiver Session closed. + This trap is optional." + ::= { pgmNotifications 6 } + +pgmNakFailuresTrap NOTIFICATION-TYPE + OBJECTS { + pgmReceiverSourceGsi, + pgmReceiverSourcePortNumber, + pgmReceiverUniqueInstance, + pgmReceiverNakFailureThresholdTimer, + pgmReceiverNakFailureThreshold, + pgmReceiverNakFailuresLastInterval, + pgmReceiverLastIntervalNakFailures + } + STATUS current + DESCRIPTION + "The number of unrecovered lost packets + exceeded the threshold limit for the + corresponding threshold interval." + ::= { pgmNotifications 7 } + +-- PGM Dlr Source Specific Traps + +pgmNewDlrSourceTrap NOTIFICATION-TYPE + OBJECTS { + pgmDlrSourceSourceGsi, + pgmDlrSourceSourcePortNumber + } + STATUS current + DESCRIPTION + "New Dlr Source Session created." + ::= { pgmNotifications 8 } + +pgmClosedDlrSourceTrap NOTIFICATION-TYPE + OBJECTS { + pgmDlrSourceSourceGsi, + pgmDlrSourceSourcePortNumber + } + STATUS current + DESCRIPTION + "Dlr Source Session closed." + ::= { pgmNotifications 9 } + +-- Conformance information + +pgmMIBConformance OBJECT IDENTIFIER ::= { pgmMIB 3 } +pgmMIBCompliances OBJECT IDENTIFIER ::= { pgmMIBConformance 1 } +pgmMIBGroups OBJECT IDENTIFIER ::= { pgmMIBConformance 2 } + +-- Compliance statements + +pgmNetworkElementMIBCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for devices running as PGM + Network Elements." + MODULE -- this module + MANDATORY-GROUPS { pgmNetworkElementMIBGroup } + + ::= { pgmMIBCompliances 1 } + +pgmSourceMIBCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for devices running as PGM + sources." + MODULE -- this module + MANDATORY-GROUPS { pgmSourceMIBGroup } + + ::= { pgmMIBCompliances 2 } + +pgmReceiverMIBCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for devices running as PGM + receivers." + MODULE -- this module + MANDATORY-GROUPS { pgmReceiverMIBGroup } + + ::= { pgmMIBCompliances 3 } + +pgmDLRMIBCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for devices running as PGM + designated local repairers (DLR)." + MODULE -- this module + MANDATORY-GROUPS { pgmDLRMIBGroup, + pgmReceiverMIBGroup } + + ::= { pgmMIBCompliances 4 } + +pgmTrapsMIBCompliance MODULE-COMPLIANCE + STATUS current + DESCRIPTION + "The compliance statement for PGM traps." + MODULE -- this module + MANDATORY-GROUPS { pgmTrapsMIBGroup, + pgmTrapsSourceMIBGroup, + pgmTrapsReceiverMIBGroup, + pgmTrapsDlrSourceMIBGroup } + ::= { pgmMIBCompliances 5 } + +-- Units of conformance + +pgmNetworkElementMIBGroup OBJECT-GROUP + OBJECTS { pgmNeEnable, + pgmNeSessionLifeTime, + pgmNeMaxReXmitStates, + pgmNeMaxSessions, + pgmNeTotalInterfacesNumberOfEntries, + pgmNeIfPgmEnable, + pgmNeIfNakRptInterval, + pgmNeIfNakRptRate, + pgmNeIfNakRdataInterval, + pgmNeIfNakEliminateInterval, + pgmNeIfReXmitStates, + pgmNeIfReXmitTimedOut, + pgmNeIfInSpms, + pgmNeIfOutSpms, + pgmNeIfInParitySpms, + pgmNeIfOutParitySpms, + pgmNeIfInRdata, + pgmNeIfOutRdata, + pgmNeIfInParityRdata, + pgmNeIfOutParityRdata, + pgmNeIfInRdataNoSessionErrors, + pgmNeIfUniqueNaks, + pgmNeIfInNaks, + pgmNeIfOutNaks, + pgmNeIfUniqueParityNaks, + pgmNeIfInParityNaks, + pgmNeIfOutParityNaks, + pgmNeIfInNakNoSessionErrors, + pgmNeIfInNakSeqErrors, + pgmNeIfInParityNakTgErrors, + pgmNeIfInNnaks, + pgmNeIfOutNnaks, + pgmNeIfInParityNnaks, + pgmNeIfOutParityNnaks, + pgmNeIfInNnakNoSessionErrors, + pgmNeIfInNcfs, + pgmNeIfOutNcfs, + pgmNeIfInParityNcfs, + pgmNeIfOutParityNcfs, + pgmNeIfInNcfNoSessionErrors, + pgmNeIfInRedirectNcfs, + pgmNeIfMalformed, + pgmNeIfSpmFromSource, + pgmNeIfSpmBadSqn, + pgmNeIfSpmError, + pgmNeIfPollRandomIgnore, + pgmNeIfPollTsiStateError, + pgmNeIfPollParentError, + pgmNeIfPollTypeError, + pgmNeIfPollError, + pgmNeIfPollSuccess, + pgmNeIfPollOriginated, + pgmNeIfPolrNoState, + pgmNeIfPolrError, + pgmNeIfPolrParityError, + pgmNeIfPolrSuccess, + pgmNeIfPolrOriginated, + pgmNeIfNcfError, + pgmNeIfNcfParityError, + pgmNeIfNcfPartialParity, + pgmNeIfNcfReceived, + pgmNeIfNcfAnticipated, + pgmNeIfNcfRedirecting, + pgmNeIfNakEliminated, + pgmNeIfNakError, + pgmNeIfNakParityError, + pgmNeIfNNakEliminated, + pgmNeIfNNakError, + pgmNeIfNNakParityError, + pgmNeIfNNakCongestionReports, + pgmNeIfNakRetryExpired, + pgmNeIfNakRetryExpiredDLR, + pgmNeIfNakForwardedDLR, + pgmNeIfNakRetransmitted, + pgmNeIfRdataEliminatedOIF, + pgmNeIfRdataEliminatedSqn, + pgmNeIfInRdataFragments, + pgmNeIfRdataFragmentsNoSessionErrors, + pgmNeIfRdataFragmentsEliminatedOIF, + pgmNeIfRdataFragmentsEliminatedSqn, + pgmNeIfOutRdataFragments, + pgmNeTotalTsiNumberOfEntries, + pgmNeTsiStateBits, + pgmNeTsiDataDestinationPort, + pgmNeTsiSourceAddress, + pgmNeTsiGroupAddress, + pgmNeTsiUpstreamAddress, + pgmNeTsiUpstreamIfIndex, + pgmNeTsiDlrAddress, + pgmNeTsiSessionTrailEdgeSeq, + pgmNeTsiSessionIncrSeq, + pgmNeTsiLeadEdgeSeq, + pgmNeTsiInSpms, + pgmNeTsiOutSpms, + pgmNeTsiInParitySpms, + pgmNeTsiOutParitySpms, + pgmNeTsiTotalReXmitStates, + pgmNeTsiTotalReXmitTimedOut, + pgmNeTsiInRdata, + pgmNeTsiOutRdata, + pgmNeTsiInParityRdata, + pgmNeTsiOutParityRdata, + pgmNeTsiInRdataNoStateErrors, + pgmNeTsiUniqueNaks, + pgmNeTsiInNaks, + pgmNeTsiOutNaks, + pgmNeTsiUniqueParityNaks, + pgmNeTsiInParityNaks, + pgmNeTsiOutParityNaks, + pgmNeTsiInNakSeqErrors, + pgmNeTsiInNnaks, + pgmNeTsiOutNnaks, + pgmNeTsiInParityNnaks, + pgmNeTsiOutParityNnaks, + pgmNeTsiInNcfs, + pgmNeTsiOutNcfs, + pgmNeTsiInParityNcfs, + pgmNeTsiOutParityNcfs, + pgmNeTsiSpmSequenceNumber, + pgmNeTsiTransmissionGroupSize, + pgmNeTsiTimeout, + pgmNeTsiLastTtl, + pgmNeTsiLinkLossRate, + pgmNeTsiPathLossRate, + pgmNeTsiReceiverLossRate, + pgmNeTsiCongestionReportLead, + pgmNeTsiCongestionReportWorstReceiver, + pgmNeTsiRtxNumberOfEntries, + pgmNeTsiRtxReqParityTgCount, + pgmNeTsiRtxTimeout, + pgmNeTsiRtxStateBits, + pgmNeTsiRtxIfNumberOfEntries, + pgmNeTsiRtxIfPacketCount, + pgmNeTsiPolrNumberOfEntries, + pgmNeTsiPolrSequenceNumber, + pgmNeTsiPollNumberOfEntries, + pgmNeTsiPollSequence, + pgmNeTsiPollChildBackoff, + pgmNeTsiPollMask, + pgmNeTsiPollPeriod, + pgmNeTsiPollCount, + pgmNeTsiPollTimeout } + STATUS current + DESCRIPTION + "A collection of objects to support + management of PGM Network Elements." + ::= { pgmMIBGroups 1 } + +pgmSourceMIBGroup OBJECT-GROUP + OBJECTS { pgmSourceSaveDefaults, + pgmSourceLastUpdateTime, + pgmSourceDefaultTtl, + pgmSourceDefaultAdvMode, + pgmSourceDefaultLateJoin, + pgmSourceDefaultTxwMaxRte, + pgmSourceDefaultTxwSecs, + pgmSourceDefaultTxwAdvSecs, + pgmSourceDefaultAdvIvl, + pgmSourceDefaultSpmIvl, + pgmSourceDefaultSpmHeartBeatIvlMin, + pgmSourceDefaultSpmHeartBeatIvlMax, + pgmSourceDefaultRdataBackoffIvl, + pgmSourceDefaultFECProactiveParitySize, + pgmSourceDefaultGroupAddress, + pgmSourceUpdateSinceLastSave, + pgmSourceNumberOfEntries, + pgmSourceSourceAddress, + pgmSourceGroupAddress, + pgmSourceDestPort, + pgmSourceSourceGsi, + pgmSourceSourcePortNumber, + pgmSourceTtl, + pgmSourceAdvMode, + pgmSourceLateJoin, + pgmSourceTxwMaxRte, + pgmSourceTxwSecs, + pgmSourceTxwAdvSecs, + pgmSourceAdvIvl, + pgmSourceSpmIvl, + pgmSourceSpmHeartBeatIvlMin, + pgmSourceSpmHeartBeatIvlMax, + pgmSourceRdataBackoffIvl, + pgmSourceFEC, + pgmSourceFECTransmissionGrpSize, + pgmSourceFECProactiveParitySize, + pgmSourceSpmPathAddress, + pgmSourceDataBytesSent, + pgmSourceDataMsgsSent, + pgmSourceBytesBuffered, + pgmSourceMsgsBuffered, + pgmSourceBytesRetransmitted, + pgmSourceMsgsRetransmitted, + pgmSourceBytesSent, + pgmSourceRawNaksReceived, + pgmSourceNaksIgnored, + pgmSourceCksumErrors, + pgmSourceMalformedNaks, + pgmSourcePacketsDiscarded, + pgmSourceNaksRcvd, + pgmSourceParityBytesRetransmitted, + pgmSourceSelectiveBytesRetransmited, + pgmSourceParityMsgsRetransmitted, + pgmSourceSelectiveMsgsRetransmitted, + pgmSourceBytesAdmit, + pgmSourceMsgsAdmit, + pgmSourceParityNakPacketsReceived, + pgmSourceSelectiveNakPacketsReceived, + pgmSourceParityNaksReceived, + pgmSourceSelectiveNaksReceived, + pgmSourceParityNaksIgnored, + pgmSourceSelectiveNaksIgnored, + pgmSourceAckErrors, + pgmSourcePgmCCAcker, + pgmSourceTransmissionCurrentRate, + pgmSourceAckPacketsReceived, + pgmSourceNNakPacketsReceived, + pgmSourceParityNNakPacketsReceived, + pgmSourceSelectiveNNakPacketsReceived, + pgmSourceNNaksReceived, + pgmSourceParityNNaksReceived, + pgmSourceSelectiveNNaksReceived, + pgmSourceNNakErrors } + STATUS current + DESCRIPTION + "A collection of objects to support management of + PGM sources." + ::= { pgmMIBGroups 2 } + +pgmReceiverMIBGroup OBJECT-GROUP + OBJECTS { pgmReceiverSaveDefaults, + pgmReceiverLastUpdateTime, + pgmReceiverDefaultNakBackoffIvl, + pgmReceiverDefaultNakRepeatIvl, + pgmReceiverDefaultNakNcfRetries, + pgmReceiverDefaultNakRdataIvl, + pgmReceiverDefaultNakDataRetries, + pgmReceiverDefaultSendNaks, + pgmReceiverDefaultLateJoin, + pgmReceiverDefaultNakTtl, + pgmReceiverDefaultDeliveryOrder, + pgmReceiverDefaultNextPgmHop, + pgmReceiverDefaultGroupAddress, + pgmReceiverUpdateSinceLastSave, + pgmReceiverDefaultNakFailureThresholdTimer, + pgmReceiverDefaultNakFailureThreshold, + pgmReceiverNumberOfEntries, + pgmReceiverGroupAddress, + pgmReceiverDestPort, + pgmReceiverSourceAddress, + pgmReceiverLastHop, + pgmReceiverSourceGsi, + pgmReceiverSourcePortNumber, + pgmReceiverUniqueInstance, + pgmReceiverNakBackoffIvl, + pgmReceiverNakRepeatIvl, + pgmReceiverNakNcfRetries, + pgmReceiverNakRdataIvl, + pgmReceiverNakDataRetries, + pgmReceiverSendNaks, + pgmReceiverLateJoin, + pgmReceiverNakTtl, + pgmReceiverDeliveryOrder, + pgmReceiverMcastNaks, + pgmReceiverNakFailureThresholdTimer, + pgmReceiverNakFailureThreshold, + pgmReceiverDataBytesReceived, + pgmReceiverDataMsgsReceived, + pgmReceiverNaksSent, + pgmReceiverNaksRetransmitted, + pgmReceiverNakFailures, + pgmReceiverBytesReceived, + pgmReceiverNaksSuppressed, + pgmReceiverCksumErrors, + pgmReceiverMalformedSpms, + pgmReceiverMalformedOdata, + pgmReceiverMalformedRdata, + pgmReceiverMalformedNcfs, + pgmReceiverPacketsDiscarded, + pgmReceiverLosses, + pgmReceiverBytesDeliveredToApp, + pgmReceiverMsgsDeliveredToApp, + pgmReceiverDupSpms, + pgmReceiverDupDatas, + pgmReceiverDupParities, + pgmReceiverNakPacketsSent, + pgmReceiverParityNakPacketsSent, + pgmReceiverSelectiveNakPacketsSent, + pgmReceiverParityNaksSent, + pgmReceiverSelectiveNaksSent, + pgmReceiverParityNaksRetransmitted, + pgmReceiverSelectiveNaksRetransmitted, + pgmReceiverNaksFailed, + pgmReceiverParityNaksFailed, + pgmReceiverSelectiveNaksFailed, + pgmReceiverNaksFailedRxwAdvanced, + pgmReceiverNaksFaledNcfRetriesExceeded, + pgmReceiverNaksFailedDataRetriesExceeded, + pgmReceiverNaksFailedGenExpired, + pgmReceiverNakFailuresDelivered, + pgmReceiverParityNaksSuppressed, + pgmReceiverSelectiveNaksSuppressed, + pgmReceiverNakErrors, + pgmReceiverOutstandingParityNaks, + pgmReceiverOutstandingSelectiveNaks, + pgmReceiverLastActivity, + pgmReceiverNakSvcTimeMin, + pgmReceiverNakSvcTimeMean, + pgmReceiverNakSvcTimeMax, + pgmReceiverNakFailTimeMin, + pgmReceiverNakFailTimeMean, + pgmReceiverNakFailTimeMax, + pgmReceiverNakTransmitMin, + pgmReceiverNakTransmitMean, + pgmReceiverNakTransmitMax, + pgmReceiverAcksSent, + pgmReceiverRxwTrail, + pgmReceiverRxwLead, + pgmReceiverNakFailuresLastInterval, + pgmReceiverLastIntervalNakFailures } + STATUS current + DESCRIPTION + "A collection of objects to support management of + PGM receivers." + ::= { pgmMIBGroups 3 } + +pgmDLRMIBGroup OBJECT-GROUP + OBJECTS { pgmDlrSaveDefaults, + pgmDlrLastUpdateTime, + pgmDlrGroupAddress, + pgmDlrCacheRtx, + pgmDlrActivityIvl, + pgmDlrMaxRate, + pgmDlrParentNeAddr, + pgmDlrUpdateSinceLastSave, + pgmDlrSourceNumberOfEntries, + pgmDlrSourceGroupAddress, + pgmDlrSourceSourceGsi, + pgmDlrSourceSourcePortNumber, + pgmDlrSourceGroupTtl, + pgmDlrSourceRdataBackoffIvl, + pgmDlrSourceRdataMsgsSent, + pgmDlrSourceRdataBytesSent, + pgmDlrSourceBytesSent, + pgmDlrSourceNaksRcvd, + pgmDlrSourceNaksIgnored, + pgmDlrSourceNakErrors, + pgmDlrSourceDiscards, + pgmDlrSourceCksumErrors, + pgmDlrSourceNNaksSent, + pgmDlrSourceBytesBuffered, + pgmDlrSourceMsgsBuffered, + pgmDlrSourceParityBytesRetransmitted, + pgmDlrSourceSelectiveBytesRetransmited, + pgmDlrSourceParityMsgsRetransmitted, + pgmDlrSourceSelectiveMsgsRetransmitted, + pgmDlrSourceBytesAdmit, + pgmDlrSourceMsgsAdmit, + pgmDlrSourceNakPacketsReceived, + pgmDlrSourceParityNakPacketsReceived, + pgmDlrSourceSelectiveNakPacketsReceived, + pgmDlrSourceParityNaksReceived, + pgmDlrSourceSelectiveNaksReceived, + pgmDlrSourceParityNaksIgnored, + pgmDlrSourceSelectiveNaksIgnored, + pgmDlrSourceAckErrors, + pgmDlrSourceNNakErrors, + pgmDlrSourceAckPacketsReceived, + pgmDlrSourceNNakPacketsReceived, + pgmDlrSourceParityNNakPacketsReceived, + pgmDlrSourceSelectiveNNakPacketsReceived, + pgmDlrSourceNNaksReceived, + pgmDlrSourceParityNNaksReceived, + pgmDlrSourceSelectiveNNaksReceived } + STATUS current + DESCRIPTION + "A collection of objects to support management of + PGM designated local repairers (DLR)." + ::= { pgmMIBGroups 4 } + +pgmTrapsMIBGroup NOTIFICATION-GROUP + NOTIFICATIONS { pgmStart, + pgmStop } + STATUS current + DESCRIPTION + "A collection of objects to support pgm + specific traps." + ::= { pgmMIBGroups 5 } + +pgmTrapsSourceMIBGroup NOTIFICATION-GROUP + NOTIFICATIONS { pgmNewSourceTrap, + pgmClosedSourceTrap } + STATUS current + DESCRIPTION + "A collection of objects to support pgm + source specific traps." + ::= { pgmMIBGroups 6 } + +pgmTrapsReceiverMIBGroup NOTIFICATION-GROUP + NOTIFICATIONS { pgmNewReceiverTrap, + pgmClosedReceiverTrap, + pgmNakFailuresTrap } + STATUS current + DESCRIPTION + "A collection of objects to support pgm + receiver specific traps." + ::= { pgmMIBGroups 7 } + +pgmTrapsDlrSourceMIBGroup NOTIFICATION-GROUP + NOTIFICATIONS { pgmNewDlrSourceTrap, + pgmClosedDlrSourceTrap } + STATUS current + DESCRIPTION + "A collection of objects to support pgm + dlr source specific traps." + ::= { pgmMIBGroups 8 } + + +END + diff --git a/3rdparty/openpgm-svn-r1135/pgm/mld-semantics.txt b/3rdparty/openpgm-svn-r1135/pgm/mld-semantics.txt new file mode 100644 index 0000000..135400d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/mld-semantics.txt @@ -0,0 +1,52 @@ + previous request following request return + ----------------- ----------------- ----------- + MCAST_JOIN_GROUP MCAST_JOIN_GROUP EADDRINUSE + MCAST_JOIN_GROUP MCAST_LEAVE_GROUP 0 + MCAST_JOIN_GROUP MCAST_JOIN_SOURCE_GROUP EINVAL + MCAST_JOIN_GROUP MCAST_LEAVE_SOURCE_GROUP EINVAL + MCAST_JOIN_GROUP MCAST_BLOCK_SOURCE 0 + MCAST_JOIN_SOURCE_GROUP MCAST_JOIN_GROUP EADDRINUSE + MCAST_JOIN_SOURCE_GROUP MCAST_LEAVE_GROUP 0 + MCAST_JOIN_SOURCE_GROUP MCAST_JOIN_SOURCE_GROUP (*1) + MCAST_JOIN_SOURCE_GROUP MCAST_LEAVE_SOURCE_GROUP (*2) + MCAST_JOIN_SOURCE_GROUP MCAST_BLOCK_SOURCE EINVAL + MCAST_JOIN_SOURCE_GROUP MCAST_UNBLOCK_SOURCE EINVAL + MCAST_BLOCK_SOURCE MCAST_JOIN_GROUP EADDRINUSE + MCAST_BLOCK_SOURCE MCAST_LEAVE_GROUP 0 + MCAST_BLOCK_SOURCE MCAST_JOIN_SOURCE_GROUP EINVAL + MCAST_BLOCK_SOURCE MCAST_LEAVE_SOURCE_GROUP EINVAL + MCAST_BLOCK_SOURCE MCAST_BLOCK_SOURCE (*1) + MCAST_BLOCK_SOURCE MCAST_UNBLOCK_SOURCE (*2) + +(*1) EADDRNOTAVAIL if source address is same of filtered one. Otherwise 0. +(*2) EADDRNOTAVAIL if source address is not same of filtered one. Otherwise 0. + + +http://planete.inria.fr/Hitoshi.Asaeda/mldv2/README.txt + + +The following steps apply for any-source applications: + + Use MCAST_JOIN_GROUP to join a group. + Use MCAST_BLOCK_SOURCE to turn off a given source, if required. + Use MCAST_UNBLOCK_SOURCE to re-allow a blocked source, if required. + Use MCAST_LEAVE_GROUP to leave the group. + +The following steps apply for controlled-source applications: + + Use MCAST_JOIN_SOURCE_GROUP to join each group/source pair. + Use MCAST_LEAVE_SOURCE_GROUP to leave each group/source, or use MCAST_LEAVE_GROUP to leave all sources, if the same group address is used by all sources. + +The following steps apply for any-source applications: + + Use IP_ADD_MEMBERSHIP to join a group (IPV6_ADD_MEMBERSHIP for IPv6). + Use IP_BLOCK_SOURCE to turn off a given source, if required. + Use IP_UNBLOCK_SOURCE to re-allow a blocked source, if required. + Use IP_DROP_MEMBERSHIP to leave the group (IPV6_DROP_MEMBERSHIP for IPv6). + +The following steps apply for controlled-source applications: + + Use IP_ADD_SOURCE_MEMBERSHIP to join each group/source pair. + Use IP_DROP_SOURCE_MEMBERSHIP to leave each group/source, or use IP_DROP_MEMBERSHIP to leave all sources, if the same group address is used by all sources. + +http://msdn.microsoft.com/en-us/library/ms738558(VS.85).aspx diff --git a/3rdparty/openpgm-svn-r1135/pgm/msfec.txt b/3rdparty/openpgm-svn-r1135/pgm/msfec.txt new file mode 100644 index 0000000..4b2c23a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/msfec.txt @@ -0,0 +1,33 @@ +FEC parameters for Microsoft's PGM stack + + +FECBlockSize (n) [FECGroupSize+1, 255] +Maximum number of packets that can be sent for any group, including original data and parity packets. Maximum and default value is 255. + +FECProActivePackets +Number of packets to send proactively with each group. Use this option when the network is dispersed, and upstream NAK requests are expensive. + +FECGroupSize (k) [2, 128] +Number of packets to be treated as one group for the purpose of computing parity packets. Group size must be a power of two. In lossy networks, keep the group size relatively small. + +fFECOnDemandParityEnabled +Specifies whether the sender is enabled for sending parity repair packets. When TRUE, receivers should only request parity repair packets. + + +Reed Solomon codes: + + encode/decode time (us) +RS(255, 2) 4/6 +RS(255, 4) 7/10 +RS(255, 8) 14/18 +RS(255, 16) 29/34 +RS(255, 32) 57/64 +RS(255, 64) 119/134 +RS(255, 128) 236/fail(278) + +reference platform: Intel Xeon CPU 3.20Ghz + + +Implementation exact copy of Luigi Rizzo FEC code as demonstrated in RMDP: + +http://info.iet.unipi.it/~luigi/fec.html diff --git a/3rdparty/openpgm-svn-r1135/pgm/nametoindex.c b/3rdparty/openpgm-svn-r1135/pgm/nametoindex.c new file mode 100644 index 0000000..28444d1 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/nametoindex.c @@ -0,0 +1,249 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Windows interface name to interface index function. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef _WIN32 +# include +# include +#endif +#include +#include + + +//#define NAMETOINDEX_DEBUG + +#define MAX_TRIES 3 +#define DEFAULT_BUFFER_SIZE 4096 + + +#ifdef _WIN32 +static inline +void* +_pgm_heap_alloc ( + const size_t n_bytes + ) +{ +# ifdef CONFIG_USE_HEAPALLOC + return HeapAlloc (GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, n_bytes); +# else + return pgm_malloc (n_bytes); +# endif +} + +static inline +void +_pgm_heap_free ( + void* mem + ) +{ +# ifdef CONFIG_USE_HEAPALLOC + HeapFree (GetProcessHeap(), 0, mem); +# else + pgm_free (mem); +# endif +} + +/* Retrieve adapter index via name. + * Wine edition: First try GetAdapterIndex() then fallback to enumerating + * adapters via GetAdaptersInfo(). + * + * On error returns zero, no errors are defined. + */ + +static +unsigned /* type matching if_nametoindex() */ +_pgm_getadaptersinfo_nametoindex ( + const sa_family_t iffamily, + const char* ifname + ) +{ + pgm_return_val_if_fail (NULL != ifname, 0); + + pgm_assert (AF_INET6 != iffamily); + + DWORD dwRet, ifIndex; + ULONG ulOutBufLen = DEFAULT_BUFFER_SIZE; + PIP_ADAPTER_INFO pAdapterInfo = NULL; + PIP_ADAPTER_INFO pAdapter = NULL; + +/* loop to handle interfaces coming online causing a buffer overflow + * between first call to list buffer length and second call to enumerate. + */ + for (unsigned i = MAX_TRIES; i; i--) + { + pgm_debug ("IP_ADAPTER_INFO buffer length %lu bytes.", ulOutBufLen); + pAdapterInfo = (IP_ADAPTER_INFO*)_pgm_heap_alloc (ulOutBufLen); + dwRet = GetAdaptersInfo (pAdapterInfo, &ulOutBufLen); + if (ERROR_BUFFER_OVERFLOW == dwRet) { + _pgm_heap_free (pAdapterInfo); + pAdapterInfo = NULL; + } else { + break; + } + } + + switch (dwRet) { + case ERROR_SUCCESS: /* NO_ERROR */ + break; + case ERROR_BUFFER_OVERFLOW: + pgm_warn (_("GetAdaptersInfo repeatedly failed with ERROR_BUFFER_OVERFLOW.")); + if (pAdapterInfo) + _pgm_heap_free (pAdapterInfo); + return 0; + default: + pgm_warn (_("GetAdaptersInfo failed")); + if (pAdapterInfo) + _pgm_heap_free (pAdapterInfo); + return 0; + } + + for (pAdapter = pAdapterInfo; + pAdapter; + pAdapter = pAdapter->Next) + { + for (IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList; + pIPAddr; + pIPAddr = pIPAddr->Next) + { +/* skip null adapters */ + if (strlen (pIPAddr->IpAddress.String) == 0) + continue; + + if (0 == strncmp (ifname, pAdapter->AdapterName, IF_NAMESIZE)) { + ifIndex = pAdapter->Index; + _pgm_heap_free (pAdapterInfo); + return ifIndex; + } + } + } + + if (pAdapterInfo) + _pgm_heap_free (pAdapterInfo); + return 0; +} + +/* Retrieve adapter index via name. + * Windows edition: First try GetAdapterIndex() then fallback to enumerating + * adapters via GetAdaptersAddresses(). + * + * On error returns zero, no errors are defined. + */ + +static +unsigned /* type matching if_nametoindex() */ +_pgm_getadaptersaddresses_nametoindex ( + const sa_family_t iffamily, + const char* ifname + ) +{ + pgm_return_val_if_fail (NULL != ifname, 0); + + ULONG ifIndex; + DWORD dwSize = DEFAULT_BUFFER_SIZE, dwRet; + IP_ADAPTER_ADDRESSES *pAdapterAddresses = NULL, *adapter; + +/* first see if GetAdapterIndex is working + */ + dwRet = GetAdapterIndex ((const LPWSTR)ifname, &ifIndex); + if (NO_ERROR == dwRet) + return ifIndex; + +/* fallback to finding index via iterating adapter list */ + +/* loop to handle interfaces coming online causing a buffer overflow + * between first call to list buffer length and second call to enumerate. + */ + for (unsigned i = MAX_TRIES; i; i--) + { + pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_pgm_heap_alloc (dwSize); + dwRet = GetAdaptersAddresses (AF_UNSPEC, + GAA_FLAG_SKIP_ANYCAST | + GAA_FLAG_SKIP_DNS_SERVER | + GAA_FLAG_SKIP_FRIENDLY_NAME | + GAA_FLAG_SKIP_MULTICAST, + NULL, + pAdapterAddresses, + &dwSize); + if (ERROR_BUFFER_OVERFLOW == dwRet) { + _pgm_heap_free (pAdapterAddresses); + pAdapterAddresses = NULL; + } else { + break; + } + } + + switch (dwRet) { + case ERROR_SUCCESS: + break; + case ERROR_BUFFER_OVERFLOW: + pgm_warn (_("GetAdaptersAddresses repeatedly failed with ERROR_BUFFER_OVERFLOW")); + if (pAdapterAddresses) + _pgm_heap_free (pAdapterAddresses); + return 0; + default: + pgm_warn (_("GetAdaptersAddresses failed")); + if (pAdapterAddresses) + _pgm_heap_free (pAdapterAddresses); + return 0; + } + + for (adapter = pAdapterAddresses; + adapter; + adapter = adapter->Next) + { + if (0 == strcmp (ifname, adapter->AdapterName)) { + ifIndex = AF_INET6 == iffamily ? adapter->Ipv6IfIndex : adapter->IfIndex; + _pgm_heap_free (pAdapterAddresses); + return ifIndex; + } + } + + if (pAdapterAddresses) + _pgm_heap_free (pAdapterAddresses); + return 0; +} +#endif /* _WIN32 */ + +/* Retrieve interface index for a specified adapter name. + * On error returns zero, no errors are defined. + */ + +unsigned /* type matching if_nametoindex() */ +pgm_if_nametoindex ( +#ifndef _WIN32 + PGM_GNUC_UNUSED const sa_family_t iffamily, +#else + const sa_family_t iffamily, +#endif + const char* ifname + ) +{ + pgm_return_val_if_fail (NULL != ifname, 0); + +#ifndef _WIN32 + return if_nametoindex (ifname); +#elif defined(CONFIG_TARGET_WINE) + return _pgm_getadaptersinfo_nametoindex (iffamily, ifname); +#else + return _pgm_getadaptersaddresses_nametoindex (iffamily, ifname); +#endif +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/nametoindex.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/nametoindex.c.c89.patch new file mode 100644 index 0000000..127eb4a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/nametoindex.c.c89.patch @@ -0,0 +1,89 @@ +--- nametoindex.c 2010-05-21 11:34:30.000000000 +0800 ++++ nametoindex.c89 2010-08-04 12:57:20.000000000 +0800 +@@ -78,6 +78,7 @@ + + pgm_assert (AF_INET6 != iffamily); + ++ { + DWORD dwRet, ifIndex; + ULONG ulOutBufLen = DEFAULT_BUFFER_SIZE; + PIP_ADAPTER_INFO pAdapterInfo = NULL; +@@ -86,7 +87,9 @@ + /* loop to handle interfaces coming online causing a buffer overflow + * between first call to list buffer length and second call to enumerate. + */ +- for (unsigned i = MAX_TRIES; i; i--) ++ { ++ unsigned i; ++ for (i = MAX_TRIES; i; i--) + { + pgm_debug ("IP_ADAPTER_INFO buffer length %lu bytes.", ulOutBufLen); + pAdapterInfo = (IP_ADAPTER_INFO*)_pgm_heap_alloc (ulOutBufLen); +@@ -98,6 +101,7 @@ + break; + } + } ++ } + + switch (dwRet) { + case ERROR_SUCCESS: /* NO_ERROR */ +@@ -118,7 +122,9 @@ + pAdapter; + pAdapter = pAdapter->Next) + { +- for (IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList; ++ { ++ IP_ADDR_STRING *pIPAddr; ++ for (pIPAddr = &pAdapter->IpAddressList; + pIPAddr; + pIPAddr = pIPAddr->Next) + { +@@ -132,11 +138,13 @@ + return ifIndex; + } + } ++ } + } + + if (pAdapterInfo) + _pgm_heap_free (pAdapterInfo); + return 0; ++ } + } + + /* Retrieve adapter index via name. +@@ -155,6 +163,7 @@ + { + pgm_return_val_if_fail (NULL != ifname, 0); + ++ { + ULONG ifIndex; + DWORD dwSize = DEFAULT_BUFFER_SIZE, dwRet; + IP_ADAPTER_ADDRESSES *pAdapterAddresses = NULL, *adapter; +@@ -170,7 +179,9 @@ + /* loop to handle interfaces coming online causing a buffer overflow + * between first call to list buffer length and second call to enumerate. + */ +- for (unsigned i = MAX_TRIES; i; i--) ++ { ++ unsigned i; ++ for (i = MAX_TRIES; i; i--) + { + pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_pgm_heap_alloc (dwSize); + dwRet = GetAdaptersAddresses (AF_UNSPEC, +@@ -188,6 +199,7 @@ + break; + } + } ++ } + + switch (dwRet) { + case ERROR_SUCCESS: +@@ -218,6 +230,7 @@ + if (pAdapterAddresses) + _pgm_heap_free (pAdapterAddresses); + return 0; ++ } + } + #endif /* _WIN32 */ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/net-snmp.txt b/3rdparty/openpgm-svn-r1135/pgm/net-snmp.txt new file mode 100644 index 0000000..549bcc2 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/net-snmp.txt @@ -0,0 +1,34 @@ +net-snmp is hard coded on mib location, only the mib file names can +be specified outside of snmptranslate. + +$ mkdir -p ~/.snmp/mibs +$ cp mibs/PGM-MIB-petrova-01.txt ~/.snmp/mibs + +Basic test: + +$ snmptranslate -m ALL -IR pgmMIB +PGM-MIB::pgmMIB + +Display full pretty tree: + +$ snmptranslate -m ALL -Tp -IR pgmMIB ++--pgmMIB(112) + | + +--pgm(1) + | | + | +--pgmNetworkElement(1) + | | | +... + + +Now the framework tool can be used: + +$ env MIBS="+ALL" mib2c pgmMIB + +... + +To run with SNMP install snmpd, enable "master agentx" and walk: + +$ env MIBS="+ALL" snmpwalk -v 1 -c public localhost pgmMIB +End of MIB + diff --git a/3rdparty/openpgm-svn-r1135/pgm/net.c b/3rdparty/openpgm-svn-r1135/pgm/net.c new file mode 100644 index 0000000..eb5f403 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/net.c @@ -0,0 +1,181 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * network send wrapper. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#ifdef CONFIG_HAVE_POLL +# include +#endif +#ifndef _WIN32 +# include +# include +# include +#endif +#include +#include +#include +#include + + +#define NET_DEBUG + + +#if !defined(ENETUNREACH) && defined(WSAENETUNREACH) +# define ENETUNREACH WSAENETUNREACH +#endif +#if !defined(EHOSTUNREACH) && defined(WSAEHOSTUNREACH) +# define EHOSTUNREACH WSAEHOSTUNREACH +#endif +#if !defined(ENOBUFS) && defined(WSAENOBUFS) +# define ENOBUFS WSAENOBUFS +#endif + + +/* locked and rate regulated sendto + * + * on success, returns number of bytes sent. on error, -1 is returned, and + * errno set appropriately. + */ + +ssize_t +pgm_sendto_hops ( + pgm_sock_t* sock, + bool use_rate_limit, + bool use_router_alert, + int hops, /* -1 == system default */ + const void* restrict buf, + size_t len, + const struct sockaddr* restrict to, + socklen_t tolen + ) +{ + pgm_assert( NULL != sock ); + pgm_assert( NULL != buf ); + pgm_assert( len > 0 ); + pgm_assert( NULL != to ); + pgm_assert( tolen > 0 ); + +#ifdef NET_DEBUG + char saddr[INET_ADDRSTRLEN]; + pgm_sockaddr_ntop (to, saddr, sizeof(saddr)); + pgm_debug ("pgm_sendto (sock:%p use_rate_limit:%s use_router_alert:%s buf:%p len:%zu to:%s [toport:%d] tolen:%d)", + (const void*)sock, + use_rate_limit ? "TRUE" : "FALSE", + use_router_alert ? "TRUE" : "FALSE", + (const void*)buf, + len, + saddr, + ntohs (((const struct sockaddr_in*)to)->sin_port), + (int)tolen); +#endif + + const int send_sock = use_router_alert ? sock->send_with_router_alert_sock : sock->send_sock; + + if (use_rate_limit && + !pgm_rate_check (&sock->rate_control, len, sock->is_nonblocking)) + { + errno = ENOBUFS; + return (const ssize_t)-1; + } + + if (!use_router_alert && sock->can_send_data) + pgm_mutex_lock (&sock->send_mutex); + if (-1 != hops) + pgm_sockaddr_multicast_hops (send_sock, sock->send_gsr.gsr_group.ss_family, hops); + + ssize_t sent = sendto (send_sock, buf, len, 0, to, (socklen_t)tolen); + pgm_debug ("sendto returned %zd", sent); + if (sent < 0) { + int save_errno = pgm_sock_errno(); + if (PGM_UNLIKELY(errno != ENETUNREACH && /* Network is unreachable */ + errno != EHOSTUNREACH && /* No route to host */ + errno != EAGAIN)) /* would block on non-blocking send */ + { +#ifdef CONFIG_HAVE_POLL +/* poll for cleared socket */ + struct pollfd p = { + .fd = send_sock, + .events = POLLOUT, + .revents = 0 + }; + const int ready = poll (&p, 1, 500 /* ms */); +#else + fd_set writefds; + FD_ZERO(&writefds); + FD_SET(send_sock, &writefds); + struct timeval tv = { + .tv_sec = 0, + .tv_usec = 500 /* ms */ * 1000 + }; + const int ready = select (1, NULL, &writefds, NULL, &tv); +#endif /* CONFIG_HAVE_POLL */ + if (ready > 0) + { + sent = sendto (send_sock, buf, len, 0, to, (socklen_t)tolen); + if ( sent < 0 ) + { + save_errno = pgm_sock_errno(); + pgm_warn (_("sendto() %s failed: %s"), + inet_ntoa( ((const struct sockaddr_in*)to)->sin_addr ), + pgm_sock_strerror (save_errno)); + } + } + else if (ready == 0) + { + pgm_warn (_("sendto() %s failed: socket timeout."), + inet_ntoa( ((const struct sockaddr_in*)to)->sin_addr )); + } + else + { + save_errno = pgm_sock_errno(); + pgm_warn (_("blocked socket failed: %s"), + pgm_sock_strerror (save_errno)); + } + } + } + +/* revert to default value hop limit */ + if (-1 != hops) + pgm_sockaddr_multicast_hops (send_sock, sock->send_gsr.gsr_group.ss_family, sock->hops); + if (!use_router_alert && sock->can_send_data) + pgm_mutex_unlock (&sock->send_mutex); + return sent; +} + +/* socket helper, for setting pipe ends non-blocking + * + * on success, returns 0. on error, returns -1, and sets errno appropriately. + */ + +int +pgm_set_nonblocking ( + int fd[2] + ) +{ +/* pre-conditions */ + pgm_assert (fd[0]); + pgm_assert (fd[1]); + + pgm_sockaddr_nonblocking (fd[0], TRUE); + pgm_sockaddr_nonblocking (fd[1], TRUE); + return 0; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/net.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/net.c.c89.patch new file mode 100644 index 0000000..fd1d1f0 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/net.c.c89.patch @@ -0,0 +1,67 @@ +--- net.c 2010-05-21 11:35:44.000000000 +0800 ++++ net.c89 2010-08-04 15:21:42.000000000 +0800 +@@ -72,19 +72,22 @@ + pgm_assert( tolen > 0 ); + + #ifdef NET_DEBUG ++ { + char saddr[INET_ADDRSTRLEN]; + pgm_sockaddr_ntop (to, saddr, sizeof(saddr)); +- pgm_debug ("pgm_sendto (sock:%p use_rate_limit:%s use_router_alert:%s buf:%p len:%zu to:%s [toport:%d] tolen:%d)", ++ pgm_debug ("pgm_sendto (sock:%p use_rate_limit:%s use_router_alert:%s buf:%p len:%lu to:%s [toport:%d] tolen:%d)", + (const void*)sock, + use_rate_limit ? "TRUE" : "FALSE", + use_router_alert ? "TRUE" : "FALSE", + (const void*)buf, +- len, ++ (unsigned long)len, + saddr, + ntohs (((const struct sockaddr_in*)to)->sin_port), + (int)tolen); ++ } + #endif + ++ { + const int send_sock = use_router_alert ? sock->send_with_router_alert_sock : sock->send_sock; + + if (use_rate_limit && +@@ -97,8 +100,9 @@ + if (!use_router_alert && sock->can_send_data) + pgm_mutex_lock (&sock->send_mutex); + ++ { + ssize_t sent = sendto (send_sock, buf, len, 0, to, (socklen_t)tolen); +- pgm_debug ("sendto returned %zd", sent); ++ pgm_debug ("sendto returned %ld", (signed long)sent); + if (sent < 0) { + int save_errno = pgm_sock_errno(); + if (PGM_UNLIKELY(errno != ENETUNREACH && /* Network is unreachable */ +@@ -114,14 +118,14 @@ + }; + const int ready = poll (&p, 1, 500 /* ms */); + #else ++ int ready; + fd_set writefds; ++ struct timeval tv; + FD_ZERO(&writefds); + FD_SET(send_sock, &writefds); +- struct timeval tv = { +- .tv_sec = 0, +- .tv_usec = 500 /* ms */ * 1000 +- }; +- const int ready = select (1, NULL, &writefds, NULL, &tv); ++ tv.tv_sec = 0; ++ tv.tv_usec = 500 /* ms */ * 1000; ++ ready = select (1, NULL, &writefds, NULL, &tv); + #endif /* CONFIG_HAVE_POLL */ + if (ready > 0) + { +@@ -151,6 +155,8 @@ + if (!use_router_alert && sock->can_send_data) + pgm_mutex_unlock (&sock->send_mutex); + return sent; ++ } ++ } + } + + /* socket helper, for setting pipe ends non-blocking diff --git a/3rdparty/openpgm-svn-r1135/pgm/net_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/net_unittest.c new file mode 100644 index 0000000..fc684ca --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/net_unittest.c @@ -0,0 +1,375 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for network send wrapper. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include + + +/* mock state */ + +#define pgm_rate_check mock_pgm_rate_check +#define sendto mock_sendto +#define poll mock_poll +#define select mock_select +#define fcntl mock_fcntl + +#define NET_DEBUG +#include "net.c" + + +static +pgm_sock_t* +generate_sock (void) +{ + pgm_sock_t* sock = g_malloc0 (sizeof(pgm_sock_t)); + return sock; +} + +static +char* +flags_string ( + int flags + ) +{ + static char s[1024]; + + s[0] = '\0'; + if (flags & MSG_OOB) + strcat (s, "MSG_OOB"); +#define MSG(flag) \ + do { \ + if (flags & flag) { \ + strcat (s, s[0] ? ("|" #flag) : (#flag)); \ + } \ + } while (0) +#ifdef MSG_PEEK + MSG(MSG_PEEK); +#endif +#ifdef MSG_DONTROUTE + MSG(MSG_DONTROUTE); +#endif +#ifdef MSG_CTRUNC + MSG(MSG_CTRUNC); +#endif +#ifdef MSG_PROXY + MSG(MSG_PROXY); +#endif +#ifdef MSG_TRUNC + MSG(MSG_TRUNC); +#endif +#ifdef MSG_DONTWAIT + MSG(MSG_DONTWAIT); +#endif +#ifdef MSG_EOR + MSG(MSG_EOR); +#endif +#ifdef MSG_WAITALL + MSG(MSG_WAITALL); +#endif +#ifdef MSG_FIN + MSG(MSG_FIN); +#endif +#ifdef MSG_SYN + MSG(MSG_SYN); +#endif +#ifdef MSG_CONFIRM + MSG(MSG_CONFIRM); +#endif +#ifdef MSG_RST + MSG(MSG_RST); +#endif +#ifdef MSG_ERRQUEUE + MSG(MSG_ERRQUEUE); +#endif +#ifdef MSG_NOSIGNAL + MSG(MSG_NOSIGNAL); +#endif +#ifdef MSG_MORE + MSG(MSG_MORE); +#endif +#ifdef MSG_CMSG_CLOEXEC + MSG(MSG_CMSG_CLOEXEC); +#endif + if (!s[0]) { + if (flags) + sprintf (s, "0x%x", flags); + else + strcpy (s, "0"); + } + return s; +} + + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_rate_check ( + pgm_rate_t* bucket, + const size_t data_size, + const bool is_nonblocking + ) +{ + g_debug ("mock_pgm_rate_check (bucket:%p data-size:%zu is-nonblocking:%s)", + (gpointer)bucket, data_size, is_nonblocking ? "TRUE" : "FALSE"); + return TRUE; +} + +ssize_t +mock_sendto ( + int s, + const void* buf, + size_t len, + int flags, + const struct sockaddr* to, + socklen_t tolen + ) +{ + char saddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop (to, saddr, sizeof(saddr)); + g_debug ("mock_sendto (s:%i buf:%p len:%d flags:%s to:%s tolen:%d)", + s, buf, len, flags_string (flags), saddr, tolen); + return len; +} + +#ifdef CONFIG_HAVE_POLL +int +mock_poll ( + struct pollfd* fds, + nfds_t nfds, + int timeout + ) +{ + g_debug ("mock_poll (fds:%p nfds:%d timeout:%d)", + (gpointer)fds, (int)nfds, timeout); + return 0; +} +#else +int +mock_select ( + int nfds, + fd_set* readfds, + fd_set* writefds, + fd_set* exceptfds, + struct timeval* timeout + ) +{ + g_debug ("mock_select (nfds:%d readfds:%p writefds:%p exceptfds:%p timeout:%p)", + nfds, (gpointer)readfds, (gpointer)writefds, (gpointer)exceptfds, (gpointer)timeout); + return 0; +} +#endif + +int +mock_fcntl ( + int fd, + int cmd, + ... + ) +{ + long arg; + va_list args; + if (F_GETFL == cmd) { + g_debug ("mock_fcntl (fd:%d cmd:F_GETFL)", fd); + return 0; + } + if (F_SETFL == cmd) { + va_start (args, cmd); + arg = va_arg (args, long); + va_end (args); + g_debug ("mock_fcntl (fd:%d cmd:F_SETFL arg:%ld)", fd, arg); + return arg; + } + g_assert_not_reached(); +} + + +/* target: + * ssize_t + * pgm_sendto ( + * pgm_sock_t* sock, + * bool use_rate_limit, + * bool use_router_alert, + * const void* buf, + * size_t len, + * const struct sockaddr* to, + * socklen_t tolen + * ) + */ + +START_TEST (test_sendto_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + const char* buf = "i am not a string"; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr ("172.12.90.1") + }; + gssize len = pgm_sendto (sock, FALSE, FALSE, buf, sizeof(buf), (struct sockaddr*)&addr, sizeof(addr)); + fail_unless (sizeof(buf) == len, "sendto underrun"); +} +END_TEST + +START_TEST (test_sendto_fail_001) +{ + const char* buf = "i am not a string"; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr ("172.12.90.1") + }; + gssize len = pgm_sendto (NULL, FALSE, FALSE, buf, sizeof(buf), (struct sockaddr*)&addr, sizeof(addr)); + fail ("reached"); +} +END_TEST + +START_TEST (test_sendto_fail_002) +{ + pgm_sock_t* sock = generate_sock (); + const char* buf = "i am not a string"; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr ("172.12.90.1") + }; + gssize len = pgm_sendto (sock, FALSE, FALSE, NULL, sizeof(buf), (struct sockaddr*)&addr, sizeof(addr)); + fail ("reached"); +} +END_TEST + +START_TEST (test_sendto_fail_003) +{ + pgm_sock_t* sock = generate_sock (); + const char* buf = "i am not a string"; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr ("172.12.90.1") + }; + gssize len = pgm_sendto (sock, FALSE, FALSE, buf, 0, (struct sockaddr*)&addr, sizeof(addr)); + fail ("reached"); +} +END_TEST + +START_TEST (test_sendto_fail_004) +{ + pgm_sock_t* sock = generate_sock (); + const char* buf = "i am not a string"; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr ("172.12.90.1") + }; + gssize len = pgm_sendto (sock, FALSE, FALSE, buf, sizeof(buf), NULL, sizeof(addr)); + fail ("reached"); +} +END_TEST + +START_TEST (test_sendto_fail_005) +{ + pgm_sock_t* sock = generate_sock (); + const char* buf = "i am not a string"; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr ("172.12.90.1") + }; + gssize len = pgm_sendto (sock, FALSE, FALSE, buf, sizeof(buf), (struct sockaddr*)&addr, 0); + fail ("reached"); +} +END_TEST + +/* target: + * int + * pgm_set_nonblocking ( + * int filedes[2] + * ) + */ + +START_TEST (test_set_nonblocking_pass_001) +{ + int filedes[2] = { fileno (stdout), fileno (stderr) }; + int retval = pgm_set_nonblocking (filedes); +} +END_TEST + +START_TEST (test_set_nonblocking_fail_001) +{ + int filedes[2] = { 0, 0 }; + int retval = pgm_set_nonblocking (filedes); + fail ("reached"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_sendto = tcase_create ("sendto"); + suite_add_tcase (s, tc_sendto); + tcase_add_test (tc_sendto, test_sendto_pass_001); + tcase_add_test_raise_signal (tc_sendto, test_sendto_fail_001, SIGABRT); + tcase_add_test_raise_signal (tc_sendto, test_sendto_fail_002, SIGABRT); + tcase_add_test_raise_signal (tc_sendto, test_sendto_fail_003, SIGABRT); + tcase_add_test_raise_signal (tc_sendto, test_sendto_fail_004, SIGABRT); + tcase_add_test_raise_signal (tc_sendto, test_sendto_fail_005, SIGABRT); + + TCase* tc_set_nonblocking = tcase_create ("set-nonblocking"); + suite_add_tcase (s, tc_set_nonblocking); + tcase_add_test (tc_set_nonblocking, test_set_nonblocking_pass_001); + tcase_add_test_raise_signal (tc_set_nonblocking, test_set_nonblocking_fail_001, SIGABRT); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/options.txt b/3rdparty/openpgm-svn-r1135/pgm/options.txt new file mode 100644 index 0000000..cb01da0 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/options.txt @@ -0,0 +1,158 @@ + OPT_LENGTH 0x00 - Option's Length + +pgm_opt_header +pgm_opt_length + +first option, always present. + +-------------------------------------------------------------------------------- + + OPT_FRAGMENT 0x01 - Fragmentation + +pgm_opt_header +pgm_opt_fragment + +may be present for odata, rdata. 'MAY' exist for others, although a bit strange. + +-------------------------------------------------------------------------------- + + OPT_NAK_LIST 0x02 - List of NAK entries + +pgm_opt_header +pgm_opt_nak_list + +may be present for naks. + +-------------------------------------------------------------------------------- + + OPT_JOIN 0x03 - Late Joining + +pgm_opt_header +pgm_opt_join + +may be present for odata, rdata, spm. + +requires SPM to learn NLA already so not overly useful with odata/rdata, could be +used with video streaming to last i-frame data sequence number. + +-------------------------------------------------------------------------------- + + OPT_REDIRECT 0x07 - Redirect + +pgm_opt_header +pgm_opt_redirect +pgm_opt_redirect6 + +should be present for polrs from a dlr. + +-------------------------------------------------------------------------------- + + OPT_SYN 0x0D - Synchronization + +pgm_opt_header +pgm_opt_syn + +must only appear with odata or rdata. + +-------------------------------------------------------------------------------- + + OPT_FIN 0x0E - Session Fin receivers, conventional + feedbackish + +pgm_opt_header +opt_opt_fin + +may be present for odata, rdata, must appear in following spms. + +-------------------------------------------------------------------------------- + + OPT_RST 0x0F - Session Reset + +pgm_opt_header +pgm_opt_rst + +must only appear in spms. not many 'unrecoverable error conditions' exist though. + +-------------------------------------------------------------------------------- + + OPT_PARITY + +must appear in odata or rdata to indicate pro-active or on-demand parity data, +nak to request parity repair data, ncf to confirm parity nak. + + + OPT_VAR_PKTLEN + +may be present in odata or data to indicate variable size packets. + + + OPT_PARITY_PRM 0x08 - Forward Error Correction Parameters + +pgm_opt_header +pgm_opt_parity_prm + +appended to spms to inform of pro-active or on-demand parity. + +-------------------------------------------------------------------------------- + + OPT_PARITY_GRP 0x09 - Forward Error Correction Group Number + +pgm_opt_parity_grp + +appended to odata and rdata parity packets. + +-------------------------------------------------------------------------------- + + OPT_CURR_TGSIZE 0x0A - Forward Error Correction Group Size + +pgm_opt_curr_tgsize + +must appear in last odata or rdata packet of variable transmission group, may +appear in spms. + +-------------------------------------------------------------------------------- + + OPT_CR 0x10 - Congestion Report + +pgm_opt_header +pgm_opt_cr + +-------------------------------------------------------------------------------- + + OPT_CRQST 0x11 - Congestion Report Request + +pgm_opt_header +pgm_opt_crqst + +-------------------------------------------------------------------------------- + + OPT_NAK_BO_IVL 0x04 - NAK Back-Off Interval + +pgm_opt_header +pgm_opt_nak_bo_ivl + +-------------------------------------------------------------------------------- + + OPT_NAK_BO_RNG 0x05 - NAK Back-Off Range + +pgm_opt_header +pgm_opt_nak_bo_rng + +-------------------------------------------------------------------------------- + + OPT_NBR_UNREACH 0x0B - Neighbor Unreachable + +pgm_opt_header +pgm_opt_nbr_unreach + +-------------------------------------------------------------------------------- + + OPT_PATH_NLA 0x0C - Path NLA + +pgm_opt_header +pgm_opt_path_nla +pgm_opt6_path_nla + +-------------------------------------------------------------------------------- + + OPT_INVALID 0x7F - Option invalidated diff --git a/3rdparty/openpgm-svn-r1135/pgm/packet_parse.c b/3rdparty/openpgm-svn-r1135/pgm/packet_parse.c new file mode 100644 index 0000000..65c36a9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/packet_parse.c @@ -0,0 +1,619 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM packet formats, RFC 3208. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __STDC_FORMAT_MACROS +#ifdef _MSC_VER +# include +#else +# include +#endif +#include +#include +#include + + +//#define PACKET_DEBUG + +#ifndef PACKET_DEBUG +# define PGM_DISABLE_ASSERT +#endif + + +/* locals */ + +static bool pgm_parse (struct pgm_sk_buff_t*const restrict, pgm_error_t**restrict); + + +/* Parse a raw-IP packet for IP and PGM header and any payload. + */ + +#define PGM_MIN_SIZE ( \ + sizeof(struct pgm_ip) + /* IPv4 header */ \ + sizeof(struct pgm_header) /* PGM header */ \ + ) + +bool +pgm_parse_raw ( + struct pgm_sk_buff_t* const restrict skb, /* data will be modified */ + struct sockaddr* const restrict dst, + pgm_error_t** restrict error + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + pgm_assert (NULL != dst); + + pgm_debug ("pgm_parse_raw (skb:%p dst:%p error:%p)", + (const void*)skb, (const void*)dst, (const void*)error); + +/* minimum size should be IPv4 header plus PGM header, check IP version later */ + if (PGM_UNLIKELY(skb->len < PGM_MIN_SIZE)) + { + pgm_set_error (error, + PGM_ERROR_DOMAIN_PACKET, + PGM_ERROR_BOUNDS, + _("IP packet too small at %" PRIu16 " bytes, expecting at least %" PRIu16 " bytes."), + skb->len, (uint16_t)PGM_MIN_SIZE); + return FALSE; + } + +/* IP packet header: IPv4 + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Version| HL | ToS | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Fragment ID |R|D|M| Fragment Offset | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | TTL | Protocol | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source IP Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Destination IP Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | IP Options when present ... + * +-+-+-+-+-+-+-+-+-+-+-+-+ ... + * | Data ... + * +-+-+- ... + * + * IPv6 + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Version| Traffic Class | Flow Label | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Payload Length | Next Header | Hop Limit | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | Source IP Address | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | Destination IP Address | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | IP Options when present ... + * +-+-+-+-+-+-+-+-+-+-+-+-+ ... + * | Data ... + * +-+-+- ... + * + */ + +/* decode IP header */ + const struct pgm_ip* ip = (struct pgm_ip*)skb->data; + switch (ip->ip_v) { + case 4: { + struct sockaddr_in* sin = (struct sockaddr_in*)dst; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = ip->ip_dst.s_addr; + break; + } + + case 6: + pgm_set_error (error, + PGM_ERROR_DOMAIN_PACKET, + PGM_ERROR_AFNOSUPPORT, + _("IPv6 is not supported for raw IP header parsing.")); + return FALSE; + + default: + pgm_set_error (error, + PGM_ERROR_DOMAIN_PACKET, + PGM_ERROR_AFNOSUPPORT, + _("IP header reports an invalid version %d."), + ip->ip_v); + return FALSE; + } + + const size_t ip_header_length = ip->ip_hl * 4; /* IP header length in 32bit octets */ + if (PGM_UNLIKELY(ip_header_length < sizeof(struct pgm_ip))) + { + pgm_set_error (error, + PGM_ERROR_DOMAIN_PACKET, + PGM_ERROR_BOUNDS, + _("IP header reports an invalid header length %zu bytes."), + ip_header_length); + return FALSE; + } + +#ifndef CONFIG_HOST_ORDER_IP_LEN + size_t packet_length = ntohs (ip->ip_len); /* total packet length */ +#else + size_t packet_length = ip->ip_len; /* total packet length */ +#endif + + +/* ip_len can equal packet_length - ip_header_length in FreeBSD/NetBSD + * Stevens/Fenner/Rudolph, Unix Network Programming Vol.1, p.739 + * + * RFC3828 allows partial packets such that len < packet_length with UDP lite + */ + if (skb->len == packet_length + ip_header_length) { + packet_length += ip_header_length; + } + + if (PGM_UNLIKELY(skb->len < packet_length)) { /* redundant: often handled in kernel */ + pgm_set_error (error, + PGM_ERROR_DOMAIN_PACKET, + PGM_ERROR_BOUNDS, + _("IP packet received at %" PRIu16 " bytes whilst IP header reports %zu bytes."), + skb->len, packet_length); + return FALSE; + } + +/* packets that fail checksum will generally not be passed upstream except with rfc3828 + */ +#ifdef PGM_CHECK_IN_CKSUM + const uint16_t sum = in_cksum (data, packet_length, 0); + if (PGM_UNLIKELY(0 != sum)) { + const uint16_t ip_sum = ntohs (ip->ip_sum); + pgm_set_error (error, + PGM_ERROR_DOMAIN_PACKET, + PGM_ERROR_CKSUM, + _("IP packet checksum mismatch, reported 0x%x whilst calculated 0x%x."), + ip_sum, sum); + return FALSE; + } +#endif + +/* fragmentation offset, bit 0: 0, bit 1: do-not-fragment, bit 2: more-fragments */ +#ifndef CONFIG_HOST_ORDER_IP_OFF + const uint16_t offset = ntohs (ip->ip_off); +#else + const uint16_t offset = ip->ip_off; +#endif + if (PGM_UNLIKELY((offset & 0x1fff) != 0)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_PACKET, + PGM_ERROR_PROTO, + _("IP header reports packet fragmentation, offset %u."), + offset & 0x1fff); + return FALSE; + } + +/* PGM payload, header looks as follows: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source Port | Destination Port | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Options | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Global Source ID ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ... Global Source ID | TSDU Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type specific data ... + * +-+-+-+-+-+-+-+-+-+- ... + */ + + skb->pgm_header = (void*)( (char*)skb->data + ip_header_length ); + +/* advance DATA pointer to PGM packet */ + skb->data = skb->pgm_header; + skb->len -= ip_header_length; + return pgm_parse (skb, error); +} + +bool +pgm_parse_udp_encap ( + struct pgm_sk_buff_t*const restrict skb, /* will be modified */ + pgm_error_t** restrict error + ) +{ + pgm_assert (NULL != skb); + + if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_header))) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_PACKET, + PGM_ERROR_BOUNDS, + _("UDP payload too small for PGM packet at %" PRIu16 " bytes, expecting at least %zu bytes."), + skb->len, sizeof(struct pgm_header)); + return FALSE; + } + +/* DATA payload is PGM packet, no headers */ + skb->pgm_header = skb->data; + return pgm_parse (skb, error); +} + +/* will modify packet contents to calculate and check PGM checksum + */ +static +bool +pgm_parse ( + struct pgm_sk_buff_t*const restrict skb, /* will be modified to calculate checksum */ + pgm_error_t** restrict error + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + +/* pgm_checksum == 0 means no transmitted checksum */ + if (skb->pgm_header->pgm_checksum) + { + const uint16_t sum = skb->pgm_header->pgm_checksum; + skb->pgm_header->pgm_checksum = 0; + const uint16_t pgm_sum = pgm_csum_fold (pgm_csum_partial ((const char*)skb->pgm_header, skb->len, 0)); + skb->pgm_header->pgm_checksum = sum; + if (PGM_UNLIKELY(pgm_sum != sum)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_PACKET, + PGM_ERROR_CKSUM, + _("PGM packet checksum mismatch, reported 0x%x whilst calculated 0x%x."), + pgm_sum, sum); + return FALSE; + } + } else { + if (PGM_ODATA == skb->pgm_header->pgm_type || + PGM_RDATA == skb->pgm_header->pgm_type) + { + pgm_set_error (error, + PGM_ERROR_DOMAIN_PACKET, + PGM_ERROR_PROTO, + _("PGM checksum missing whilst mandatory for %cDATA packets."), + PGM_ODATA == skb->pgm_header->pgm_type ? 'O' : 'R'); + return FALSE; + } + pgm_debug ("No PGM checksum :O"); + } + +/* copy packets source transport identifier */ + memcpy (&skb->tsi.gsi, skb->pgm_header->pgm_gsi, sizeof(pgm_gsi_t)); + skb->tsi.sport = skb->pgm_header->pgm_sport; + return TRUE; +} + +/* 8.1. Source Path Messages (SPM) + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | SPM's Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Trailing Edge Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Leading Edge Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Path NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * NLA = Network Layer Address + * NLA AFI = NLA Address Family Indicator: rfc 1700 (ADDRESS FAMILY NUMBERS) + * => Path NLA = IP address of last network element + */ + +#define PGM_MIN_SPM_SIZE ( sizeof(struct pgm_spm) ) + +bool +pgm_verify_spm ( + const struct pgm_sk_buff_t*const skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + + const struct pgm_spm* spm = (const struct pgm_spm*)skb->data; + switch (ntohs (spm->spm_nla_afi)) { +/* truncated packet */ + case AFI_IP6: + if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_spm6))) + return FALSE; + break; + case AFI_IP: + if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_spm))) + return FALSE; + break; + + default: + return FALSE; + } + + return TRUE; +} + +/* 14.7.1. Poll Request + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLL's Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLL's Round | POLL's Sub-type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Path NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | POLL's Back-off Interval | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Random String | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Matching Bit-Mask | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Sent to ODATA multicast group with IP Router Alert option. + */ + +#define PGM_MIN_POLL_SIZE ( sizeof(struct pgm_poll) ) + +bool +pgm_verify_poll ( + const struct pgm_sk_buff_t*const skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + + const struct pgm_poll* poll4 = (const struct pgm_poll*)skb->data; + switch (ntohs (poll4->poll_nla_afi)) { +/* truncated packet */ + case AFI_IP6: + if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_poll6))) + return FALSE; + break; + case AFI_IP: + if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_poll))) + return FALSE; + break; + + default: + return FALSE; + } + + return TRUE; +} + +/* 14.7.2. Poll Response + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLR's Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLR's Round | reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +bool +pgm_verify_polr ( + const struct pgm_sk_buff_t*const skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + +/* truncated packet */ + if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_polr))) + return FALSE; + return TRUE; +} + +/* 8.2. Data Packet + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Data Packet Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Trailing Edge Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Data ... + * +-+-+- ... + */ + +/* no verification api */ + +/* 8.3. NAK + * + * Technically the AFI of the source and multicast group can be different + * but that would be very wibbly wobbly. One example is using a local DLR + * with a IPv4 address to reduce NAK cost for recovery on wide IPv6 + * distribution. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Requested Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Multicast Group NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | Option Extensions when present ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... + */ + +#define PGM_MIN_NAK_SIZE ( sizeof(struct pgm_nak) ) + +bool +pgm_verify_nak ( + const struct pgm_sk_buff_t*const skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + + pgm_debug ("pgm_verify_nak (skb:%p)", (const void*)skb); + +/* truncated packet */ + if (PGM_UNLIKELY(skb->len < PGM_MIN_NAK_SIZE)) + return FALSE; + + const struct pgm_nak* nak = (struct pgm_nak*)skb->data; + const uint16_t nak_src_nla_afi = ntohs (nak->nak_src_nla_afi); + uint16_t nak_grp_nla_afi = 0; + +/* check source NLA: unicast address of the ODATA sender */ + switch (nak_src_nla_afi) { + case AFI_IP: + nak_grp_nla_afi = ntohs (nak->nak_grp_nla_afi); + break; + + case AFI_IP6: + nak_grp_nla_afi = ntohs (((const struct pgm_nak6*)nak)->nak6_grp_nla_afi); + break; + + default: + return FALSE; + } + +/* check multicast group NLA */ + switch (nak_grp_nla_afi) { + case AFI_IP6: + switch (nak_src_nla_afi) { +/* IPv4 + IPv6 NLA */ + case AFI_IP: + if (PGM_UNLIKELY(skb->len < ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) ))) + return FALSE; + break; + +/* IPv6 + IPv6 NLA */ + case AFI_IP6: + if (PGM_UNLIKELY(skb->len < sizeof(struct pgm_nak6))) + return FALSE; + break; + } + + case AFI_IP: + break; + + default: + return FALSE; + } + + return TRUE; +} + +/* 8.3. N-NAK + */ + +bool +pgm_verify_nnak ( + const struct pgm_sk_buff_t*const skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + + return pgm_verify_nak (skb); +} + +/* 8.3. NCF + */ + +bool +pgm_verify_ncf ( + const struct pgm_sk_buff_t*const skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + + return pgm_verify_nak (skb); +} + +/* 13.6. SPM Request + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... + */ + +bool +pgm_verify_spmr ( + PGM_GNUC_UNUSED const struct pgm_sk_buff_t*const skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + + return TRUE; +} + +/* PGMCC: ACK + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | RX_MAX | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Received Packet Bitmap | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... + */ + +#define PGM_MIN_ACK_SIZE ( sizeof(struct pgm_ack) ) + +bool +pgm_verify_ack ( + PGM_GNUC_UNUSED const struct pgm_sk_buff_t*const skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + + return TRUE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/packet_parse.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/packet_parse.c.c89.patch new file mode 100644 index 0000000..fad2ec9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/packet_parse.c.c89.patch @@ -0,0 +1,121 @@ +--- packet_parse.c 2010-08-04 15:32:09.000000000 +0800 ++++ packet_parse.c89 2010-08-04 15:32:40.000000000 +0800 +@@ -122,6 +122,7 @@ + */ + + /* decode IP header */ ++ { + const struct pgm_ip* ip = (struct pgm_ip*)skb->data; + switch (ip->ip_v) { + case 4: { +@@ -147,6 +148,7 @@ + return FALSE; + } + ++ { + const size_t ip_header_length = ip->ip_hl * 4; /* IP header length in 32bit octets */ + if (PGM_UNLIKELY(ip_header_length < sizeof(struct pgm_ip))) + { +@@ -158,6 +160,7 @@ + return FALSE; + } + ++ { + #ifndef CONFIG_HOST_ORDER_IP_LEN + size_t packet_length = ntohs (ip->ip_len); /* total packet length */ + #else +@@ -186,6 +189,7 @@ + /* packets that fail checksum will generally not be passed upstream except with rfc3828 + */ + #if PGM_CHECK_IN_CKSUM ++ { + const uint16_t sum = in_cksum (data, packet_length, 0); + if (PGM_UNLIKELY(0 != sum)) { + const uint16_t ip_sum = ntohs (ip->ip_sum); +@@ -196,9 +200,11 @@ + ip_sum, sum); + return FALSE; + } ++ } + #endif + + /* fragmentation offset, bit 0: 0, bit 1: do-not-fragment, bit 2: more-fragments */ ++ { + #ifndef CONFIG_HOST_ORDER_IP_OFF + const uint16_t offset = ntohs (ip->ip_off); + #else +@@ -236,6 +242,10 @@ + skb->data = skb->pgm_header; + skb->len -= ip_header_length; + return pgm_parse (skb, error); ++ } ++ } ++ } ++ } + } + + bool +@@ -277,6 +287,7 @@ + { + const uint16_t sum = skb->pgm_header->pgm_checksum; + skb->pgm_header->pgm_checksum = 0; ++ { + const uint16_t pgm_sum = pgm_csum_fold (pgm_csum_partial ((const char*)skb->pgm_header, skb->len, 0)); + skb->pgm_header->pgm_checksum = sum; + if (PGM_UNLIKELY(pgm_sum != sum)) { +@@ -287,6 +298,7 @@ + pgm_sum, sum); + return FALSE; + } ++ } + } else { + if (PGM_ODATA == skb->pgm_header->pgm_type || + PGM_RDATA == skb->pgm_header->pgm_type) +@@ -340,6 +352,7 @@ + /* pre-conditions */ + pgm_assert (NULL != skb); + ++ { + const struct pgm_spm* spm = (const struct pgm_spm*)skb->data; + switch (ntohs (spm->spm_nla_afi)) { + /* truncated packet */ +@@ -357,6 +370,7 @@ + } + + return TRUE; ++ } + } + + /* 14.7.1. Poll Request +@@ -394,6 +408,7 @@ + /* pre-conditions */ + pgm_assert (NULL != skb); + ++ { + const struct pgm_poll* poll4 = (const struct pgm_poll*)skb->data; + switch (ntohs (poll4->poll_nla_afi)) { + /* truncated packet */ +@@ -411,6 +426,7 @@ + } + + return TRUE; ++ } + } + + /* 14.7.2. Poll Response +@@ -497,6 +513,7 @@ + if (PGM_UNLIKELY(skb->len < PGM_MIN_NAK_SIZE)) + return FALSE; + ++ { + const struct pgm_nak* nak = (struct pgm_nak*)skb->data; + const uint16_t nak_src_nla_afi = ntohs (nak->nak_src_nla_afi); + uint16_t nak_grp_nla_afi = 0; +@@ -540,6 +557,7 @@ + } + + return TRUE; ++ } + } + + /* 8.3. N-NAK diff --git a/3rdparty/openpgm-svn-r1135/pgm/packet_parse_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/packet_parse_unittest.c new file mode 100644 index 0000000..94b06d2 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/packet_parse_unittest.c @@ -0,0 +1,382 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for PGM packet handling. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* mock state */ + +#define PACKET_DEBUG +#include "packet_parse.c" + + +static +struct pgm_sk_buff_t* +generate_raw_pgm (void) +{ + const char source[] = "i am not a string"; + const guint source_len = sizeof(source); + struct pgm_sk_buff_t* skb; + GError* err = NULL; + + skb = pgm_alloc_skb (1500); + skb->sock = (pgm_sock_t*)0x1; + skb->tstamp = 0x1; + skb->data = skb->head; + skb->len = sizeof(struct pgm_ip) + sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len; + skb->tail = (guint8*)skb->data + skb->len; + +/* add IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_hl = sizeof(struct pgm_ip) / 4; + iphdr->ip_v = 4; + iphdr->ip_tos = 0; + iphdr->ip_len = g_htons (skb->len); + iphdr->ip_id = 0; + iphdr->ip_off = 0; + iphdr->ip_ttl = 16; + iphdr->ip_p = IPPROTO_PGM; + iphdr->ip_sum = 0; + iphdr->ip_src.s_addr = inet_addr ("127.0.0.1"); + iphdr->ip_dst.s_addr = inet_addr ("127.0.0.2"); + +/* add PGM header */ + struct pgm_header* pgmhdr = (gpointer)(iphdr + 1); + pgmhdr->pgm_sport = g_htons ((guint16)1000); + pgmhdr->pgm_dport = g_htons ((guint16)7500); + pgmhdr->pgm_type = PGM_ODATA; + pgmhdr->pgm_options = 0; + pgmhdr->pgm_gsi[0] = 1; + pgmhdr->pgm_gsi[1] = 2; + pgmhdr->pgm_gsi[2] = 3; + pgmhdr->pgm_gsi[3] = 4; + pgmhdr->pgm_gsi[4] = 5; + pgmhdr->pgm_gsi[5] = 6; + pgmhdr->pgm_tsdu_length = g_htons (source_len); + +/* add ODATA header */ + struct pgm_data* datahdr = (gpointer)(pgmhdr + 1); + datahdr->data_sqn = g_htonl ((guint32)0); + datahdr->data_trail = g_htonl ((guint32)-1); + +/* add payload */ + gpointer data = (gpointer)(datahdr + 1); + memcpy (data, source, source_len); + +/* finally PGM checksum */ + pgmhdr->pgm_checksum = 0; + pgmhdr->pgm_checksum = pgm_csum_fold (pgm_csum_partial (pgmhdr, sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len, 0)); + +/* and IP checksum */ + iphdr->ip_sum = pgm_inet_checksum (skb->head, skb->len, 0); + + return skb; +} + +static +struct pgm_sk_buff_t* +generate_udp_encap_pgm (void) +{ + const char source[] = "i am not a string"; + const guint source_len = sizeof(source); + struct pgm_sk_buff_t* skb; + GError* err = NULL; + + skb = pgm_alloc_skb (1500); + skb->sock = (pgm_sock_t*)0x1; + skb->tstamp = 0x1; + skb->data = skb->head; + skb->len = sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len; + skb->tail = (guint8*)skb->data + skb->len; + +/* add PGM header */ + struct pgm_header* pgmhdr = skb->head; + pgmhdr->pgm_sport = g_htons ((guint16)1000); + pgmhdr->pgm_dport = g_htons ((guint16)7500); + pgmhdr->pgm_type = PGM_ODATA; + pgmhdr->pgm_options = 0; + pgmhdr->pgm_gsi[0] = 1; + pgmhdr->pgm_gsi[1] = 2; + pgmhdr->pgm_gsi[2] = 3; + pgmhdr->pgm_gsi[3] = 4; + pgmhdr->pgm_gsi[4] = 5; + pgmhdr->pgm_gsi[5] = 6; + pgmhdr->pgm_tsdu_length = g_htons (source_len); + +/* add ODATA header */ + struct pgm_data* datahdr = (gpointer)(pgmhdr + 1); + datahdr->data_sqn = g_htonl ((guint32)0); + datahdr->data_trail = g_htonl ((guint32)-1); + +/* add payload */ + gpointer data = (gpointer)(datahdr + 1); + memcpy (data, source, source_len); + +/* finally PGM checksum */ + pgmhdr->pgm_checksum = 0; + pgmhdr->pgm_checksum = pgm_csum_fold (pgm_csum_partial (pgmhdr, sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len, 0)); + + return skb; +} + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + + +/* target: + * bool + * pgm_parse_raw ( + * struct pgm_sk_buff_t* const skb, + * struct sockaddr* const addr, + * pgm_error_t** error + * ) + */ + +START_TEST (test_parse_raw_pass_001) +{ + struct sockaddr_storage addr; + pgm_error_t* err = NULL; + struct pgm_sk_buff_t* skb = generate_raw_pgm (); + gboolean success = pgm_parse_raw (skb, (struct sockaddr*)&addr, &err); + if (!success && err) { + g_error ("Parsing raw packet: %s", err->message); + } + fail_unless (TRUE == success, "parse_raw failed"); + char saddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); + g_message ("Decoded destination NLA: %s", saddr); +} +END_TEST + +START_TEST (test_parse_raw_fail_001) +{ + struct sockaddr_storage addr; + pgm_error_t* err = NULL; + pgm_parse_raw (NULL, (struct sockaddr*)&addr, &err); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_parse_udp_encap ( + * struct pgm_sk_buff_t* const skb, + * pgm_error_t** error + * ) + */ + +START_TEST (test_parse_udp_encap_pass_001) +{ + pgm_error_t* err = NULL; + struct pgm_sk_buff_t* skb = generate_udp_encap_pgm (); + gboolean success = pgm_parse_udp_encap (skb, &err); + if (!success && err) { + g_error ("Parsing UDP encapsulated packet: %s", err->message); + } + fail_unless (TRUE == success, "parse_udp_encap failed"); +} +END_TEST + +START_TEST (test_parse_udp_encap_fail_001) +{ + pgm_error_t* err = NULL; + pgm_parse_udp_encap (NULL, &err); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_verify_spm ( + * struct pgm_sk_buff_t* const skb + * ) + */ + +START_TEST (test_verify_spm_pass_001) +{ +} +END_TEST + +START_TEST (test_verify_spm_fail_001) +{ + pgm_verify_spm (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_verify_spmr ( + * struct pgm_sk_buff_t* const skb + * ) + */ + +START_TEST (test_verify_spmr_pass_001) +{ +} +END_TEST + +START_TEST (test_verify_spmr_fail_001) +{ + pgm_verify_spmr (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_verify_nak ( + * struct pgm_sk_buff_t* const skb + * ) + */ + +START_TEST (test_verify_nak_pass_001) +{ +} +END_TEST + +START_TEST (test_verify_nak_fail_001) +{ + pgm_verify_nak (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_verify_nnak ( + * struct pgm_sk_buff_t* const skb + * ) + */ + +START_TEST (test_verify_nnak_pass_001) +{ +} +END_TEST + +START_TEST (test_verify_nnak_fail_001) +{ + pgm_verify_nnak (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_verify_ncf ( + * struct pgm_sk_buff_t* const skb + * ) + */ + +START_TEST (test_verify_ncf_pass_001) +{ +} +END_TEST + +START_TEST (test_verify_ncf_fail_001) +{ + pgm_verify_ncf (NULL); + fail ("reached"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_parse_raw = tcase_create ("parse-raw"); + suite_add_tcase (s, tc_parse_raw); + tcase_add_test (tc_parse_raw, test_parse_raw_pass_001); + tcase_add_test_raise_signal (tc_parse_raw, test_parse_raw_fail_001, SIGABRT); + + TCase* tc_parse_udp_encap = tcase_create ("parse-udp-encap"); + suite_add_tcase (s, tc_parse_udp_encap); + tcase_add_test (tc_parse_udp_encap, test_parse_udp_encap_pass_001); + tcase_add_test_raise_signal (tc_parse_udp_encap, test_parse_udp_encap_fail_001, SIGABRT); + + TCase* tc_verify_spm = tcase_create ("verify-spm"); + suite_add_tcase (s, tc_verify_spm); + tcase_add_test (tc_verify_spm, test_verify_spm_pass_001); + tcase_add_test_raise_signal (tc_verify_spm, test_verify_spm_fail_001, SIGABRT); + + TCase* tc_verify_spmr = tcase_create ("verify-spmr"); + suite_add_tcase (s, tc_verify_spmr); + tcase_add_test (tc_verify_spmr, test_verify_spmr_pass_001); + tcase_add_test_raise_signal (tc_verify_spmr, test_verify_spmr_fail_001, SIGABRT); + + TCase* tc_verify_nak = tcase_create ("verify-nak"); + suite_add_tcase (s, tc_verify_nak); + tcase_add_test (tc_verify_nak, test_verify_nak_pass_001); + tcase_add_test_raise_signal (tc_verify_nak, test_verify_nak_fail_001, SIGABRT); + + TCase* tc_verify_nnak = tcase_create ("verify-nnak"); + suite_add_tcase (s, tc_verify_nnak); + tcase_add_test (tc_verify_nnak, test_verify_nnak_pass_001); + tcase_add_test_raise_signal (tc_verify_nnak, test_verify_nnak_fail_001, SIGABRT); + + TCase* tc_verify_ncf = tcase_create ("verify-ncf"); + suite_add_tcase (s, tc_verify_ncf); + tcase_add_test (tc_verify_ncf, test_verify_ncf_pass_001); + tcase_add_test_raise_signal (tc_verify_ncf, test_verify_ncf_fail_001, SIGABRT); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/packet_test.c b/3rdparty/openpgm-svn-r1135/pgm/packet_test.c new file mode 100644 index 0000000..267700a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/packet_test.c @@ -0,0 +1,1162 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM packet formats, RFC 3208. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __STDC_FORMAT_MACROS +#ifdef _MSC_VER +# include +#else +# include +#endif +#include +#include +#ifndef _WIN32 +# include +# include +# include +# include +#endif +#include +#include +#include + + +//#define PACKET_DEBUG + + +static bool pgm_print_spm (const struct pgm_header* const, const void*, const size_t); +static bool pgm_print_poll (const struct pgm_header* const, const void*, const size_t); +static bool pgm_print_polr (const struct pgm_header* const, const void*, const size_t); +static bool pgm_print_odata (const struct pgm_header* const, const void*, const size_t); +static bool pgm_print_rdata (const struct pgm_header* const, const void*, const size_t); +static bool pgm_print_nak (const struct pgm_header* const, const void*, const size_t); +static bool pgm_print_nnak (const struct pgm_header* const, const void*, const size_t); +static bool pgm_print_ncf (const struct pgm_header* const, const void*, const size_t); +static bool pgm_print_spmr (const struct pgm_header* const, const void*, const size_t); +static bool pgm_print_ack (const struct pgm_header* const, const void*, const size_t); +static ssize_t pgm_print_options (const void*, size_t); + +bool +pgm_print_packet ( + const void* data, + size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != data); + pgm_assert (len > 0); + +/* minimum size should be IP header plus PGM header */ + if (len < (sizeof(struct pgm_ip) + sizeof(struct pgm_header))) + { + printf ("Packet size too small: %zu bytes, expecting at least %zu bytes.\n", + len, sizeof(struct pgm_ip) + sizeof(struct pgm_header)); + return FALSE; + } + +/* decode IP header */ + const struct pgm_ip* ip = (const struct pgm_ip*)data; + if (ip->ip_v != 4) /* IP version, 4 or 6 */ + { + puts ("not IP4 packet :/"); /* v6 not currently handled */ + return FALSE; + } + printf ("IP "); + + const size_t ip_header_length = ip->ip_hl * 4; /* IP header length in 32bit octets */ + if (ip_header_length < sizeof(struct pgm_ip)) + { + puts ("bad IP header length :("); + return FALSE; + } + + size_t packet_length = ntohs(ip->ip_len); /* total packet length */ + +/* ip_len can equal packet_length - ip_header_length in FreeBSD/NetBSD + * Stevens/Fenner/Rudolph, Unix Network Programming Vol.1, p.739 + * + * RFC3828 allows partial packets such that len < packet_length with UDP lite + */ + if (len == packet_length + ip_header_length) { + packet_length += ip_header_length; + } + + if (len < packet_length) { /* redundant: often handled in kernel */ + puts ("truncated IP packet"); + return FALSE; + } + +/* TCP Segmentation Offload (TSO) might have zero length here */ + if (packet_length < ip_header_length) { + puts ("bad length :("); + return FALSE; + } + + const uint16_t offset = ntohs(ip->ip_off); + +/* 3 bits routing priority, 4 bits type of service: delay, throughput, reliability, cost */ + printf ("(tos 0x%x", (int)ip->ip_tos); + switch (ip->ip_tos & 0x3) + { + case 1: printf (",ECT(1)"); break; + case 2: printf (",ECT(0)"); break; + case 3: printf (",CE"); break; + default: break; + } + +/* time to live */ + if (ip->ip_ttl >= 1) printf (", ttl %u", ip->ip_ttl); + +/* fragmentation */ +#define IP_RDF 0x8000 +#define IP_DF 0x4000 +#define IP_MF 0x2000 +#define IP_OFFMASK 0x1fff + + printf (", id %u, offset %u, flags [%s%s]", + ntohs(ip->ip_id), + (offset & 0x1fff) * 8, + ((offset & IP_DF) ? "DF" : ""), + ((offset & IP_MF) ? "+" : "")); + printf (", length %zu", packet_length); + +/* IP options */ + if ((ip_header_length - sizeof(struct pgm_ip)) > 0) { + printf (", options ("); + pgm_ipopt_print((const void*)(ip + 1), ip_header_length - sizeof(struct pgm_ip)); + printf (" )"); + } + +/* packets that fail checksum will generally not be passed upstream except with rfc3828 + */ + const uint16_t ip_sum = pgm_inet_checksum(data, packet_length, 0); + if (ip_sum != 0) { + const uint16_t encoded_ip_sum = ntohs(ip->ip_sum); + printf (", bad cksum! %i", encoded_ip_sum); + } + + printf (") "); + +/* fragmentation offset, bit 0: 0, bit 1: do-not-fragment, bit 2: more-fragments */ + if ((offset & 0x1fff) != 0) { + puts ("fragmented packet :/"); + return FALSE; + } + +/* PGM payload, header looks as follows: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source Port | Destination Port | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Options | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Global Source ID ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ... Global Source ID | TSDU Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type specific data ... + * +-+-+-+-+-+-+-+-+-+- ... + */ + const struct pgm_header* pgm_header = (const struct pgm_header*)((const char*)data + ip_header_length); + const size_t pgm_length = packet_length - ip_header_length; + + if (pgm_length < sizeof(pgm_header)) { + puts ("bad packet size :("); + return FALSE; + } + + printf ("%s.%s > ", + pgm_gethostbyaddr((const struct in_addr*)&ip->ip_src), pgm_udpport_string(pgm_header->pgm_sport)); + printf ("%s.%s: PGM\n", + pgm_gethostbyaddr((const struct in_addr*)&ip->ip_dst), pgm_udpport_string(pgm_header->pgm_dport)); + + printf ("type: %s [%i] (version=%i, reserved=%i)\n" + "options: extensions=%s, network-significant=%s, parity packet=%s (variable size=%s)\n" + "global source id: %i.%i.%i.%i.%i.%i\n" + "tsdu length: %i\n", + + /* packet type */ /* packet version */ /* reserved = 0x0 */ + pgm_type_string(pgm_header->pgm_type & 0xf), + (pgm_header->pgm_type & 0xf), ((pgm_header->pgm_type & 0xc0) >> 6), ((pgm_header->pgm_type & 0x30) >> 4), + +/* bit 0 set => one or more option extensions are present */ + ((pgm_header->pgm_options & (0x1 << 7)) ? "true" : "false"), +/* bit 1 set => one or more options are network-significant */ + ((pgm_header->pgm_options & (0x1 << 6)) ? "true" : "false"), +/* bit 7 set => parity packet (OPT_PARITY) */ + ((pgm_header->pgm_options & (0x1 << 0)) ? "true" : "false"), +/* bit 6 set => parity packet for variable packet sizes (OPT_VAR_PKTLEN) */ + ((pgm_header->pgm_options & (0x1 << 1)) ? "true" : "false"), + + pgm_header->pgm_gsi[0], pgm_header->pgm_gsi[1], pgm_header->pgm_gsi[2], pgm_header->pgm_gsi[3], pgm_header->pgm_gsi[4], pgm_header->pgm_gsi[5], + ntohs(pgm_header->pgm_tsdu_length)); + + if (pgm_header->pgm_checksum) + { +#if 0 + const uint16_t encoded_pgm_sum = pgm_header->pgm_checksum; +/* requires modification of data buffer */ + pgm_header->pgm_checksum = 0; + const uint16_t pgm_sum = pgm_csum_fold (pgm_csum_partial((const char*)pgm_header, pgm_length, 0)); + if (pgm_sum != encoded_pgm_sum) { + printf ("PGM checksum incorrect, packet %x calculated %x :(\n", encoded_pgm_sum, pgm_sum); + return FALSE; + } +#endif + } else { + puts ("No PGM checksum :O"); + } + +/* now decode PGM packet types */ + const void* pgm_data = pgm_header + 1; + const size_t pgm_data_length = pgm_length - sizeof(pgm_header); /* can equal zero for SPMR's */ + + bool err = FALSE; + switch (pgm_header->pgm_type) { + case PGM_SPM: err = pgm_print_spm (pgm_header, pgm_data, pgm_data_length); break; + case PGM_POLL: err = pgm_print_poll (pgm_header, pgm_data, pgm_data_length); break; + case PGM_POLR: err = pgm_print_polr (pgm_header, pgm_data, pgm_data_length); break; + case PGM_ODATA: err = pgm_print_odata (pgm_header, pgm_data, pgm_data_length); break; + case PGM_RDATA: err = pgm_print_rdata (pgm_header, pgm_data, pgm_data_length); break; + case PGM_NAK: err = pgm_print_nak (pgm_header, pgm_data, pgm_data_length); break; + case PGM_NNAK: err = pgm_print_nnak (pgm_header, pgm_data, pgm_data_length); break; + case PGM_NCF: err = pgm_print_ncf (pgm_header, pgm_data, pgm_data_length); break; + case PGM_SPMR: err = pgm_print_spmr (pgm_header, pgm_data, pgm_data_length); break; + case PGM_ACK: err = pgm_print_ack (pgm_header, pgm_data, pgm_data_length); break; + default: puts ("unknown packet type :("); break; + } + + return err; +} + +/* 8.1. Source Path Messages (SPM) + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | SPM's Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Trailing Edge Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Leading Edge Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Path NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * NLA = Network Layer Address + * NLA AFI = NLA Address Family Indicator: rfc 1700 (ADDRESS FAMILY NUMBERS) + * => Path NLA = IP address of last network element + */ + +#define PGM_MIN_SPM_SIZE ( sizeof(struct pgm_spm) ) + +static +bool +pgm_print_spm ( + const struct pgm_header* const header, + const void* data, + const size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != header); + pgm_assert (NULL != data); + pgm_assert (len > 0); + + printf ("SPM: "); + + if (len < PGM_MIN_SPM_SIZE) { + puts ("packet truncated :("); + return FALSE; + } + + const struct pgm_spm * spm = (const struct pgm_spm *)data; + const struct pgm_spm6* spm6 = (const struct pgm_spm6*)data; + const uint16_t spm_nla_afi = ntohs (spm->spm_nla_afi); + + printf ("sqn %" PRIu32 " trail %" PRIu32 "lu lead %" PRIu32 "lu nla-afi %u ", + ntohl(spm->spm_sqn), + ntohl(spm->spm_trail), + ntohl(spm->spm_lead), + spm_nla_afi); /* address family indicator */ + + char s[INET6_ADDRSTRLEN]; + const void* pgm_opt; + size_t pgm_opt_len; + switch (spm_nla_afi) { + case AFI_IP: + pgm_inet_ntop (AF_INET, &spm->spm_nla, s, sizeof(s)); + pgm_opt = (const uint8_t*)data + sizeof(struct pgm_spm); + pgm_opt_len = len - sizeof(struct pgm_spm); + break; + + case AFI_IP6: + if (len < sizeof (struct pgm_spm6)) { + puts ("packet truncated :("); + return FALSE; + } + + pgm_inet_ntop (AF_INET6, &spm6->spm6_nla, s, sizeof(s)); + pgm_opt = (const uint8_t*)data + sizeof(struct pgm_spm6); + pgm_opt_len = len - sizeof(struct pgm_spm6); + break; + + default: + printf ("unsupported afi"); + return FALSE; + } + + printf ("%s", s); + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT && + pgm_print_options (pgm_opt, pgm_opt_len) < 0 ) + { + return FALSE; + } + + printf ("\n"); + return TRUE; +} + +/* 14.7.1. Poll Request + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLL's Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLL's Round | POLL's Sub-type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Path NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | POLL's Back-off Interval | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Random String | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Matching Bit-Mask | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Sent to ODATA multicast group with IP Router Alert option. + */ + +#define PGM_MIN_POLL_SIZE ( sizeof(struct pgm_poll) ) + +static +bool +pgm_print_poll ( + const struct pgm_header* const header, + const void* data, + const size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != header); + pgm_assert (NULL != data); + pgm_assert (len > 0); + + printf ("POLL: "); + + if (len < PGM_MIN_POLL_SIZE) { + puts ("packet truncated :("); + return FALSE; + } + + const struct pgm_poll * poll4 = (const struct pgm_poll *)data; + const struct pgm_poll6* poll6 = (const struct pgm_poll6*)data; + const uint16_t poll_nla_afi = ntohs (poll4->poll_nla_afi); + + printf ("sqn %" PRIu32 " round %u sub-type %u nla-afi %u ", + ntohl(poll4->poll_sqn), + ntohs(poll4->poll_round), + ntohs(poll4->poll_s_type), + poll_nla_afi); /* address family indicator */ + + char s[INET6_ADDRSTRLEN]; + const void* pgm_opt; + size_t pgm_opt_len; + switch (poll_nla_afi) { + case AFI_IP: + pgm_inet_ntop (AF_INET, &poll4->poll_nla, s, sizeof(s)); + pgm_opt = (const uint8_t*)data + sizeof(struct pgm_poll); + pgm_opt_len = len - sizeof(struct pgm_poll); + printf ("%s", s); + +/* back-off interval in microseconds */ + printf (" bo_ivl %u", poll4->poll_bo_ivl); + +/* random string */ + printf (" rand [%c%c%c%c]", + isprint (poll4->poll_rand[0]) ? poll4->poll_rand[0] : '.', + isprint (poll4->poll_rand[1]) ? poll4->poll_rand[1] : '.', + isprint (poll4->poll_rand[2]) ? poll4->poll_rand[2] : '.', + isprint (poll4->poll_rand[3]) ? poll4->poll_rand[3] : '.' ); + +/* matching bit-mask */ + printf (" mask 0x%x", poll4->poll_mask); + break; + + case AFI_IP6: + if (len < sizeof (struct pgm_poll6)) { + puts ("packet truncated :("); + return FALSE; + } + + pgm_inet_ntop (AF_INET6, &poll6->poll6_nla, s, sizeof (s)); + pgm_opt = (const uint8_t*)data + sizeof(struct pgm_poll6); + pgm_opt_len = len - sizeof(struct pgm_poll6); + printf ("%s", s); + +/* back-off interval in microseconds */ + printf (" bo_ivl %u", poll6->poll6_bo_ivl); + +/* random string */ + printf (" rand [%c%c%c%c]", + isprint (poll6->poll6_rand[0]) ? poll6->poll6_rand[0] : '.', + isprint (poll6->poll6_rand[1]) ? poll6->poll6_rand[1] : '.', + isprint (poll6->poll6_rand[2]) ? poll6->poll6_rand[2] : '.', + isprint (poll6->poll6_rand[3]) ? poll6->poll6_rand[3] : '.' ); + +/* matching bit-mask */ + printf (" mask 0x%x", poll6->poll6_mask); + break; + + default: + printf ("unsupported afi"); + return FALSE; + } + + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT && + pgm_print_options (pgm_opt, pgm_opt_len) < 0 ) + { + return FALSE; + } + + printf ("\n"); + return TRUE; +} + +/* 14.7.2. Poll Response + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLR's Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLR's Round | reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +static +bool +pgm_print_polr ( + const struct pgm_header* const header, + const void* data, + const size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != header); + pgm_assert (NULL != data); + pgm_assert (len > 0); + + printf ("POLR: "); + + if (len < sizeof(struct pgm_polr)) { + puts ("packet truncated :("); + return FALSE; + } + + const struct pgm_polr* polr = (const struct pgm_polr*)data; + + printf("sqn %" PRIu32 " round %u", + ntohl(polr->polr_sqn), + ntohs(polr->polr_round)); + + const void* pgm_opt = (const uint8_t*)data + sizeof(struct pgm_polr); + size_t pgm_opt_len = len - sizeof(struct pgm_polr); + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT && + pgm_print_options (pgm_opt, pgm_opt_len) < 0 ) + { + return FALSE; + } + + printf ("\n"); + return TRUE; +} + +/* 8.2. Data Packet + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Data Packet Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Trailing Edge Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Data ... + * +-+-+- ... + */ + +static +bool +pgm_print_odata ( + const struct pgm_header* const header, + const void* data, + const size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != header); + pgm_assert (NULL != data); + pgm_assert (len > 0); + + printf ("ODATA: "); + + if (len < sizeof(struct pgm_data)) { + puts ("packet truncated :("); + return FALSE; + } + + const struct pgm_data* odata = (const struct pgm_data*)data; + + printf ("sqn %" PRIu32 " trail %" PRIu32 " [", + ntohl(odata->data_sqn), + ntohl(odata->data_trail)); + +/* option extensions */ + const void* pgm_opt = (const uint8_t*)data + sizeof(struct pgm_data); + size_t pgm_opt_len = len - sizeof(struct pgm_data); + const char* payload = pgm_opt; + + if (header->pgm_options & PGM_OPT_PRESENT) { + const ssize_t opt_len = pgm_print_options (pgm_opt, pgm_opt_len); + if (opt_len < 0) + return FALSE; + payload += opt_len; + } + +/* data */ + const char* end = payload + ntohs (header->pgm_tsdu_length); + while (payload < end) { + if (isprint (*payload)) + putchar (*payload); + else + putchar ('.'); + payload++; + } + + printf ("]\n"); + return TRUE; +} + +/* 8.2. Repair Data + */ + +static +bool +pgm_print_rdata ( + const struct pgm_header* const header, + const void* data, + const size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != header); + pgm_assert (NULL != data); + pgm_assert (len > 0); + + printf ("RDATA: "); + + if (len < sizeof(struct pgm_data)) { + puts ("packet truncated :("); + return FALSE; + } + + const struct pgm_data* rdata = (const struct pgm_data*)data; + + printf ("sqn %" PRIu32 " trail %" PRIu32 " [", + ntohl (rdata->data_sqn), + ntohl (rdata->data_trail)); + +/* option extensions */ + const void* pgm_opt = (const uint8_t*)data + sizeof(struct pgm_data); + size_t pgm_opt_len = len - sizeof(struct pgm_data); + const char* payload = pgm_opt; + + if (header->pgm_options & PGM_OPT_PRESENT) { + const ssize_t opt_len = pgm_print_options (pgm_opt, pgm_opt_len); + if (opt_len < 0) + return FALSE; + payload += opt_len; + } + +/* data */ + const char* end = payload + ntohs (header->pgm_tsdu_length); + while (payload < end) { + if (isprint (*payload)) + putchar (*payload); + else + putchar ('.'); + payload++; + } + + printf ("]\n"); + return TRUE; +} + +/* 8.3. NAK + * + * Technically the AFI of the source and multicast group can be different + * but that would be very wibbly wobbly. One example is using a local DLR + * with a IPv4 address to reduce NAK cost for recovery on wide IPv6 + * distribution. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Requested Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Multicast Group NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | Option Extensions when present ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... + */ + +#define PGM_MIN_NAK_SIZE ( sizeof(struct pgm_nak) ) + +static +bool +pgm_print_nak ( + const struct pgm_header* const header, + const void* data, + const size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != header); + pgm_assert (NULL != data); + pgm_assert (len > 0); + + printf ("NAK: "); + + if (len < PGM_MIN_NAK_SIZE) { + puts ("packet truncated :("); + return FALSE; + } + + const struct pgm_nak * nak = (const struct pgm_nak *)data; + const struct pgm_nak6* nak6 = (const struct pgm_nak6*)data; + const uint16_t nak_src_nla_afi = ntohs (nak->nak_src_nla_afi); + + printf ("sqn %" PRIu32 " src ", + ntohl(nak->nak_sqn)); + + char s[INET6_ADDRSTRLEN]; + const void* pgm_opt; + size_t pgm_opt_len; + +/* source nla */ + switch (nak_src_nla_afi) { + case AFI_IP: { + const uint16_t nak_grp_nla_afi = ntohs (nak->nak_grp_nla_afi); + if (nak_src_nla_afi != nak_grp_nla_afi) { + puts ("different source & group afi very wibbly wobbly :("); + return FALSE; + } + + pgm_inet_ntop (AF_INET, &nak->nak_src_nla, s, sizeof(s)); + pgm_opt = (const uint8_t*)data + sizeof(struct pgm_nak); + pgm_opt_len = len - sizeof(struct pgm_nak); + printf ("%s grp ", s); + + pgm_inet_ntop (AF_INET, &nak->nak_grp_nla, s, sizeof(s)); + printf ("%s", s); + break; + } + + case AFI_IP6: { + if (len < sizeof (struct pgm_nak6)) { + puts ("packet truncated :("); + return FALSE; + } + + const uint16_t nak_grp_nla_afi = ntohs (nak6->nak6_grp_nla_afi); + if (nak_src_nla_afi != nak_grp_nla_afi) { + puts ("different source & group afi very wibbly wobbly :("); + return FALSE; + } + + pgm_inet_ntop (AF_INET6, &nak6->nak6_src_nla, s, sizeof(s)); + pgm_opt = (const uint8_t*)data + sizeof(struct pgm_nak6); + pgm_opt_len = len - sizeof(struct pgm_nak6); + printf ("%s grp ", s); + + pgm_inet_ntop (AF_INET6, &nak6->nak6_grp_nla, s, sizeof(s)); + printf ("%s", s); + break; + } + + default: + puts ("unsupported afi"); + return FALSE; + } + + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT && + pgm_print_options (pgm_opt, pgm_opt_len) < 0 ) + { + return FALSE; + } + + printf ("\n"); + return TRUE; +} + +/* 8.3. N-NAK + */ + +static +bool +pgm_print_nnak ( + PGM_GNUC_UNUSED const struct pgm_header* const header, + PGM_GNUC_UNUSED const void* data, + const size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != header); + pgm_assert (NULL != data); + pgm_assert (len > 0); + + printf ("N-NAK: "); + + if (len < sizeof(struct pgm_nak)) { + puts ("packet truncated :("); + return FALSE; + } + +// struct pgm_nak* nnak = (struct pgm_nak*)data; + + return TRUE; +} + +/* 8.3. NCF + */ + +bool +pgm_print_ncf ( + PGM_GNUC_UNUSED const struct pgm_header* const header, + PGM_GNUC_UNUSED const void* data, + const size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != header); + pgm_assert (NULL != data); + pgm_assert (len > 0); + + printf ("NCF: "); + + if (len < sizeof(struct pgm_nak)) { + puts ("packet truncated :("); + return FALSE; + } + +// struct pgm_nak* ncf = (struct pgm_nak*)data; + + return TRUE; +} + +/* 13.6. SPM Request + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... + */ + +static +bool +pgm_print_spmr ( + const struct pgm_header* const header, + const void* data, + const size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != header); + pgm_assert (NULL != data); + pgm_assert (len > 0); + + printf ("SPMR: "); + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT && + pgm_print_options (data, len) < 0 ) + { + return FALSE; + } + + printf ("\n"); + return TRUE; +} + +/* PGMCC: ACK + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | RX_MAX | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Received Packet Bitmap | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... + */ + +static +bool +pgm_print_ack ( + const struct pgm_header* const header, + const void* data, + const size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != header); + pgm_assert (NULL != data); + pgm_assert (len > 0); + + printf ("ACK: "); + + const struct pgm_ack* ack = (const struct pgm_ack*)data; + char bitmap[33]; + + for (unsigned i = 31; i; i--) + bitmap[i] = (ack->ack_bitmap & (1 << i)) ? '1' : '0'; + bitmap[32] = '\0'; + + printf ("rx_max %" PRIu32 " bitmap [%s] ", + ntohl(ack->ack_rx_max), bitmap); + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT && + pgm_print_options (data, len) < 0 ) + { + return FALSE; + } + + printf ("\n"); + return TRUE; +} + + +/* Parse PGM options fields, alters contents of packet. + * + * returns -1 on failure, or total length in octets of the option fields + */ + +static +ssize_t +pgm_print_options ( + const void* data, + size_t len + ) +{ +/* pre-conditions */ + pgm_assert (NULL != data); + pgm_assert (len > 0); + + printf (" OPTIONS:"); + if (len < sizeof(struct pgm_opt_length)) { + puts (" packet truncated :("); + return -1; + } + + const struct pgm_opt_length* opt_len = (const struct pgm_opt_length*)data; + if (opt_len->opt_length != sizeof(struct pgm_opt_length)) { + printf (" bad opt_length length %u\n", (unsigned)opt_len->opt_length); + return -1; + } + + uint16_t opt_total_length = ntohs (opt_len->opt_total_length); + printf (" total len %u ", opt_total_length); + if (opt_total_length < (sizeof(struct pgm_opt_length) + sizeof(struct pgm_opt_header)) || + opt_total_length > len) + { + puts ("bad total length"); + return -1; + } + +/* total length includes opt_length option */ + opt_total_length -= sizeof(struct pgm_opt_length); + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)(opt_len + 1); + +/* iterate through options (max 16) */ + unsigned count = 16; + while (opt_total_length && count) + { + if (opt_total_length < sizeof(struct pgm_opt_header) || + opt_header->opt_length > opt_total_length) + { + puts ("short on option data :o"); + return -1; + } + + if (opt_header->opt_type & PGM_OPT_END) { + printf ("OPT_END+"); + } + + switch (opt_header->opt_type & PGM_OPT_MASK) { + case PGM_OPT_FRAGMENT: + printf ("OPT_FRAGMENT "); + break; + + case PGM_OPT_NAK_LIST: + printf ("OPT_NAK_LIST "); + break; + + case PGM_OPT_JOIN: + printf ("OPT_JOIN "); + break; + + case PGM_OPT_REDIRECT: + printf ("OPT_REDIRECT "); + break; + + case PGM_OPT_SYN: + printf ("OPT_SYN "); + break; + + case PGM_OPT_FIN: + printf ("OPT_FIN "); + break; + + case PGM_OPT_RST: + printf ("OPT_RST "); + break; + + case PGM_OPT_PARITY_PRM: + printf ("OPT_PARITY_PRM "); + break; + + case PGM_OPT_CURR_TGSIZE: + printf ("OPT_CURR_TGSIZE "); + break; + + case PGM_OPT_CR: + printf ("OPT_CR "); + break; + + case PGM_OPT_CRQST: + printf ("OPT_CRQST "); + break; + + case PGM_OPT_PGMCC_DATA: + printf ("OPT_PGMCC_DATA "); + break; + + case PGM_OPT_PGMCC_FEEDBACK: + printf ("OPT_PGMCC_FEEDBACK "); + break; + + case PGM_OPT_NAK_BO_IVL: + printf ("OPT_NAK_BO_IVL "); + break; + + case PGM_OPT_NAK_BO_RNG: + printf ("OPT_NAK_BO_RNG "); + break; + + case PGM_OPT_NBR_UNREACH: + printf ("OPT_NBR_UNREACH "); + break; + + case PGM_OPT_PATH_NLA: + printf ("OPT_PATH_NLA "); + break; + + default: + printf ("OPT-%u{%u} ", opt_header->opt_type & PGM_OPT_MASK, opt_header->opt_length); + break; + } + + opt_total_length -= opt_header->opt_length; + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); + + count--; + } + + if (!count) { + puts ("too many options found"); + return -1; + } + + return ((const uint8_t*)opt_header - (const uint8_t*)data); +} + +const char* +pgm_type_string ( + uint8_t type + ) +{ + const char* c; + + switch (type) { + case PGM_SPM: c = "PGM_SPM"; break; + case PGM_POLL: c = "PGM_POLL"; break; + case PGM_POLR: c = "PGM_POLR"; break; + case PGM_ODATA: c = "PGM_ODATA"; break; + case PGM_RDATA: c = "PGM_RDATA"; break; + case PGM_NAK: c = "PGM_NAK"; break; + case PGM_NNAK: c = "PGM_NNAK"; break; + case PGM_NCF: c = "PGM_NCF"; break; + case PGM_SPMR: c = "PGM_SPMR"; break; + case PGM_ACK: c = "PGM_ACK"; break; + default: c = "(unknown)"; break; + } + + return c; +} + +const char* +pgm_udpport_string ( + uint16_t port + ) +{ + static pgm_hashtable_t *services = NULL; + + if (!services) { + services = pgm_hashtable_new (pgm_int_hash, pgm_int_equal); + } + + const int hash_key = port; + void* service_string = pgm_hashtable_lookup (services, &hash_key); + if (service_string != NULL) { + return service_string; + } + + struct servent* se = getservbyport (port, "udp"); + if (se == NULL) { + char buf[sizeof("00000")]; + snprintf(buf, sizeof(buf), "%u", ntohs(port)); + service_string = pgm_strdup(buf); + } else { + service_string = pgm_strdup(se->s_name); + } + pgm_hashtable_insert (services, &hash_key, service_string); + return service_string; +} + +const char* +pgm_gethostbyaddr ( + const struct in_addr* ap + ) +{ + static pgm_hashtable_t *hosts = NULL; + + if (!hosts) { + hosts = pgm_hashtable_new (pgm_str_hash, pgm_int_equal); + } + + const int hash_key = (int)ap->s_addr; + void* host_string = pgm_hashtable_lookup (hosts, &hash_key); + if (host_string != NULL) { + return host_string; + } + + struct hostent* he = gethostbyaddr((const char*)ap, sizeof(struct in_addr), AF_INET); + if (he == NULL) { + struct in_addr in; + memcpy (&in, ap, sizeof(in)); + host_string = pgm_strdup(inet_ntoa(in)); + } else { + host_string = pgm_strdup(he->h_name); + } + pgm_hashtable_insert (hosts, &hash_key, host_string); + return host_string; +} + +void +pgm_ipopt_print ( + const void* ipopt, + size_t length + ) +{ +/* pre-conditions */ + pgm_assert (NULL != ipopt); + + const char* op = ipopt; + + while (length) + { + char len = (*op == PGM_IPOPT_NOP || *op == PGM_IPOPT_EOL) ? 1 : op[1]; + switch (*op) { + case PGM_IPOPT_EOL: printf(" eol"); break; + case PGM_IPOPT_NOP: printf(" nop"); break; + case PGM_IPOPT_RR: printf(" rr"); break; /* 1 route */ + case PGM_IPOPT_TS: printf(" ts"); break; /* 1 TS */ +#if 0 + case PGM_IPOPT_SECURITY: printf(" sec-level"); break; + case PGM_IPOPT_LSRR: printf(" lsrr"); break; /* 1 route */ + case PGM_IPOPT_SATID: printf(" satid"); break; + case PGM_IPOPT_SSRR: printf(" ssrr"); break; /* 1 route */ +#endif + default: printf(" %x{%d}", (int)*op, (int)len); break; + } + + if (!len) { + puts ("invalid IP opt length"); + return; + } + + op += len; + length -= len; + } +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/packet_test.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/packet_test.c.c89.patch new file mode 100644 index 0000000..72dbcac --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/packet_test.c.c89.patch @@ -0,0 +1,401 @@ +--- packet_test.c 2010-08-04 15:24:51.000000000 +0800 ++++ packet_test.c89 2010-08-04 15:40:35.000000000 +0800 +@@ -66,12 +66,13 @@ + /* minimum size should be IP header plus PGM header */ + if (len < (sizeof(struct pgm_ip) + sizeof(struct pgm_header))) + { +- printf ("Packet size too small: %zu bytes, expecting at least %zu bytes.\n", ++ printf ("Packet size too small: %lu bytes, expecting at least %lu bytes.\n", + len, sizeof(struct pgm_ip) + sizeof(struct pgm_header)); + return FALSE; + } + + /* decode IP header */ ++ { + const struct pgm_ip* ip = (const struct pgm_ip*)data; + if (ip->ip_v != 4) /* IP version, 4 or 6 */ + { +@@ -80,6 +81,7 @@ + } + printf ("IP "); + ++ { + const size_t ip_header_length = ip->ip_hl * 4; /* IP header length in 32bit octets */ + if (ip_header_length < sizeof(struct pgm_ip)) + { +@@ -87,6 +89,7 @@ + return FALSE; + } + ++ { + size_t packet_length = ntohs(ip->ip_len); /* total packet length */ + + /* ip_len can equal packet_length - ip_header_length in FreeBSD/NetBSD +@@ -109,6 +112,7 @@ + return FALSE; + } + ++ { + const uint16_t offset = ntohs(ip->ip_off); + + /* 3 bits routing priority, 4 bits type of service: delay, throughput, reliability, cost */ +@@ -135,7 +139,7 @@ + (offset & 0x1fff) * 8, + ((offset & IP_DF) ? "DF" : ""), + ((offset & IP_MF) ? "+" : "")); +- printf (", length %zu", packet_length); ++ printf (", length %lu", packet_length); + + /* IP options */ + if ((ip_header_length - sizeof(struct pgm_ip)) > 0) { +@@ -146,6 +150,7 @@ + + /* packets that fail checksum will generally not be passed upstream except with rfc3828 + */ ++ { + const uint16_t ip_sum = pgm_inet_checksum(data, packet_length, 0); + if (ip_sum != 0) { + const uint16_t encoded_ip_sum = ntohs(ip->ip_sum); +@@ -176,6 +181,7 @@ + * | Type specific data ... + * +-+-+-+-+-+-+-+-+-+- ... + */ ++ { + const struct pgm_header* pgm_header = (const struct pgm_header*)((const char*)data + ip_header_length); + const size_t pgm_length = packet_length - ip_header_length; + +@@ -227,6 +233,7 @@ + } + + /* now decode PGM packet types */ ++ { + const void* pgm_data = pgm_header + 1; + const size_t pgm_data_length = pgm_length - sizeof(pgm_header); /* can equal zero for SPMR's */ + +@@ -246,6 +253,13 @@ + } + + return err; ++ } ++ } ++ } ++ } ++ } ++ } ++ } + } + + /* 8.1. Source Path Messages (SPM) +@@ -293,6 +307,7 @@ + return FALSE; + } + ++ { + const struct pgm_spm * spm = (const struct pgm_spm *)data; + const struct pgm_spm6* spm6 = (const struct pgm_spm6*)data; + const uint16_t spm_nla_afi = ntohs (spm->spm_nla_afi); +@@ -303,6 +318,7 @@ + ntohl(spm->spm_lead), + spm_nla_afi); /* address family indicator */ + ++ { + char s[INET6_ADDRSTRLEN]; + const void* pgm_opt; + size_t pgm_opt_len; +@@ -340,6 +356,8 @@ + + printf ("\n"); + return TRUE; ++ } ++ } + } + + /* 14.7.1. Poll Request +@@ -389,6 +407,7 @@ + return FALSE; + } + ++ { + const struct pgm_poll * poll4 = (const struct pgm_poll *)data; + const struct pgm_poll6* poll6 = (const struct pgm_poll6*)data; + const uint16_t poll_nla_afi = ntohs (poll4->poll_nla_afi); +@@ -399,6 +418,7 @@ + ntohs(poll4->poll_s_type), + poll_nla_afi); /* address family indicator */ + ++ { + char s[INET6_ADDRSTRLEN]; + const void* pgm_opt; + size_t pgm_opt_len; +@@ -463,6 +483,8 @@ + + printf ("\n"); + return TRUE; ++ } ++ } + } + + /* 14.7.2. Poll Response +@@ -498,12 +520,14 @@ + return FALSE; + } + ++ { + const struct pgm_polr* polr = (const struct pgm_polr*)data; + + printf("sqn %" PRIu32 " round %u", + ntohl(polr->polr_sqn), + ntohs(polr->polr_round)); + ++ { + const void* pgm_opt = (const uint8_t*)data + sizeof(struct pgm_polr); + size_t pgm_opt_len = len - sizeof(struct pgm_polr); + +@@ -516,6 +540,8 @@ + + printf ("\n"); + return TRUE; ++ } ++ } + } + + /* 8.2. Data Packet +@@ -553,6 +579,7 @@ + return FALSE; + } + ++ { + const struct pgm_data* odata = (const struct pgm_data*)data; + + printf ("sqn %" PRIu32 " trail %" PRIu32 " [", +@@ -560,6 +587,7 @@ + ntohl(odata->data_trail)); + + /* option extensions */ ++ { + const void* pgm_opt = (const uint8_t*)data + sizeof(struct pgm_data); + size_t pgm_opt_len = len - sizeof(struct pgm_data); + const char* payload = pgm_opt; +@@ -572,6 +600,7 @@ + } + + /* data */ ++ { + const char* end = payload + ntohs (header->pgm_tsdu_length); + while (payload < end) { + if (isprint (*payload)) +@@ -583,6 +612,9 @@ + + printf ("]\n"); + return TRUE; ++ } ++ } ++ } + } + + /* 8.2. Repair Data +@@ -608,6 +640,7 @@ + return FALSE; + } + ++ { + const struct pgm_data* rdata = (const struct pgm_data*)data; + + printf ("sqn %" PRIu32 " trail %" PRIu32 " [", +@@ -615,6 +648,7 @@ + ntohl (rdata->data_trail)); + + /* option extensions */ ++ { + const void* pgm_opt = (const uint8_t*)data + sizeof(struct pgm_data); + size_t pgm_opt_len = len - sizeof(struct pgm_data); + const char* payload = pgm_opt; +@@ -627,6 +661,7 @@ + } + + /* data */ ++ { + const char* end = payload + ntohs (header->pgm_tsdu_length); + while (payload < end) { + if (isprint (*payload)) +@@ -638,6 +673,9 @@ + + printf ("]\n"); + return TRUE; ++ } ++ } ++ } + } + + /* 8.3. NAK +@@ -686,6 +724,7 @@ + return FALSE; + } + ++ { + const struct pgm_nak * nak = (const struct pgm_nak *)data; + const struct pgm_nak6* nak6 = (const struct pgm_nak6*)data; + const uint16_t nak_src_nla_afi = ntohs (nak->nak_src_nla_afi); +@@ -693,6 +732,7 @@ + printf ("sqn %" PRIu32 " src ", + ntohl(nak->nak_sqn)); + ++ { + char s[INET6_ADDRSTRLEN]; + const void* pgm_opt; + size_t pgm_opt_len; +@@ -722,6 +762,7 @@ + return FALSE; + } + ++ { + const uint16_t nak_grp_nla_afi = ntohs (nak6->nak6_grp_nla_afi); + if (nak_src_nla_afi != nak_grp_nla_afi) { + puts ("different source & group afi very wibbly wobbly :("); +@@ -736,6 +777,7 @@ + pgm_inet_ntop (AF_INET6, &nak6->nak6_grp_nla, s, sizeof(s)); + printf ("%s", s); + break; ++ } + } + + default: +@@ -753,6 +795,8 @@ + + printf ("\n"); + return TRUE; ++ } ++ } + } + + /* 8.3. N-NAK +@@ -873,11 +917,15 @@ + + printf ("ACK: "); + ++ { + const struct pgm_ack* ack = (const struct pgm_ack*)data; + char bitmap[33]; + +- for (unsigned i = 31; i; i--) ++ { ++ unsigned i; ++ for (i = 31; i; i--) + bitmap[i] = (ack->ack_bitmap & (1 << i)) ? '1' : '0'; ++ } + bitmap[32] = '\0'; + + printf ("rx_max %" PRIu32 " bitmap [%s] ", +@@ -892,6 +940,7 @@ + + printf ("\n"); + return TRUE; ++ } + } + + +@@ -917,12 +966,14 @@ + return -1; + } + ++ { + const struct pgm_opt_length* opt_len = (const struct pgm_opt_length*)data; + if (opt_len->opt_length != sizeof(struct pgm_opt_length)) { + printf (" bad opt_length length %u\n", (unsigned)opt_len->opt_length); + return -1; + } + ++ { + uint16_t opt_total_length = ntohs (opt_len->opt_total_length); + printf (" total len %u ", opt_total_length); + if (opt_total_length < (sizeof(struct pgm_opt_length) + sizeof(struct pgm_opt_header)) || +@@ -934,6 +985,7 @@ + + /* total length includes opt_length option */ + opt_total_length -= sizeof(struct pgm_opt_length); ++ { + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)(opt_len + 1); + + /* iterate through options (max 16) */ +@@ -1037,6 +1089,9 @@ + } + + return ((const uint8_t*)opt_header - (const uint8_t*)data); ++ } ++ } ++ } + } + + const char* +@@ -1074,22 +1129,30 @@ + services = pgm_hashtable_new (pgm_int_hash, pgm_int_equal); + } + ++ { + const int hash_key = port; + void* service_string = pgm_hashtable_lookup (services, &hash_key); + if (service_string != NULL) { + return service_string; + } + ++ { + struct servent* se = getservbyport (port, "udp"); + if (se == NULL) { + char buf[sizeof("00000")]; +- snprintf(buf, sizeof(buf), "%u", ntohs(port)); ++#ifdef _MSC_VER ++ _snprintf_s (buf, sizeof(buf), _TRUNCATE, "%u", ntohs(port)); ++#else ++ snprintf (buf, sizeof(buf), "%u", ntohs(port)); ++#endif + service_string = pgm_strdup(buf); + } else { + service_string = pgm_strdup(se->s_name); + } + pgm_hashtable_insert (services, &hash_key, service_string); + return service_string; ++ } ++ } + } + + const char* +@@ -1103,12 +1166,14 @@ + hosts = pgm_hashtable_new (pgm_str_hash, pgm_int_equal); + } + ++ { + const int hash_key = (int)ap->s_addr; + void* host_string = pgm_hashtable_lookup (hosts, &hash_key); + if (host_string != NULL) { + return host_string; + } + ++ { + struct hostent* he = gethostbyaddr((const char*)ap, sizeof(struct in_addr), AF_INET); + if (he == NULL) { + struct in_addr in; +@@ -1119,6 +1184,8 @@ + } + pgm_hashtable_insert (hosts, &hash_key, host_string); + return host_string; ++ } ++ } + } + + void +@@ -1130,6 +1197,7 @@ + /* pre-conditions */ + pgm_assert (NULL != ipopt); + ++ { + const char* op = ipopt; + + while (length) +@@ -1157,6 +1225,7 @@ + op += len; + length -= len; + } ++ } + } + + /* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/packet_test_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/packet_test_unittest.c new file mode 100644 index 0000000..7edefbb --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/packet_test_unittest.c @@ -0,0 +1,169 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for PGM packet handling. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include + + +/* mock state */ + +#define PACKET_DEBUG +#include "packet_test.c" + + +static +struct pgm_sk_buff_t* +generate_raw_pgm (void) +{ + const char source[] = "i am not a string"; + const guint source_len = sizeof(source); + struct pgm_sk_buff_t* skb; + GError* err = NULL; + + skb = pgm_alloc_skb (1500); + skb->sock = (pgm_sock_t*)0x1; + skb->tstamp = 0x1; + skb->data = skb->head; + skb->len = sizeof(struct pgm_ip) + sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len; + skb->tail = (guint8*)skb->data + skb->len; + +/* add IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_hl = sizeof(struct pgm_ip) / 4; + iphdr->ip_v = 4; + iphdr->ip_tos = 0; + iphdr->ip_len = g_htons (skb->len); + iphdr->ip_id = 0; + iphdr->ip_off = 0; + iphdr->ip_ttl = 16; + iphdr->ip_p = IPPROTO_PGM; + iphdr->ip_sum = 0; + iphdr->ip_src.s_addr = inet_addr ("127.0.0.1"); + iphdr->ip_dst.s_addr = inet_addr ("127.0.0.2"); + +/* add PGM header */ + struct pgm_header* pgmhdr = (gpointer)(iphdr + 1); + pgmhdr->pgm_sport = g_htons ((guint16)1000); + pgmhdr->pgm_dport = g_htons ((guint16)7500); + pgmhdr->pgm_type = PGM_ODATA; + pgmhdr->pgm_options = 0; + pgmhdr->pgm_gsi[0] = 1; + pgmhdr->pgm_gsi[1] = 2; + pgmhdr->pgm_gsi[2] = 3; + pgmhdr->pgm_gsi[3] = 4; + pgmhdr->pgm_gsi[4] = 5; + pgmhdr->pgm_gsi[5] = 6; + pgmhdr->pgm_tsdu_length = g_htons (source_len); + +/* add ODATA header */ + struct pgm_data* datahdr = (gpointer)(pgmhdr + 1); + datahdr->data_sqn = g_htonl ((guint32)0); + datahdr->data_trail = g_htonl ((guint32)-1); + +/* add payload */ + gpointer data = (gpointer)(datahdr + 1); + memcpy (data, source, source_len); + +/* finally PGM checksum */ + pgmhdr->pgm_checksum = 0; + pgmhdr->pgm_checksum = pgm_csum_fold (pgm_csum_partial (pgmhdr, sizeof(struct pgm_header) + sizeof(struct pgm_data) + source_len, 0)); + +/* and IP checksum */ + iphdr->ip_sum = pgm_inet_checksum (skb->head, skb->len, 0); + + return skb; +} + + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + + +/* target: + * gboolean + * pgm_print_packet ( + * gpointer data, + * gsize len + * ) + */ + +START_TEST (test_print_packet_pass_001) +{ + struct pgm_sk_buff_t* skb = generate_raw_pgm (); + pgm_print_packet (skb->head, skb->len); +} +END_TEST + +START_TEST (test_print_packet_fail_001) +{ + pgm_print_packet (NULL, 0); + fail ("reached"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_print_packet = tcase_create ("print-packet"); + suite_add_tcase (s, tc_print_packet); + tcase_add_test (tc_print_packet, test_print_packet_pass_001); + tcase_add_test_raise_signal (tc_print_packet, test_print_packet_fail_001, SIGABRT); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/pgmMIB.c b/3rdparty/openpgm-svn-r1135/pgm/pgmMIB.c new file mode 100644 index 0000000..1226c50 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/pgmMIB.c @@ -0,0 +1,3212 @@ +/* + * Note: this file originally auto-generated by mib2c using + * : mib2c.notify.conf,v 5.3 2004/04/15 12:29:19 dts12 Exp $ + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "pgm/snmp.h" +#include "impl/pgmMIB.h" +#include "impl/pgmMIB_columns.h" +#include "impl/pgmMIB_enums.h" + + +//#define PGMMIB_DEBUG + + +/* locals */ + +struct pgm_snmp_context_t { + pgm_slist_t* list; + pgm_list_t* node; + int index; /* table index */ + unsigned instance; /* unique number per node */ +}; + +typedef struct pgm_snmp_context_t pgm_snmp_context_t; + +static const oid snmptrap_oid[] = {1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0}; + + +/* functions */ + +static int initialize_table_pgmSourceTable(void); +static Netsnmp_Node_Handler pgmSourceTable_handler; +static Netsnmp_First_Data_Point pgmSourceTable_get_first_data_point; +static Netsnmp_Next_Data_Point pgmSourceTable_get_next_data_point; +static Netsnmp_Free_Loop_Context pgmSourceTable_free_loop_context; + +static int initialize_table_pgmSourceConfigTable(void); +static Netsnmp_Node_Handler pgmSourceConfigTable_handler; +static Netsnmp_First_Data_Point pgmSourceConfigTable_get_first_data_point; +static Netsnmp_Next_Data_Point pgmSourceConfigTable_get_next_data_point; +static Netsnmp_Free_Loop_Context pgmSourceConfigTable_free_loop_context; + +static int initialize_table_pgmSourcePerformanceTable(void); +static Netsnmp_Node_Handler pgmSourcePerformanceTable_handler; +static Netsnmp_First_Data_Point pgmSourcePerformanceTable_get_first_data_point; +static Netsnmp_Next_Data_Point pgmSourcePerformanceTable_get_next_data_point; +static Netsnmp_Free_Loop_Context pgmSourcePerformanceTable_free_loop_context; + +static int initialize_table_pgmReceiverTable(void); +static Netsnmp_Node_Handler pgmReceiverTable_handler; +static Netsnmp_First_Data_Point pgmReceiverTable_get_first_data_point; +static Netsnmp_Next_Data_Point pgmReceiverTable_get_next_data_point; +static Netsnmp_Free_Loop_Context pgmReceiverTable_free_loop_context; + +static int initialize_table_pgmReceiverConfigTable(void); +static Netsnmp_Node_Handler pgmReceiverConfigTable_handler; +static Netsnmp_First_Data_Point pgmReceiverConfigTable_get_first_data_point; +static Netsnmp_Next_Data_Point pgmReceiverConfigTable_get_next_data_point; +static Netsnmp_Free_Loop_Context pgmReceiverConfigTable_free_loop_context; + +static int initialize_table_pgmReceiverPerformanceTable(void); +static Netsnmp_Node_Handler pgmReceiverPerformanceTable_handler; +static Netsnmp_First_Data_Point pgmReceiverPerformanceTable_get_first_data_point; +static Netsnmp_Next_Data_Point pgmReceiverPerformanceTable_get_next_data_point; +static Netsnmp_Free_Loop_Context pgmReceiverPerformanceTable_free_loop_context; + + +bool +pgm_mib_init ( + pgm_error_t** error + ) +{ + if (MIB_REGISTERED_OK != initialize_table_pgmSourceTable()) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SNMP, + PGM_ERROR_FAILED, + _("pgmSourceTable registration: see SNMP log for further details.")); + return FALSE; + } + if (MIB_REGISTERED_OK != initialize_table_pgmSourceConfigTable()) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SNMP, + PGM_ERROR_FAILED, + _("pgmSourceConfigTable registration: see SNMP log for further details.")); + return FALSE; + } + if (MIB_REGISTERED_OK != initialize_table_pgmSourcePerformanceTable()) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SNMP, + PGM_ERROR_FAILED, + _("pgmSourcePerformanceTable registration: see SNMP log for further details.")); + return FALSE; + } + if (MIB_REGISTERED_OK != initialize_table_pgmReceiverTable()) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SNMP, + PGM_ERROR_FAILED, + _("pgmReceiverTable registration: see SNMP log for further details.")); + return FALSE; + } + if (MIB_REGISTERED_OK != initialize_table_pgmReceiverConfigTable()) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SNMP, + PGM_ERROR_FAILED, + _("pgmReceiverConfigTable registration: see SNMP log for further details.")); + return FALSE; + } + if (MIB_REGISTERED_OK != initialize_table_pgmReceiverPerformanceTable()) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SNMP, + PGM_ERROR_FAILED, + _("pgmReceiverPerformanceTable registration: see SNMP log for further details.")); + return FALSE; + } + + return TRUE; +} + +/* + * pgmSourceTable + * + * returns MIB_REGISTERED_OK on success, failures include: + * MIB_REGISTRATION_FAILED + * MIB_DUPLICATE_REGISTRATION + * SNMPERR_GENERR + */ + +static +int +initialize_table_pgmSourceTable (void) +{ + pgm_debug ("initialize_table_pgmSourceTable ()"); + + static const oid pgmSourceTable_oid[] = {1,3,6,1,3,112,1,2,100,2}; + netsnmp_table_registration_info* table_info = NULL; + netsnmp_iterator_info* iinfo = NULL; + netsnmp_handler_registration* reg = NULL; + + reg = netsnmp_create_handler_registration ("pgmSourceTable", pgmSourceTable_handler, + pgmSourceTable_oid, OID_LENGTH( pgmSourceTable_oid ), + HANDLER_CAN_RONLY); + if (!reg) + goto error; + + table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); + if (!table_info) + goto error; + + table_info->min_column = COLUMN_PGMSOURCESOURCEADDRESS; + table_info->max_column = COLUMN_PGMSOURCESOURCEPORTNUMBER; + + netsnmp_table_helper_add_indexes (table_info, + ASN_OCTET_STR, /* index: pgmSourceGlobalId */ + ASN_UNSIGNED, /* index: pgmSourceSourcePort */ + 0); + + iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); + if (!iinfo) + goto error; + + iinfo->get_first_data_point = pgmSourceTable_get_first_data_point; + iinfo->get_next_data_point = pgmSourceTable_get_next_data_point; + iinfo->free_loop_context_at_end = pgmSourceTable_free_loop_context; + iinfo->table_reginfo = table_info; + + return netsnmp_register_table_iterator (reg, iinfo); + +error: + if (table_info && table_info->indexes) /* table_data_free_func() is internal */ + snmp_free_var (table_info->indexes); + SNMP_FREE( table_info ); + SNMP_FREE( iinfo ); + netsnmp_handler_registration_free (reg); + + return -1; +} + +/* called for first row of data in SNMP table + * + * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, + * optionally returns my_data_context. + * + * returns answer or NULL + */ + +static +netsnmp_variable_list* +pgmSourceTable_get_first_data_point( + void** my_loop_context, /* valid through one query of multiple "data points" */ + void** my_data_context, /* answer blob which is passed to handler() */ + netsnmp_variable_list* put_index_data, /* answer */ + netsnmp_iterator_info* mydata /* iinfo on init() */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmSourceTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_rwlock_reader_lock (&pgm_sock_list_lock); + + if (!pgm_sock_list) { + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + return NULL; + } + +/* create our own context for this SNMP loop */ + pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); + context->list = pgm_sock_list; + *my_loop_context = context; + +/* pass on for generic row access */ + return pgmSourceTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); +} + +static +netsnmp_variable_list* +pgmSourceTable_get_next_data_point( + void** my_loop_context, + void** my_data_context, + netsnmp_variable_list* put_index_data, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmSourceTable_get_next_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; + netsnmp_variable_list *idx = put_index_data; + + if (!context->list) + return NULL; + + pgm_sock_t* sock = context->list->data; + +/* pgmSourceGlobalId */ + char gsi[ PGM_GSISTRLEN ]; + pgm_gsi_print_r (&sock->tsi.gsi, gsi, sizeof(gsi)); + snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); + idx = idx->next_variable; + +/* pgmSourceSourcePort */ + const unsigned sport = ntohs (sock->tsi.sport); + snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); + + *my_data_context = sock; + context->list = context->list->next; + + return put_index_data; +} + +static +void +pgmSourceTable_free_loop_context ( + void* my_loop_context, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmSourceTable_free_loop_context (my_loop_context:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; + pgm_free (context); + my_loop_context = NULL; + + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); +} + +static +int +pgmSourceTable_handler ( + netsnmp_mib_handler* handler, + netsnmp_handler_registration* reginfo, + netsnmp_agent_request_info* reqinfo, + netsnmp_request_info* requests + ) +{ +/* pre-conditions */ + pgm_assert (NULL != handler); + pgm_assert (NULL != reginfo); + pgm_assert (NULL != reqinfo); + pgm_assert (NULL != requests); + + pgm_debug ("pgmSourceTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", + (const void*)handler, + (const void*)reginfo, + (const void*)reqinfo, + (const void*)requests); + + switch (reqinfo->mode) { + +/* Read-support (also covers GetNext requests) */ + + case MODE_GET: + for (netsnmp_request_info* request = requests; + request; + request = request->next) + { + const pgm_sock_t* sock = (pgm_sock_t*)netsnmp_extract_iterator_context (request); + + if (!sock) { + netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); + continue; + } + + netsnmp_variable_list *var = request->requestvb; + netsnmp_table_request_info* table_info = netsnmp_extract_table_info (request); + + if (!table_info) { + snmp_log (LOG_ERR, "pgmSourceTable_handler: empty table request info.\n"); + continue; + } + + switch (table_info->colnum) { + + case COLUMN_PGMSOURCESOURCEADDRESS: + { + struct sockaddr_in s4; + if (AF_INET == sock->send_gsr.gsr_source.ss_family) + memcpy (&s4, &sock->send_gsr.gsr_source, sizeof(s4)); + else + memset (&s4, 0, sizeof(s4)); + snmp_set_var_typed_value (var, ASN_IPADDRESS, + (const u_char*)&s4.sin_addr.s_addr, + sizeof(struct in_addr) ); + } + break; + + case COLUMN_PGMSOURCEGROUPADDRESS: + { + struct sockaddr_in s4; + if (AF_INET == sock->send_gsr.gsr_group.ss_family) + memcpy (&s4, &sock->send_gsr.gsr_group, sizeof(s4)); + else + memset (&s4, 0, sizeof(s4)); + snmp_set_var_typed_value (var, ASN_IPADDRESS, + (const u_char*)&s4.sin_addr.s_addr, + sizeof(struct in_addr) ); + } + break; + + case COLUMN_PGMSOURCEDESTPORT: + { + const unsigned dport = ntohs (sock->dport); + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&dport, sizeof(dport) ); + } + break; + +/* copy index[0] */ + case COLUMN_PGMSOURCESOURCEGSI: + snmp_set_var_typed_value (var, ASN_OCTET_STR, + (const u_char*)table_info->indexes->val.string, + table_info->indexes->val_len); + break; + +/* copy index[1] */ + case COLUMN_PGMSOURCESOURCEPORTNUMBER: + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)table_info->indexes->next_variable->val.integer, + table_info->indexes->next_variable->val_len); + + break; + + default: + snmp_log (LOG_ERR, "pgmSourceTable_handler: unknown column.\n"); + break; + } + } + break; + + case MODE_SET_RESERVE1: + default: + snmp_log (LOG_ERR, "pgmSourceTable_handler: unsupported mode.\n"); + break; + + } + + return SNMP_ERR_NOERROR; +} + +/* + * pgmSourceConfigTable + * + */ + +static +int +initialize_table_pgmSourceConfigTable(void) +{ + pgm_debug ("initialize_table_pgmSourceConfigTable ()"); + + static const oid pgmSourceConfigTable_oid[] = {1,3,6,1,3,112,1,2,100,3}; + netsnmp_table_registration_info* table_info = NULL; + netsnmp_iterator_info* iinfo = NULL; + netsnmp_handler_registration* reg = NULL; + + reg = netsnmp_create_handler_registration ("pgmSourceConfigTable", pgmSourceConfigTable_handler, + pgmSourceConfigTable_oid, OID_LENGTH( pgmSourceConfigTable_oid ), + HANDLER_CAN_RONLY); + if (!reg) + goto error; + + table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); + if (!table_info) + goto error; + + table_info->min_column = COLUMN_PGMSOURCETTL; + table_info->max_column = COLUMN_PGMSOURCESPMPATHADDRESS; + + netsnmp_table_helper_add_indexes (table_info, + ASN_OCTET_STR, /* index: pgmSourceConfigGlobalId */ + ASN_UNSIGNED, /* index: pgmSourceConfigSourcePort */ + 0); + + iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); + if (!iinfo) + goto error; + + iinfo->get_first_data_point = pgmSourceConfigTable_get_first_data_point; + iinfo->get_next_data_point = pgmSourceConfigTable_get_next_data_point; + iinfo->free_loop_context_at_end = pgmSourceConfigTable_free_loop_context; + iinfo->table_reginfo = table_info; + + return netsnmp_register_table_iterator (reg, iinfo); + +error: + if (table_info && table_info->indexes) /* table_data_free_func() is internal */ + snmp_free_var (table_info->indexes); + SNMP_FREE( table_info ); + SNMP_FREE( iinfo ); + netsnmp_handler_registration_free (reg); + + return -1; +} + +/* called for first row of data in SNMP table + * + * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, + * optionally returns my_data_context. + * + * returns answer or NULL + */ + +static +netsnmp_variable_list* +pgmSourceConfigTable_get_first_data_point( + void** my_loop_context, /* valid through one query of multiple "data points" */ + void** my_data_context, /* answer blob which is passed to handler() */ + netsnmp_variable_list* put_index_data, /* answer */ + netsnmp_iterator_info* mydata /* iinfo on init() */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmSourceConfigTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_rwlock_reader_lock (&pgm_sock_list_lock); + + if (!pgm_sock_list) { + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + return NULL; + } + +/* create our own context for this SNMP loop */ + pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); + context->list = pgm_sock_list; + *my_loop_context = context; + +/* pass on for generic row access */ + return pgmSourceConfigTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); +} + +static +netsnmp_variable_list* +pgmSourceConfigTable_get_next_data_point( + void** my_loop_context, + void** my_data_context, + netsnmp_variable_list* put_index_data, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmSourceConfigTable_get_next_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; + netsnmp_variable_list *idx = put_index_data; + + if (!context->list) + return NULL; + + pgm_sock_t* sock = context->list->data; + +/* pgmSourceGlobalId */ + char gsi[ PGM_GSISTRLEN ]; + pgm_gsi_print_r (&sock->tsi.gsi, gsi, sizeof(gsi)); + snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); + idx = idx->next_variable; + +/* pgmSourceSourcePort */ + const unsigned sport = ntohs (sock->tsi.sport); + snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); + + *my_data_context = sock; + context->list = context->list->next; + + return put_index_data; +} + +static +void +pgmSourceConfigTable_free_loop_context ( + void* my_loop_context, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmSourceConfigTable_free_loop_context (my_loop_context:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; + pgm_free (context); + my_loop_context = NULL; + + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); +} + +static +int +pgmSourceConfigTable_handler ( + netsnmp_mib_handler* handler, + netsnmp_handler_registration* reginfo, + netsnmp_agent_request_info* reqinfo, + netsnmp_request_info* requests + ) +{ +/* pre-conditions */ + pgm_assert (NULL != handler); + pgm_assert (NULL != reginfo); + pgm_assert (NULL != reqinfo); + pgm_assert (NULL != requests); + + pgm_debug ("pgmSourceConfigTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", + (const void*)handler, + (const void*)reginfo, + (const void*)reqinfo, + (const void*)requests); + + switch (reqinfo->mode) { + +/* Read-support (also covers GetNext requests) */ + + case MODE_GET: + for (netsnmp_request_info* request = requests; + request; + request = request->next) + { + const pgm_sock_t* sock = (pgm_sock_t*)netsnmp_extract_iterator_context (request); + + if (!sock) { + netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); + continue; + } + + netsnmp_variable_list *var = request->requestvb; + netsnmp_table_request_info* table_info = netsnmp_extract_table_info (request); + + if (!table_info) { + snmp_log (LOG_ERR, "pgmSourceTable_handler: empty table request info.\n"); + continue; + } + + switch (table_info->colnum) { + + case COLUMN_PGMSOURCETTL: + { + const unsigned hops = sock->hops; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&hops, sizeof(hops) ); + } + break; + + case COLUMN_PGMSOURCEADVMODE: + { + const unsigned adv_mode = 0 == sock->adv_mode ? PGMSOURCEADVMODE_TIME : PGMSOURCEADVMODE_DATA; + snmp_set_var_typed_value (var, ASN_INTEGER, + (const u_char*)&adv_mode, sizeof(adv_mode) ); + } + break; + +/* FIXED: pgmSourceLateJoin = disable(2) */ + case COLUMN_PGMSOURCELATEJOIN: + { + const unsigned late_join = PGMSOURCELATEJOIN_DISABLE; + snmp_set_var_typed_value (var, ASN_INTEGER, + (const u_char*)&late_join, sizeof(late_join) ); + } + break; + + case COLUMN_PGMSOURCETXWMAXRTE: + { + const unsigned txw_max_rte = sock->txw_max_rte; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&txw_max_rte, sizeof(txw_max_rte) ); + } + break; + + case COLUMN_PGMSOURCETXWSECS: + { + const unsigned txw_secs = sock->txw_secs; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&txw_secs, sizeof(txw_secs) ); + } + break; + +/* FIXED: TXW_ADV_SECS = 0 */ + case COLUMN_PGMSOURCETXWADVSECS: + { + const unsigned txw_adv_secs = 0; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&txw_adv_secs, sizeof(txw_adv_secs) ); + } + break; + +/* FIXED: pgmSourceAdvIvl = TXW_ADV_SECS * 1000 = 0 */ + case COLUMN_PGMSOURCEADVIVL: + { + const unsigned adv_ivl = 0; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&adv_ivl, sizeof(adv_ivl) ); + } + break; + + case COLUMN_PGMSOURCESPMIVL: + { + const unsigned spm_ivl = pgm_to_msecs (sock->spm_ambient_interval); + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&spm_ivl, sizeof(spm_ivl) ); + } + break; + +/* TODO: IHB_MIN */ + case COLUMN_PGMSOURCESPMHEARTBEATIVLMIN: + { + const unsigned ihb_min = 0; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&ihb_min, sizeof(ihb_min) ); + } + break; + +/* TODO: IHB_MAX */ + case COLUMN_PGMSOURCESPMHEARTBEATIVLMAX: + { + const unsigned ihb_max = 0; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&ihb_max, sizeof(ihb_max) ); + } + break; + +/* NAK_BO_IVL */ + case COLUMN_PGMSOURCERDATABACKOFFIVL: + { + const unsigned nak_bo_ivl = pgm_to_msecs (sock->nak_bo_ivl); + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&nak_bo_ivl, sizeof(nak_bo_ivl) ); + } + break; + +/* FIXED: pgmSourceFEC = disabled(1) */ + case COLUMN_PGMSOURCEFEC: + { + const unsigned fec = (sock->use_ondemand_parity || sock->use_proactive_parity) ? 1 : 0; + snmp_set_var_typed_value (var, ASN_INTEGER, + (const u_char*)&fec, sizeof(fec) ); + } + break; + +/* FIXED: pgmSourceFECTransmissionGrpSize = 0 */ + case COLUMN_PGMSOURCEFECTRANSMISSIONGRPSIZE: + { + const unsigned fec_tgs = sock->rs_k; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&fec_tgs, sizeof(fec_tgs) ); + } + break; + +/* FIXED: pgmSourceFECProactiveParitySize = 0 */ + case COLUMN_PGMSOURCEFECPROACTIVEPARITYSIZE: + { + const unsigned fec_paps = sock->rs_proactive_h; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&fec_paps, sizeof(fec_paps) ); + } + break; + +/* IPv6 not supported */ + case COLUMN_PGMSOURCESPMPATHADDRESS: + { + struct sockaddr_in s4; + if (AF_INET == sock->recv_gsr[0].gsr_source.ss_family) + memcpy (&s4, &sock->recv_gsr[0].gsr_source, sizeof(s4)); + else + memset (&s4, 0, sizeof(s4)); + snmp_set_var_typed_value (var, ASN_IPADDRESS, + (const u_char*)&s4.sin_addr.s_addr, + sizeof(struct in_addr) ); + } + break; + + default: + snmp_log (LOG_ERR, "pgmSourceConfigTable_handler: unknown column.\n"); + break; + } + } + break; + + case MODE_SET_RESERVE1: + default: + snmp_log (LOG_ERR, "pgmSourceConfigTable_handler: unsupported mode.\n"); + break; + + } + + return SNMP_ERR_NOERROR; +} + +/* + * pgmSourcePerformanceTable + */ + +static +int +initialize_table_pgmSourcePerformanceTable (void) +{ + pgm_debug ("initialize_table_pgmSourcePerformanceTable ()"); + + static const oid pgmSourcePerformanceTable_oid[] = {1,3,6,1,3,112,1,2,100,4}; + netsnmp_table_registration_info* table_info = NULL; + netsnmp_iterator_info* iinfo = NULL; + netsnmp_handler_registration* reg = NULL; + + reg = netsnmp_create_handler_registration ("pgmSourcePerformanceTable", pgmSourcePerformanceTable_handler, + pgmSourcePerformanceTable_oid, OID_LENGTH( pgmSourcePerformanceTable_oid ), + HANDLER_CAN_RONLY); + if (!reg) + goto error; + + table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); + if (!table_info) + goto error; + + table_info->min_column = COLUMN_PGMSOURCEDATABYTESSENT; + table_info->max_column = COLUMN_PGMSOURCENNAKERRORS; + + netsnmp_table_helper_add_indexes (table_info, + ASN_OCTET_STR, /* index: pgmSourceGlobalId */ + ASN_UNSIGNED, /* index: pgmSourceSourcePort */ + 0); + + iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); + if (!iinfo) + goto error; + + iinfo->get_first_data_point = pgmSourcePerformanceTable_get_first_data_point; + iinfo->get_next_data_point = pgmSourcePerformanceTable_get_next_data_point; + iinfo->free_loop_context_at_end = pgmSourcePerformanceTable_free_loop_context; + iinfo->table_reginfo = table_info; + + return netsnmp_register_table_iterator (reg, iinfo); + +error: + if (table_info && table_info->indexes) /* table_data_free_func() is internal */ + snmp_free_var (table_info->indexes); + SNMP_FREE( table_info ); + SNMP_FREE( iinfo ); + netsnmp_handler_registration_free (reg); + + return -1; +} + +/* called for first row of data in SNMP table + * + * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, + * optionally returns my_data_context. + * + * returns answer or NULL + */ + +static +netsnmp_variable_list* +pgmSourcePerformanceTable_get_first_data_point ( + void** my_loop_context, /* valid through one query of multiple "data points" */ + void** my_data_context, /* answer blob which is passed to handler() */ + netsnmp_variable_list* put_index_data, /* answer */ + netsnmp_iterator_info* mydata /* iinfo on init() */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmSourcePerformanceTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_rwlock_reader_lock (&pgm_sock_list_lock); + + if (!pgm_sock_list) { + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + return NULL; + } + +/* create our own context for this SNMP loop */ + pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); + context->list = pgm_sock_list; + *my_loop_context = context; + +/* pass on for generic row access */ + return pgmSourcePerformanceTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); +} + +static +netsnmp_variable_list* +pgmSourcePerformanceTable_get_next_data_point ( + void** my_loop_context, + void** my_data_context, + netsnmp_variable_list* put_index_data, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmSourcePerformanceTable_get_next_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; + netsnmp_variable_list *idx = put_index_data; + + if (!context->list) + return NULL; + + pgm_sock_t* sock = context->list->data; + +/* pgmSourceGlobalId */ + char gsi[ PGM_GSISTRLEN ]; + pgm_gsi_print_r (&sock->tsi.gsi, gsi, sizeof(gsi)); + snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); + idx = idx->next_variable; + +/* pgmSourceSourcePort */ + const unsigned sport = ntohs (sock->tsi.sport); + snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); + + *my_data_context = sock; + context->list = context->list->next; + + return put_index_data; +} + +static +void +pgmSourcePerformanceTable_free_loop_context ( + void* my_loop_context, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmPerformanceSourceTable_free_loop_context (my_loop_context:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; + pgm_free (context); + my_loop_context = NULL; + + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); +} + +static +int +pgmSourcePerformanceTable_handler ( + netsnmp_mib_handler* handler, + netsnmp_handler_registration* reginfo, + netsnmp_agent_request_info* reqinfo, + netsnmp_request_info* requests + ) +{ +/* pre-conditions */ + pgm_assert (NULL != handler); + pgm_assert (NULL != reginfo); + pgm_assert (NULL != reqinfo); + pgm_assert (NULL != requests); + + pgm_debug ("pgmSourcePerformanceTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", + (const void*)handler, + (const void*)reginfo, + (const void*)reqinfo, + (const void*)requests); + + switch (reqinfo->mode) { + +/* Read-support (also covers GetNext requests) */ + + case MODE_GET: + for (netsnmp_request_info* request = requests; + request; + request = request->next) + { + const pgm_sock_t* sock = (pgm_sock_t*)netsnmp_extract_iterator_context (request); + + if (!sock) { + netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); + continue; + } + + const pgm_txw_t* window = (const pgm_txw_t*)sock->window; + + netsnmp_variable_list *var = request->requestvb; + netsnmp_table_request_info* table_info = netsnmp_extract_table_info (request); + + if (!table_info) { + snmp_log (LOG_ERR, "pgmSourceTable_handler: empty table request info.\n"); + continue; + } + + switch (table_info->colnum) { + + case COLUMN_PGMSOURCEDATABYTESSENT: + { + const unsigned data_bytes = sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&data_bytes, sizeof(data_bytes) ); + } + break; + + case COLUMN_PGMSOURCEDATAMSGSSENT: + { + const unsigned data_msgs = sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&data_msgs, sizeof(data_msgs) ); + } + break; + + case COLUMN_PGMSOURCEBYTESBUFFERED: + { + const unsigned bytes_buffered = sock->can_send_data ? pgm_txw_size (window) : 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&bytes_buffered, sizeof(bytes_buffered) ); + } + break; + + case COLUMN_PGMSOURCEMSGSBUFFERED: + { + const unsigned msgs_buffered = sock->can_send_data ? pgm_txw_length (window) : 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&msgs_buffered, sizeof(msgs_buffered) ); + } + break; + +/* PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED + COLUMN_PGMSOURCEPARITYBYTESRETRANSMITTED */ + case COLUMN_PGMSOURCEBYTESRETRANSMITTED: + { + const unsigned bytes_resent = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&bytes_resent, sizeof(bytes_resent) ); + } + break; + +/* PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED + COLUMN_PGMSOURCEPARITYMSGSRETRANSMITTED */ + case COLUMN_PGMSOURCEMSGSRETRANSMITTED: + { + const unsigned msgs_resent = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&msgs_resent, sizeof(msgs_resent) ); + } + break; + + case COLUMN_PGMSOURCEBYTESSENT: + { + const unsigned bytes_sent = sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&bytes_sent, sizeof(bytes_sent) ); + } + break; + +/* COLUMN_PGMSOURCEPARITYNAKPACKETSRECEIVED + COLUMN_PGMSOURCESELECTIVENAKPACKETSRECEIVED */ + case COLUMN_PGMSOURCERAWNAKSRECEIVED: + { + const unsigned nak_packets = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&nak_packets, sizeof(nak_packets) ); + } + break; + +/* PGM_PC_SOURCE_SELECTIVE_NAKS_IGNORED + COLUMN_PGMSOURCEPARITYNAKSIGNORED */ + case COLUMN_PGMSOURCENAKSIGNORED: + { + const unsigned naks_ignored = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_IGNORED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&naks_ignored, sizeof(naks_ignored) ); + } + break; + + case COLUMN_PGMSOURCECKSUMERRORS: + { + const unsigned cksum_errors = sock->cumulative_stats[PGM_PC_SOURCE_CKSUM_ERRORS]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&cksum_errors, sizeof(cksum_errors) ); + } + break; + + case COLUMN_PGMSOURCEMALFORMEDNAKS: + { + const unsigned malformed_naks = sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&malformed_naks, sizeof(malformed_naks) ); + } + break; + + case COLUMN_PGMSOURCEPACKETSDISCARDED: + { + const unsigned packets_discarded = sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&packets_discarded, sizeof(packets_discarded) ); + } + break; + +/* PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED + COLUMN_PGMSOURCEPARITYNAKSRECEIVED */ + case COLUMN_PGMSOURCENAKSRCVD: + { + const unsigned naks_received = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&naks_received, sizeof(naks_received) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMSOURCEPARITYBYTESRETRANSMITTED: + { + const unsigned parity_bytes_resent = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&parity_bytes_resent, sizeof(parity_bytes_resent) ); + } + break; + + case COLUMN_PGMSOURCESELECTIVEBYTESRETRANSMITED: + { + const unsigned selective_bytes_resent = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&selective_bytes_resent, sizeof(selective_bytes_resent) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMSOURCEPARITYMSGSRETRANSMITTED: + { + const unsigned parity_msgs_resent = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&parity_msgs_resent, sizeof(parity_msgs_resent) ); + } + break; + + case COLUMN_PGMSOURCESELECTIVEMSGSRETRANSMITTED: + { + const unsigned selective_msgs_resent = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&selective_msgs_resent, sizeof(selective_msgs_resent) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMSOURCEBYTESADMIT: + { + const unsigned bytes_admit = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&bytes_admit, sizeof(bytes_admit) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMSOURCEMSGSADMIT: + { + const unsigned msgs_admit = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&msgs_admit, sizeof(msgs_admit) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMSOURCEPARITYNAKPACKETSRECEIVED: + { + const unsigned parity_nak_packets = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&parity_nak_packets, sizeof(parity_nak_packets) ); + } + break; + + case COLUMN_PGMSOURCESELECTIVENAKPACKETSRECEIVED: + { + const unsigned selective_nak_packets = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&selective_nak_packets, sizeof(selective_nak_packets) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMSOURCEPARITYNAKSRECEIVED: + { + const unsigned parity_naks = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&parity_naks, sizeof(parity_naks) ); + } + break; + + case COLUMN_PGMSOURCESELECTIVENAKSRECEIVED: + { + const unsigned selective_naks = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&selective_naks, sizeof(selective_naks) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMSOURCEPARITYNAKSIGNORED: + { + const unsigned parity_naks_ignored = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&parity_naks_ignored, sizeof(parity_naks_ignored) ); + } + break; + + case COLUMN_PGMSOURCESELECTIVENAKSIGNORED: + { + const unsigned selective_naks_ignored = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_IGNORED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&selective_naks_ignored, sizeof(selective_naks_ignored) ); + } + break; + + case COLUMN_PGMSOURCEACKERRORS: + { + const unsigned ack_errors = sock->cumulative_stats[PGM_PC_SOURCE_ACK_ERRORS];; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&ack_errors, sizeof(ack_errors) ); + } + break; + + case COLUMN_PGMSOURCEPGMCCACKER: + { + struct sockaddr_in s4; + if (AF_INET == sock->acker_nla.ss_family) + memcpy (&s4, &sock->acker_nla, sizeof(s4)); + else + memset (&s4, 0, sizeof(s4)); + snmp_set_var_typed_value (var, ASN_IPADDRESS, + (const u_char*)&s4.sin_addr.s_addr, + sizeof(struct in_addr) ); + } + break; + + case COLUMN_PGMSOURCETRANSMISSIONCURRENTRATE: + { + const unsigned tx_current_rate = sock->cumulative_stats[PGM_PC_SOURCE_TRANSMISSION_CURRENT_RATE]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&tx_current_rate, sizeof(tx_current_rate) ); + } + break; + + case COLUMN_PGMSOURCEACKPACKETSRECEIVED: + { + const unsigned ack_packets = sock->cumulative_stats[PGM_PC_SOURCE_ACK_PACKETS_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&ack_packets, sizeof(ack_packets) ); + } + break; + +/* COLUMN_PGMSOURCEPARITYNNAKPACKETSRECEIVED + COLUMN_PGMSOURCESELECTIVENNAKPACKETSRECEIVED */ + case COLUMN_PGMSOURCENNAKPACKETSRECEIVED: + { + const unsigned nnak_packets = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&nnak_packets, sizeof(nnak_packets) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMSOURCEPARITYNNAKPACKETSRECEIVED: + { + const unsigned parity_nnak_packets = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&parity_nnak_packets, sizeof(parity_nnak_packets) ); + } + break; + + case COLUMN_PGMSOURCESELECTIVENNAKPACKETSRECEIVED: + { + const unsigned selective_nnak_packets = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&selective_nnak_packets, sizeof(selective_nnak_packets) ); + } + break; + +/* COLUMN_PGMSOURCEPARITYNNAKSRECEIVED + COLUMN_PGMSOURCESELECTIVENNAKSRECEIVED */ + case COLUMN_PGMSOURCENNAKSRECEIVED: + { + const unsigned nnaks_received = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&nnaks_received, sizeof(nnaks_received) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMSOURCEPARITYNNAKSRECEIVED: + { + const unsigned parity_nnaks = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&parity_nnaks, sizeof(parity_nnaks) ); + } + break; + + case COLUMN_PGMSOURCESELECTIVENNAKSRECEIVED: + { + const unsigned selective_nnaks = sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&selective_nnaks, sizeof(selective_nnaks) ); + } + break; + + case COLUMN_PGMSOURCENNAKERRORS: + { + const unsigned malformed_nnaks = sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&malformed_nnaks, sizeof(malformed_nnaks) ); + } + break; + + default: + snmp_log (LOG_ERR, "pgmSourcePerformanceTable_handler: unknown column.\n"); + break; + } + } + break; + + case MODE_SET_RESERVE1: + default: + snmp_log (LOG_ERR, "pgmSourcePerformanceTable_handler: unsupported mode.\n"); + break; + + } + + return SNMP_ERR_NOERROR; +} + +/* + * pgmReceiverTable + */ + +static +int +initialize_table_pgmReceiverTable(void) +{ + pgm_debug ("initialize_table_pgmReceiverTable ()"); + + static const oid pgmReceiverTable_oid[] = {1,3,6,1,3,112,1,3,100,2}; + netsnmp_table_registration_info* table_info = NULL; + netsnmp_iterator_info* iinfo = NULL; + netsnmp_handler_registration* reg = NULL; + + reg = netsnmp_create_handler_registration ("pgmReceiverTable", pgmReceiverTable_handler, + pgmReceiverTable_oid, OID_LENGTH( pgmReceiverTable_oid ), + HANDLER_CAN_RONLY); + if (!reg) + goto error; + + table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); + if (!table_info) + goto error; + + table_info->min_column = COLUMN_PGMRECEIVERGROUPADDRESS; + table_info->max_column = COLUMN_PGMRECEIVERUNIQUEINSTANCE; + + netsnmp_table_helper_add_indexes (table_info, + ASN_OCTET_STR, /* index: pgmReceiverGlobalId */ + ASN_UNSIGNED, /* index: pgmReceiverSourcePort */ + ASN_UNSIGNED, /* index: pgmReceiverInstance */ + 0); + + iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); + if (!iinfo) + goto error; + + iinfo->get_first_data_point = pgmReceiverTable_get_first_data_point; + iinfo->get_next_data_point = pgmReceiverTable_get_next_data_point; + iinfo->free_loop_context_at_end = pgmReceiverTable_free_loop_context; + iinfo->table_reginfo = table_info; + + return netsnmp_register_table_iterator (reg, iinfo); + +error: + if (table_info && table_info->indexes) /* table_data_free_func() is internal */ + snmp_free_var (table_info->indexes); + SNMP_FREE( table_info ); + SNMP_FREE( iinfo ); + netsnmp_handler_registration_free (reg); + + return -1; +} + +/* called for first row of data in SNMP table + * + * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, + * optionally returns my_data_context. + * + * returns answer or NULL + */ + +static +netsnmp_variable_list* +pgmReceiverTable_get_first_data_point ( + void** my_loop_context, /* valid through one query of multiple "data points" */ + void** my_data_context, /* answer blob which is passed to handler() */ + netsnmp_variable_list* put_index_data, /* answer */ + netsnmp_iterator_info* mydata /* iinfo on init() */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmReceiverTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_rwlock_reader_lock (&pgm_sock_list_lock); + + if (!pgm_sock_list) { + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + return NULL; + } + +/* create our own context for this SNMP loop */ + pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); + +/* hunt to find first node, through all socks */ + for (context->list = pgm_sock_list; + context->list; + context->list = context->list->next) + { +/* and through all peers for each sock */ + pgm_sock_t* sock = (pgm_sock_t*)context->list->data; + pgm_rwlock_reader_lock (&sock->peers_lock); + context->node = sock->peers_list; + if (context->node) { +/* maintain this sock's peers lock */ + break; + } + + pgm_rwlock_reader_unlock (&sock->peers_lock); + } + +/* no node found */ + if (!context->node) { + pgm_free (context); + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + return NULL; + } + + *my_loop_context = context; + +/* pass on for generic row access */ + return pgmReceiverTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); +} + +static +netsnmp_variable_list* +pgmReceiverTable_get_next_data_point ( + void** my_loop_context, + void** my_data_context, + netsnmp_variable_list* put_index_data, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmReceiverTable_get_next_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; + netsnmp_variable_list *idx = put_index_data; + + if (!context->list) + return NULL; + + pgm_sock_t* sock = context->list->data; + + if (!context->node) + return NULL; + + pgm_peer_t* peer = context->node->data; + +/* pgmReceiverGlobalId */ + char gsi[ PGM_GSISTRLEN ]; + pgm_gsi_print_r (&peer->tsi.gsi, gsi, sizeof(gsi)); + snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); + idx = idx->next_variable; + +/* pgmReceiverSourcePort */ + const unsigned sport = ntohs (peer->tsi.sport); + snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); + idx = idx->next_variable; + +/* pgmReceiverInstance */ + const unsigned instance = context->instance++; + snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&instance, sizeof(instance)); + +/* set data context to pass to handler callback */ + *my_data_context = peer; + +/* hunt for next valid node */ + if (context->node->next) { + context->node = context->node->next; + } else { + context->node = NULL; + while (context->list->next) + { + pgm_rwlock_reader_unlock (&sock->peers_lock); + context->list = context->list->next; + sock = context->list->data; + pgm_rwlock_reader_lock (&sock->peers_lock); + context->node = sock->peers_list; + if (context->node) { +/* keep lock */ + break; + } + } + } + + return put_index_data; +} + +static +void +pgmReceiverTable_free_loop_context ( + void* my_loop_context, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmReceiverTable_free_loop_context (my_loop_context:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; + +/* check for intra-peer state */ + if (context->list) { + pgm_sock_t* sock = context->list->data; + pgm_rwlock_reader_unlock (&sock->peers_lock); + } + + pgm_free (context); + my_loop_context = NULL; + + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); +} + +static +int +pgmReceiverTable_handler ( + netsnmp_mib_handler* handler, + netsnmp_handler_registration* reginfo, + netsnmp_agent_request_info* reqinfo, + netsnmp_request_info* requests + ) +{ +/* pre-conditions */ + pgm_assert (NULL != handler); + pgm_assert (NULL != reginfo); + pgm_assert (NULL != reqinfo); + pgm_assert (NULL != requests); + + pgm_debug ("pgmReceiverTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", + (const void*)handler, + (const void*)reginfo, + (const void*)reqinfo, + (const void*)requests); + + switch (reqinfo->mode) { + +/* Read-support (also covers GetNext requests) */ + + case MODE_GET: + for (netsnmp_request_info* request = requests; + request; + request = request->next) + { + const pgm_peer_t* peer = (pgm_peer_t*)netsnmp_extract_iterator_context (request); + + if (!peer) { + netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); + continue; + } + + netsnmp_variable_list *var = request->requestvb; + netsnmp_table_request_info* table_info = netsnmp_extract_table_info(request); + + if (table_info == NULL) { + snmp_log (LOG_ERR, "pgmReceiverTable_handler: empty table request info.\n"); + continue; + } + + switch (table_info->colnum) { + + case COLUMN_PGMRECEIVERGROUPADDRESS: + { + struct sockaddr_in s4; + if (AF_INET == peer->group_nla.ss_family) + memcpy (&s4, &peer->group_nla, sizeof(s4)); + else + memset (&s4, 0, sizeof(s4)); + snmp_set_var_typed_value (var, ASN_IPADDRESS, + (const u_char*)&s4.sin_addr.s_addr, + sizeof(struct in_addr) ); + } + break; + +/* by definition same as sock */ + case COLUMN_PGMRECEIVERDESTPORT: + { + const unsigned dport = ntohs (peer->sock->dport); + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&dport, sizeof(dport) ); + } + break; + + case COLUMN_PGMRECEIVERSOURCEADDRESS: + { + struct sockaddr_in s4; + if (AF_INET == peer->nla.ss_family) + memcpy (&s4, &peer->nla, sizeof(s4)); + else + memset (&s4, 0, sizeof(s4)); + snmp_set_var_typed_value (var, ASN_IPADDRESS, + (const u_char*)&s4.sin_addr.s_addr, + sizeof(struct in_addr) ); + } + break; + + case COLUMN_PGMRECEIVERLASTHOP: + { + struct sockaddr_in s4; + if (AF_INET == peer->local_nla.ss_family) + memcpy (&s4, &peer->local_nla, sizeof(s4)); + else + memset (&s4, 0, sizeof(s4)); + snmp_set_var_typed_value (var, ASN_IPADDRESS, + (const u_char*)&s4.sin_addr.s_addr, + sizeof(struct in_addr) ); + } + break; + +/* copy index[0] */ + case COLUMN_PGMRECEIVERSOURCEGSI: + snmp_set_var_typed_value (var, ASN_OCTET_STR, + (const u_char*)table_info->indexes->val.string, + table_info->indexes->val_len); + break; + +/* copy index[1] */ + case COLUMN_PGMRECEIVERSOURCEPORTNUMBER: + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)table_info->indexes->next_variable->val.integer, + table_info->indexes->next_variable->val_len); + break; + +/* copy index[2] */ + case COLUMN_PGMRECEIVERUNIQUEINSTANCE: + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)table_info->indexes->next_variable->next_variable->val.integer, + table_info->indexes->next_variable->next_variable->val_len); + break; + + default: + snmp_log (LOG_ERR, "pgmReceiverTable_handler: unknown column.\n"); + break; + } + } + break; + + case MODE_SET_RESERVE1: + default: + snmp_log (LOG_ERR, "pgmReceiverTable_handler: unsupported mode.\n"); + break; + + } + + return SNMP_ERR_NOERROR; +} + +/* + * pgmReceiverConfigTable + * + */ + +static +int +initialize_table_pgmReceiverConfigTable(void) +{ + pgm_debug ("initialize_table_pgmReceiverConfigTable ()"); + + static const oid pgmReceiverConfigTable_oid[] = {1,3,6,1,3,112,1,3,100,3}; + netsnmp_table_registration_info* table_info = NULL; + netsnmp_iterator_info* iinfo = NULL; + netsnmp_handler_registration* reg = NULL; + + reg = netsnmp_create_handler_registration ("pgmReceiverConfigTable", pgmReceiverConfigTable_handler, + pgmReceiverConfigTable_oid, OID_LENGTH(pgmReceiverConfigTable_oid), + HANDLER_CAN_RONLY); + if (!reg) + goto error; + + table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); + if (!table_info) + goto error; + + table_info->min_column = COLUMN_PGMRECEIVERNAKBACKOFFIVL; + table_info->max_column = COLUMN_PGMRECEIVERNAKFAILURETHRESHOLD; + + netsnmp_table_helper_add_indexes (table_info, + ASN_OCTET_STR, /* index: pgmReceiverConfigGlobalId */ + ASN_UNSIGNED, /* index: pgmReceiverConfigSourcePort */ + ASN_UNSIGNED, /* index: pgmReceiverInstance */ + 0); + + iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); + if (!iinfo) + goto error; + + iinfo->get_first_data_point = pgmReceiverConfigTable_get_first_data_point; + iinfo->get_next_data_point = pgmReceiverConfigTable_get_next_data_point; + iinfo->free_loop_context_at_end = pgmReceiverConfigTable_free_loop_context; + iinfo->table_reginfo = table_info; + + return netsnmp_register_table_iterator (reg, iinfo); + +error: + if (table_info && table_info->indexes) /* table_data_free_func() is internal */ + snmp_free_var (table_info->indexes); + SNMP_FREE( table_info ); + SNMP_FREE( iinfo ); + netsnmp_handler_registration_free (reg); + + return -1; +} + +/* called for first row of data in SNMP table + * + * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, + * optionally returns my_data_context. + * + * returns answer or NULL + */ + +static +netsnmp_variable_list* +pgmReceiverConfigTable_get_first_data_point( + void** my_loop_context, /* valid through one query of multiple "data points" */ + void** my_data_context, /* answer blob which is passed to handler() */ + netsnmp_variable_list* put_index_data, /* answer */ + netsnmp_iterator_info* mydata /* iinfo on init() */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmReceiverConfigTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_rwlock_reader_lock (&pgm_sock_list_lock); + + if (!pgm_sock_list) { + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + return NULL; + } + +/* create our own context for this SNMP loop */ + pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); + +/* hunt to find first node, through all socks */ + for (context->list = pgm_sock_list; + context->list; + context->list = context->list->next) + { +/* and through all peers for each sock */ + pgm_sock_t* sock = (pgm_sock_t*)context->list->data; + pgm_rwlock_reader_lock (&sock->peers_lock); + context->node = sock->peers_list; + if (context->node) + break; + + pgm_rwlock_reader_unlock (&sock->peers_lock); + } + +/* no node found */ + if (!context->node) { + pgm_free (context); + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + return NULL; + } + + *my_loop_context = context; + +/* pass on for generic row access */ + return pgmReceiverConfigTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); +} + +static +netsnmp_variable_list* +pgmReceiverConfigTable_get_next_data_point( + void** my_loop_context, + void** my_data_context, + netsnmp_variable_list* put_index_data, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmReceiverConfigTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; + netsnmp_variable_list *idx = put_index_data; + + if (!context->list) + return NULL; + + pgm_sock_t* sock = context->list->data; + + if (!context->node) + return NULL; + + pgm_peer_t* peer = context->node->data; + +/* pgmReceiverGlobalId */ + char gsi[ PGM_GSISTRLEN ]; + pgm_gsi_print_r (&peer->tsi.gsi, gsi, sizeof(gsi)); + snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); + idx = idx->next_variable; + +/* pgmReceiverSourcePort */ + const unsigned sport = ntohs (peer->tsi.sport); + snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); + idx = idx->next_variable; + +/* pgmReceiverInstance */ + const unsigned instance = context->instance++; + snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&instance, sizeof(instance)); + +/* set data context to pass to handler callback */ + *my_data_context = peer; + +/* hunt for next valid node */ + if (context->node->next) { + context->node = context->node->next; + } else { + context->node = NULL; + while (context->list->next) + { + pgm_rwlock_reader_unlock (&sock->peers_lock); + context->list = context->list->next; + sock = context->list->data; + pgm_rwlock_reader_lock (&sock->peers_lock); + context->node = sock->peers_list; + if (context->node) { +/* keep lock */ + break; + } + } + } + + return put_index_data; +} + +static +void +pgmReceiverConfigTable_free_loop_context ( + void* my_loop_context, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmReceiverConfigTable_free_loop_context (my_loop_context:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; + +/* check for intra-peer state */ + if (context->list) { + pgm_sock_t* sock = context->list->data; + pgm_rwlock_reader_unlock (&sock->peers_lock); + } + + pgm_free (context); + my_loop_context = NULL; + + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); +} + +static +int +pgmReceiverConfigTable_handler ( + netsnmp_mib_handler* handler, + netsnmp_handler_registration* reginfo, + netsnmp_agent_request_info* reqinfo, + netsnmp_request_info* requests + ) +{ +/* pre-conditions */ + pgm_assert (NULL != handler); + pgm_assert (NULL != reginfo); + pgm_assert (NULL != reqinfo); + pgm_assert (NULL != requests); + + pgm_debug ("pgmReceiverConfigTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", + (const void*)handler, + (const void*)reginfo, + (const void*)reqinfo, + (const void*)requests); + + switch (reqinfo->mode) { + +/* Read-support (also covers GetNext requests) */ + + case MODE_GET: + for (netsnmp_request_info* request = requests; + request; + request = request->next) + { + const pgm_peer_t* peer = (pgm_peer_t*)netsnmp_extract_iterator_context(request); + + if (peer == NULL) { + netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); + continue; + } + + netsnmp_variable_list *var = request->requestvb; + netsnmp_table_request_info* table_info = netsnmp_extract_table_info(request); + + if (table_info == NULL) { + snmp_log (LOG_ERR, "pgmReceiverTable_handler: empty table request info.\n"); + continue; + } + + switch (table_info->colnum) { + +/* nak_bo_ivl from sock */ + case COLUMN_PGMRECEIVERNAKBACKOFFIVL: + { + const unsigned nak_bo_ivl = peer->sock->nak_bo_ivl; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&nak_bo_ivl, sizeof(nak_bo_ivl) ); + } + break; + +/* nak_rpt_ivl from sock */ + case COLUMN_PGMRECEIVERNAKREPEATIVL: + { + const unsigned nak_rpt_ivl = peer->sock->nak_rpt_ivl; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&nak_rpt_ivl, sizeof(nak_rpt_ivl) ); + } + break; + +/* nak_ncf_retries from sock */ + case COLUMN_PGMRECEIVERNAKNCFRETRIES: + { + const unsigned nak_ncf_retries = peer->sock->nak_ncf_retries; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&nak_ncf_retries, sizeof(nak_ncf_retries) ); + } + break; + +/* nak_rdata_ivl from sock */ + case COLUMN_PGMRECEIVERNAKRDATAIVL: + { + const unsigned nak_rdata_ivl = peer->sock->nak_rdata_ivl; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&nak_rdata_ivl, sizeof(nak_rdata_ivl) ); + } + break; + +/* nak_data_retries from sock */ + case COLUMN_PGMRECEIVERNAKDATARETRIES: + { + const unsigned nak_data_retries = peer->sock->nak_data_retries; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&nak_data_retries, sizeof(nak_data_retries) ); + } + break; + +/* FIXED: pgmReceiverSendNaks = enabled(1) */ + case COLUMN_PGMRECEIVERSENDNAKS: + { + const unsigned send_naks = PGMRECEIVERSENDNAKS_ENABLED; + snmp_set_var_typed_value (var, ASN_INTEGER, + (const u_char*)&send_naks, sizeof(send_naks) ); + } + break; + +/* FIXED: pgmReceiverLateJoin = disabled(2) */ + case COLUMN_PGMRECEIVERLATEJOIN: + { + const unsigned late_join = PGMRECEIVERLATEJOIN_DISABLED; + snmp_set_var_typed_value (var, ASN_INTEGER, + (const u_char*)&late_join, sizeof(late_join) ); + } + break; + +/* FIXED: 1 for multicast */ + case COLUMN_PGMRECEIVERNAKTTL: + { + const unsigned nak_hops = 1; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&nak_hops, sizeof(nak_hops) ); + } + break; + +/* FIXED: pgmReceiverDeliveryOrder = ordered(2) */ + case COLUMN_PGMRECEIVERDELIVERYORDER: + { + const unsigned delivery_order = PGMRECEIVERDELIVERYORDER_ORDERED; + snmp_set_var_typed_value (var, ASN_INTEGER, + (const u_char*)&delivery_order, sizeof(delivery_order) ); + } + break; + +/* FIXED: pgmReceiverMcastNaks = disabled(2) */ + case COLUMN_PGMRECEIVERMCASTNAKS: + { + const unsigned mcast_naks = PGMRECEIVERMCASTNAKS_DISABLED; + snmp_set_var_typed_value (var, ASN_INTEGER, + (const u_char*)&mcast_naks, sizeof(mcast_naks) ); + } + break; + +/* TODO: traps */ + case COLUMN_PGMRECEIVERNAKFAILURETHRESHOLDTIMER: + case COLUMN_PGMRECEIVERNAKFAILURETHRESHOLD: + { + const unsigned threshold = 0; + snmp_set_var_typed_value (var, ASN_UNSIGNED, + (const u_char*)&threshold, sizeof(threshold) ); + } + break; + + default: + snmp_log (LOG_ERR, "pgmReceiverTable_handler: unknown column.\n"); + break; + } + } + break; + + case MODE_SET_RESERVE1: + default: + snmp_log (LOG_ERR, "pgmReceiverTable_handler: unsupported mode.\n"); + break; + + } + + return SNMP_ERR_NOERROR; +} + +/* + * pgmReceiverPerformanceTable + */ + +static +int +initialize_table_pgmReceiverPerformanceTable (void) +{ + pgm_debug ("initialize_table_pgmReceiverPerformanceTable ()"); + + static const oid pgmReceiverPerformanceTable_oid[] = {1,3,6,1,3,112,1,3,100,4}; + netsnmp_table_registration_info* table_info = NULL; + netsnmp_iterator_info* iinfo = NULL; + netsnmp_handler_registration* reg = NULL; + + reg = netsnmp_create_handler_registration ("pgmReceiverPerformanceTable", pgmReceiverPerformanceTable_handler, + pgmReceiverPerformanceTable_oid, OID_LENGTH( pgmReceiverPerformanceTable_oid ), + HANDLER_CAN_RONLY); + if (!reg) + goto error; + + table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); + if (!table_info) + goto error; + + table_info->min_column = COLUMN_PGMRECEIVERDATABYTESRECEIVED; + table_info->max_column = COLUMN_PGMRECEIVERLASTINTERVALNAKFAILURES; + + netsnmp_table_helper_add_indexes (table_info, + ASN_OCTET_STR, /* index: pgmReceiverGlobalId */ + ASN_UNSIGNED, /* index: pgmReceiverSourcePort */ + ASN_UNSIGNED, /* index: pgmReceiverInstance */ + 0); + + iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); + if (!iinfo) + goto error; + + iinfo->get_first_data_point = pgmReceiverPerformanceTable_get_first_data_point; + iinfo->get_next_data_point = pgmReceiverPerformanceTable_get_next_data_point; + iinfo->free_loop_context_at_end = pgmReceiverPerformanceTable_free_loop_context; + iinfo->table_reginfo = table_info; + + return netsnmp_register_table_iterator (reg, iinfo); + +error: + if (table_info && table_info->indexes) /* table_data_free_func() is internal */ + snmp_free_var (table_info->indexes); + SNMP_FREE( table_info ); + SNMP_FREE( iinfo ); + netsnmp_handler_registration_free (reg); + + return -1; +} + +/* called for first row of data in SNMP table + * + * goal is to cache all the relevant data for subsequent get_next_data_point (row) calls in my_loop_context, + * optionally returns my_data_context. + * + * returns answer or NULL + */ + +static +netsnmp_variable_list* +pgmReceiverPerformanceTable_get_first_data_point ( + void** my_loop_context, /* valid through one query of multiple "data points" */ + void** my_data_context, /* answer blob which is passed to handler() */ + netsnmp_variable_list* put_index_data, /* answer */ + netsnmp_iterator_info* mydata /* iinfo on init() */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmReceiverPerformanceTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_rwlock_reader_lock (&pgm_sock_list_lock); + + if (!pgm_sock_list) { + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + return NULL; + } + +/* create our own context for this SNMP loop */ + pgm_snmp_context_t* context = pgm_new0 (pgm_snmp_context_t, 1); + +/* hunt to find first node, through all socks */ + for (context->list = pgm_sock_list; + context->list; + context->list = context->list->next) + { +/* and through all peers for each sock */ + pgm_sock_t* sock = (pgm_sock_t*)context->list->data; + pgm_rwlock_reader_lock (&sock->peers_lock); + context->node = sock->peers_list; + if (context->node) + break; + + pgm_rwlock_reader_unlock (&sock->peers_lock); + } + +/* no node found */ + if (!context->node) { + pgm_free (context); + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); + return NULL; + } + + *my_loop_context = context; + +/* pass on for generic row access */ + return pgmReceiverPerformanceTable_get_next_data_point (my_loop_context, my_data_context, put_index_data, mydata); +} + +static +netsnmp_variable_list* +pgmReceiverPerformanceTable_get_next_data_point ( + void** my_loop_context, + void** my_data_context, + netsnmp_variable_list* put_index_data, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != my_data_context); + pgm_assert (NULL != put_index_data); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmReceiverPerformanceTable_get_first_data_point (my_loop_context:%p my_data_context:%p put_index_data:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)my_data_context, + (const void*)put_index_data, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)*my_loop_context; + netsnmp_variable_list *idx = put_index_data; + + if (!context->list) + return NULL; + + pgm_sock_t* sock = context->list->data; + + if (!context->node) + return NULL; + + pgm_peer_t* peer = context->node->data; + +/* pgmReceiverGlobalId */ + char gsi[ PGM_GSISTRLEN ]; + pgm_gsi_print_r (&peer->tsi.gsi, gsi, sizeof(gsi)); + snmp_set_var_typed_value (idx, ASN_OCTET_STR, (const u_char*)&gsi, strlen (gsi)); + idx = idx->next_variable; + +/* pgmReceiverSourcePort */ + const unsigned sport = ntohs (peer->tsi.sport); + snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&sport, sizeof(sport)); + idx = idx->next_variable; + +/* pgmReceiverInstance */ + const unsigned instance = context->instance++; + snmp_set_var_typed_value (idx, ASN_UNSIGNED, (const u_char*)&instance, sizeof(instance)); + +/* set data context to pass to handler callback */ + *my_data_context = peer; + +/* hunt for next valid node */ + if (context->node->next) { + context->node = context->node->next; + } else { + context->node = NULL; + while (context->list->next) + { + pgm_rwlock_reader_unlock (&sock->peers_lock); + context->list = context->list->next; + sock = context->list->data; + pgm_rwlock_reader_lock (&sock->peers_lock); + context->node = sock->peers_list; + + if (context->node) + break; + } + } + + return put_index_data; +} + +static +void +pgmReceiverPerformanceTable_free_loop_context ( + void* my_loop_context, + netsnmp_iterator_info* mydata + ) +{ +/* pre-conditions */ + pgm_assert (NULL != my_loop_context); + pgm_assert (NULL != mydata); + + pgm_debug ("pgmReceiverPerformanceTable_free_loop_context (my_loop_context:%p mydata:%p)", + (const void*)my_loop_context, + (const void*)mydata); + + pgm_snmp_context_t* context = (pgm_snmp_context_t*)my_loop_context; + +/* check for intra-peer state */ + if (context->list) { + pgm_sock_t* sock = context->list->data; + pgm_rwlock_reader_unlock (&sock->peers_lock); + } + + pgm_free (context); + my_loop_context = NULL; + + pgm_rwlock_reader_unlock (&pgm_sock_list_lock); +} + +static +int +pgmReceiverPerformanceTable_handler ( + netsnmp_mib_handler* handler, + netsnmp_handler_registration* reginfo, + netsnmp_agent_request_info* reqinfo, + netsnmp_request_info* requests + ) +{ +/* pre-conditions */ + pgm_assert (NULL != handler); + pgm_assert (NULL != reginfo); + pgm_assert (NULL != reqinfo); + pgm_assert (NULL != requests); + + pgm_debug ("pgmReceiverPerformanceTable_handler (handler:%p reginfo:%p reqinfo:%p requests:%p)", + (const void*)handler, + (const void*)reginfo, + (const void*)reqinfo, + (const void*)requests); + + switch (reqinfo->mode) { + +/* Read-support (also covers GetNext requests) */ + + case MODE_GET: + for (netsnmp_request_info* request = requests; + request; + request = request->next) + { + const pgm_peer_t* peer = (pgm_peer_t*)netsnmp_extract_iterator_context (request); + + if (!peer) { + netsnmp_set_request_error (reqinfo, request, SNMP_NOSUCHINSTANCE); + continue; + } + + const pgm_rxw_t* window = (const pgm_rxw_t*)peer->window; + + netsnmp_variable_list *var = request->requestvb; + netsnmp_table_request_info* table_info = netsnmp_extract_table_info (request); + + if (!table_info) { + snmp_log (LOG_ERR, "pgmReceiverTable_handler: empty table request info.\n"); + continue; + } + + switch (table_info->colnum) { + + case COLUMN_PGMRECEIVERDATABYTESRECEIVED: + { + const unsigned data_bytes = peer->cumulative_stats[PGM_PC_RECEIVER_DATA_BYTES_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&data_bytes, sizeof(data_bytes) ); + } + break; + + case COLUMN_PGMRECEIVERDATAMSGSRECEIVED: + { + const unsigned data_msgs = peer->cumulative_stats[PGM_PC_RECEIVER_DATA_MSGS_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&data_msgs, sizeof(data_msgs) ); + } + break; + +/* total */ + case COLUMN_PGMRECEIVERNAKSSENT: + { + const unsigned naks_sent = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&naks_sent, sizeof(naks_sent) ); + } + break; + +/* total */ + case COLUMN_PGMRECEIVERNAKSRETRANSMITTED: + { + const unsigned naks_resent = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_RETRANSMITTED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&naks_resent, sizeof(naks_resent) ); + } + break; + +/* total */ + case COLUMN_PGMRECEIVERNAKFAILURES: + { + const unsigned nak_failures = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_FAILED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&nak_failures, sizeof(nak_failures) ); + } + break; + + case COLUMN_PGMRECEIVERBYTESRECEIVED: + { + const unsigned bytes_received = peer->cumulative_stats[PGM_PC_RECEIVER_BYTES_RECEIVED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&bytes_received, sizeof(bytes_received) ); + } + break; + +/* total */ + case COLUMN_PGMRECEIVERNAKSSUPPRESSED: + { + const unsigned naks_suppressed = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&naks_suppressed, sizeof(naks_suppressed) ); + } + break; + +/* bogus: same as source checksum errors */ + case COLUMN_PGMRECEIVERCKSUMERRORS: + { + const unsigned cksum_errors = peer->sock->cumulative_stats[PGM_PC_SOURCE_CKSUM_ERRORS]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&cksum_errors, sizeof(cksum_errors) ); + } + break; + + case COLUMN_PGMRECEIVERMALFORMEDSPMS: + { + const unsigned malformed_spms = peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&malformed_spms, sizeof(malformed_spms) ); + } + break; + + case COLUMN_PGMRECEIVERMALFORMEDODATA: + { + const unsigned malformed_odata = peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_ODATA]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&malformed_odata, sizeof(malformed_odata) ); + } + break; + + case COLUMN_PGMRECEIVERMALFORMEDRDATA: + { + const unsigned malformed_rdata = peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_RDATA]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&malformed_rdata, sizeof(malformed_rdata) ); + } + break; + + case COLUMN_PGMRECEIVERMALFORMEDNCFS: + { + const unsigned malformed_ncfs = peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&malformed_ncfs, sizeof(malformed_ncfs) ); + } + break; + + case COLUMN_PGMRECEIVERPACKETSDISCARDED: + { + const unsigned packets_discarded = peer->cumulative_stats[PGM_PC_RECEIVER_PACKETS_DISCARDED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&packets_discarded, sizeof(packets_discarded) ); + } + break; + + case COLUMN_PGMRECEIVERLOSSES: + { + const unsigned losses = window->cumulative_losses; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&losses, sizeof(losses) ); + } + break; + + case COLUMN_PGMRECEIVERBYTESDELIVEREDTOAPP: + { + const unsigned bytes_delivered =window->bytes_delivered; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&bytes_delivered, sizeof(bytes_delivered) ); + } + break; + + case COLUMN_PGMRECEIVERMSGSDELIVEREDTOAPP: + { + const unsigned msgs_delivered = window->msgs_delivered; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&msgs_delivered, sizeof(msgs_delivered) ); + } + break; + + case COLUMN_PGMRECEIVERDUPSPMS: + { + const unsigned dup_spms = peer->cumulative_stats[PGM_PC_RECEIVER_DUP_SPMS]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&dup_spms, sizeof(dup_spms) ); + } + break; + + case COLUMN_PGMRECEIVERDUPDATAS: + { + const unsigned dup_data = peer->cumulative_stats[PGM_PC_RECEIVER_DUP_DATAS]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&dup_data, sizeof(dup_data) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMRECEIVERDUPPARITIES: + { + const unsigned dup_parity = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&dup_parity, sizeof(dup_parity) ); + } + break; + +/* COLUMN_PGMRECEIVERPARITYNAKPACKETSSENT + COLUMN_PGMRECEIVERSELECTIVENAKPACKETSSENT */ + case COLUMN_PGMRECEIVERNAKPACKETSSENT: + { + const unsigned nak_packets = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&nak_packets, sizeof(nak_packets) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMRECEIVERPARITYNAKPACKETSSENT: + { + const unsigned parity_naks = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&parity_naks, sizeof(parity_naks) ); + } + break; + + case COLUMN_PGMRECEIVERSELECTIVENAKPACKETSSENT: + { + const unsigned nak_packets = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&nak_packets, sizeof(nak_packets) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMRECEIVERPARITYNAKSSENT: + { + const unsigned parity_naks = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&parity_naks, sizeof(parity_naks) ); + } + break; + + case COLUMN_PGMRECEIVERSELECTIVENAKSSENT: + { + const unsigned naks_sent = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&naks_sent, sizeof(naks_sent) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMRECEIVERPARITYNAKSRETRANSMITTED: + { + const unsigned parity_resent = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&parity_resent, sizeof(parity_resent) ); + } + break; + + case COLUMN_PGMRECEIVERSELECTIVENAKSRETRANSMITTED: + { + const unsigned naks_resent = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_RETRANSMITTED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&naks_resent, sizeof(naks_resent) ); + } + break; + +/* COLUMN_PGMRECEIVERPARITYNAKSFAILED + COLUMN_PGMRECEIVERSELECTIVENAKSFAILED */ + case COLUMN_PGMRECEIVERNAKSFAILED: + { + const unsigned naks_failed = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_FAILED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&naks_failed, sizeof(naks_failed) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMRECEIVERPARITYNAKSFAILED: + { + const unsigned parity_failed = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&parity_failed, sizeof(parity_failed) ); + } + break; + + case COLUMN_PGMRECEIVERSELECTIVENAKSFAILED: + { + const unsigned naks_failed = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_FAILED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&naks_failed, sizeof(naks_failed) ); + } + break; + + case COLUMN_PGMRECEIVERNAKSFAILEDRXWADVANCED: + { + const unsigned rxw_failed = peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_RXW_ADVANCED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&rxw_failed, sizeof(rxw_failed) ); + } + break; + + case COLUMN_PGMRECEIVERNAKSFALEDNCFRETRIESEXCEEDED: + { + const unsigned ncf_retries = peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_NCF_RETRIES_EXCEEDED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&ncf_retries, sizeof(ncf_retries) ); + } + break; + + case COLUMN_PGMRECEIVERNAKSFAILEDDATARETRIESEXCEEDED: + { + const unsigned data_retries = peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_DATA_RETRIES_EXCEEDED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&data_retries, sizeof(data_retries) ); + } + break; + +/* FIXED: 0 - absolutely no idea what this means */ + case COLUMN_PGMRECEIVERNAKSFAILEDGENEXPIRED: + { + const unsigned happy_pandas = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&happy_pandas, sizeof(happy_pandas) ); + } + break; + + case COLUMN_PGMRECEIVERNAKFAILURESDELIVERED: + { + const unsigned delivered = peer->cumulative_stats[PGM_PC_RECEIVER_NAK_FAILURES_DELIVERED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&delivered, sizeof(delivered) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMRECEIVERPARITYNAKSSUPPRESSED: + { + const unsigned suppressed = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&suppressed, sizeof(suppressed) ); + } + break; + + case COLUMN_PGMRECEIVERSELECTIVENAKSSUPPRESSED: + { + const unsigned suppressed = peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&suppressed, sizeof(suppressed) ); + } + break; + + case COLUMN_PGMRECEIVERNAKERRORS: + { + const unsigned malformed_naks = peer->cumulative_stats[PGM_PC_RECEIVER_NAK_ERRORS]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&malformed_naks, sizeof(malformed_naks) ); + } + break; + +/* FIXED: 0 */ + case COLUMN_PGMRECEIVEROUTSTANDINGPARITYNAKS: + { + const unsigned outstanding_parity = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&outstanding_parity, sizeof(outstanding_parity) ); + } + break; + + case COLUMN_PGMRECEIVEROUTSTANDINGSELECTIVENAKS: + { + const unsigned outstanding_selective = window->nak_backoff_queue.length + + window->wait_ncf_queue.length + + window->wait_data_queue.length; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&outstanding_selective, sizeof(outstanding_selective) ); + } + break; + + case COLUMN_PGMRECEIVERLASTACTIVITY: + { + union { + unsigned uint_value; + time_t time_t_value; + } last_activity; + pgm_time_since_epoch (&peer->last_packet, &last_activity.time_t_value); + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&last_activity.uint_value, sizeof(last_activity.uint_value) ); + } + break; + + case COLUMN_PGMRECEIVERNAKSVCTIMEMIN: + { + const unsigned min_repair_time = window->min_fill_time; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&min_repair_time, sizeof(min_repair_time) ); + } + break; + + case COLUMN_PGMRECEIVERNAKSVCTIMEMEAN: + { + const unsigned mean_repair_time = peer->cumulative_stats[PGM_PC_RECEIVER_NAK_SVC_TIME_MEAN]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&mean_repair_time, sizeof(mean_repair_time) ); + } + break; + + case COLUMN_PGMRECEIVERNAKSVCTIMEMAX: + { + const unsigned max_repair_time = window->max_fill_time; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&max_repair_time, sizeof(max_repair_time) ); + } + break; + + case COLUMN_PGMRECEIVERNAKFAILTIMEMIN: + { + const unsigned min_fail_time = peer->min_fail_time; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&min_fail_time, sizeof(min_fail_time) ); + } + break; + + case COLUMN_PGMRECEIVERNAKFAILTIMEMEAN: + { + const unsigned mean_fail_time = peer->cumulative_stats[PGM_PC_RECEIVER_NAK_FAIL_TIME_MEAN]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&mean_fail_time, sizeof(mean_fail_time) ); + } + break; + + case COLUMN_PGMRECEIVERNAKFAILTIMEMAX: + { + const unsigned max_fail_time = peer->max_fail_time; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&max_fail_time, sizeof(max_fail_time) ); + } + break; + + case COLUMN_PGMRECEIVERNAKTRANSMITMIN: + { + const unsigned min_transmit_count = window->min_nak_transmit_count; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&min_transmit_count, sizeof(min_transmit_count) ); + } + break; + + case COLUMN_PGMRECEIVERNAKTRANSMITMEAN: + { + const unsigned mean_transmit_count = peer->cumulative_stats[PGM_PC_RECEIVER_TRANSMIT_MEAN]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&mean_transmit_count, sizeof(mean_transmit_count) ); + } + break; + + case COLUMN_PGMRECEIVERNAKTRANSMITMAX: + { + const unsigned max_transmit_count = window->max_nak_transmit_count; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&max_transmit_count, sizeof(max_transmit_count) ); + } + break; + + case COLUMN_PGMRECEIVERACKSSENT: + { + const unsigned acks_sent = peer->cumulative_stats[PGM_PC_RECEIVER_ACKS_SENT]; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&acks_sent, sizeof(acks_sent) ); + } + break; + + case COLUMN_PGMRECEIVERRXWTRAIL: + { + const unsigned rxw_trail = window->rxw_trail; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&rxw_trail, sizeof(rxw_trail) ); + } + break; + + case COLUMN_PGMRECEIVERRXWLEAD: + { + const unsigned rxw_lead = window->lead; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&rxw_lead, sizeof(rxw_lead) ); + } + break; + +/* TODO: traps */ + case COLUMN_PGMRECEIVERNAKFAILURESLASTINTERVAL: + case COLUMN_PGMRECEIVERLASTINTERVALNAKFAILURES: + { + const unsigned failures = 0; + snmp_set_var_typed_value (var, ASN_COUNTER, /* ASN_COUNTER32 */ + (const u_char*)&failures, sizeof(failures) ); + } + break; + + default: + snmp_log (LOG_ERR, "pgmReceiverTable_handler: unknown column.\n"); + break; + } + } + break; + + case MODE_SET_RESERVE1: + default: + snmp_log (LOG_ERR, "pgmReceiverTable_handler: unsupported mode.\n"); + break; + + } + + return SNMP_ERR_NOERROR; +} + +/* + * SNMP TRAPS + */ + +int +send_pgmStart_trap (void) +{ + pgm_debug ("send_pgmStart_trap ()"); + + netsnmp_variable_list *var_list = NULL; + static const oid pgmStart_oid[] = { 1,3,6,1,3,112,2,0,1 }; + +/* + * Set the snmpTrapOid.0 value + */ + snmp_varlist_add_variable (&var_list, + snmptrap_oid, OID_LENGTH( snmptrap_oid ), + ASN_OBJECT_ID, + (const u_char*)pgmStart_oid, sizeof(pgmStart_oid)); +/* + * Add any extra (optional) objects here + */ + +/* + * Send the trap to the list of configured destinations + * and clean up + */ + send_v2trap (var_list); + snmp_free_varbind (var_list); + return SNMP_ERR_NOERROR; +} + +int +send_pgmStop_trap (void) +{ + pgm_debug ("send_pgmStop_trap ()"); + + netsnmp_variable_list *var_list = NULL; + static const oid pgmStop_oid[] = { 1,3,6,1,3,112,2,0,2 }; + +/* + * Set the snmpTrapOid.0 value + */ + snmp_varlist_add_variable (&var_list, + snmptrap_oid, OID_LENGTH(snmptrap_oid), + ASN_OBJECT_ID, + (const u_char*)pgmStop_oid, sizeof(pgmStop_oid)); + + +/* + * Add any extra (optional) objects here + */ + +/* + * Send the trap to the list of configured destinations + * and clean up + */ + send_v2trap (var_list); + snmp_free_varbind (var_list); + return SNMP_ERR_NOERROR; +} + +int +send_pgmNewSourceTrap_trap (void) +{ + pgm_debug ("send_pgmNewSourceTrap_trap ()"); + + netsnmp_variable_list *var_list = NULL; + static const oid pgmNewSourceTrap_oid[] = { 1,3,6,1,3,112,2,0,3 }; + static const oid pgmSourceSourceGsi_oid[] = { 1,3,6,1,3,112,1,2,100,2,1,6, /* insert index here */ }; + static const oid pgmSourceSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,2,100,2,1,7, /* insert index here */ }; + +/* + * Set the snmpTrapOid.0 value + */ + snmp_varlist_add_variable (&var_list, + snmptrap_oid, OID_LENGTH(snmptrap_oid), + ASN_OBJECT_ID, + (const u_char*)pgmNewSourceTrap_oid, sizeof(pgmNewSourceTrap_oid)); +/* + * Add any objects from the trap definition + */ + snmp_varlist_add_variable (&var_list, + pgmSourceSourceGsi_oid, OID_LENGTH(pgmSourceSourceGsi_oid), + ASN_OCTET_STR, +/* Set an appropriate value for pgmSourceSourceGsi */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmSourceSourcePortNumber_oid, OID_LENGTH(pgmSourceSourcePortNumber_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmSourceSourcePortNumber */ + NULL, 0); +/* + * Add any extra (optional) objects here + */ + +/* + * Send the trap to the list of configured destinations + * and clean up + */ + send_v2trap (var_list); + snmp_free_varbind (var_list); + return SNMP_ERR_NOERROR; +} + +int +send_pgmClosedSourceTrap_trap (void) +{ + pgm_debug ("send_pgmClosedSourceTrap_trap ()"); + + netsnmp_variable_list *var_list = NULL; + static const oid pgmClosedSourceTrap_oid[] = { 1,3,6,1,3,112,2,0,4 }; + static const oid pgmSourceSourceGsi_oid[] = { 1,3,6,1,3,112,1,2,100,2,1,6, /* insert index here */ }; + static const oid pgmSourceSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,2,100,2,1,7, /* insert index here */ }; + +/* + * Set the snmpTrapOid.0 value + */ + snmp_varlist_add_variable (&var_list, + snmptrap_oid, OID_LENGTH(snmptrap_oid), + ASN_OBJECT_ID, + (const u_char*)pgmClosedSourceTrap_oid, sizeof(pgmClosedSourceTrap_oid)); +/* + * Add any objects from the trap definition + */ + snmp_varlist_add_variable (&var_list, + pgmSourceSourceGsi_oid, OID_LENGTH(pgmSourceSourceGsi_oid), + ASN_OCTET_STR, +/* Set an appropriate value for pgmSourceSourceGsi */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmSourceSourcePortNumber_oid, OID_LENGTH(pgmSourceSourcePortNumber_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmSourceSourcePortNumber */ + NULL, 0); +/* + * Add any extra (optional) objects here + */ + +/* + * Send the trap to the list of configured destinations + * and clean up + */ + send_v2trap (var_list); + snmp_free_varbind (var_list); + return SNMP_ERR_NOERROR; +} + +int +send_pgmNewReceiverTrap_trap (void) +{ + pgm_debug ("send_pgmNewReceiverTrap_trap ()"); + + netsnmp_variable_list *var_list = NULL; + static const oid pgmNewReceiverTrap_oid[] = { 1,3,6,1,3,112,2,0,5 }; + static const oid pgmReceiverSourceGsi_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,8, /* insert index here */ }; + static const oid pgmReceiverSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,9, /* insert index here */ }; + static const oid pgmReceiverUniqueInstance_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,10, /* insert index here */ }; + +/* + * Set the snmpTrapOid.0 value + */ + snmp_varlist_add_variable (&var_list, + snmptrap_oid, OID_LENGTH(snmptrap_oid), + ASN_OBJECT_ID, + (const u_char*)pgmNewReceiverTrap_oid, sizeof(pgmNewReceiverTrap_oid)); +/* + * Add any objects from the trap definition + */ + snmp_varlist_add_variable (&var_list, + pgmReceiverSourceGsi_oid, OID_LENGTH(pgmReceiverSourceGsi_oid), + ASN_OCTET_STR, +/* Set an appropriate value for pgmReceiverSourceGsi */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmReceiverSourcePortNumber_oid, OID_LENGTH(pgmReceiverSourcePortNumber_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmReceiverSourcePortNumber */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmReceiverUniqueInstance_oid, OID_LENGTH(pgmReceiverUniqueInstance_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmReceiverUniqueInstance */ + NULL, 0); +/* + * Add any extra (optional) objects here + */ + +/* + * Send the trap to the list of configured destinations + * and clean up + */ + send_v2trap (var_list); + snmp_free_varbind (var_list); + return SNMP_ERR_NOERROR; +} + +int +send_pgmClosedReceiverTrap_trap (void) +{ + pgm_debug ("send_pgmClosedReceiverTrap_trap ()"); + + netsnmp_variable_list *var_list = NULL; + static const oid pgmClosedReceiverTrap_oid[] = { 1,3,6,1,3,112,2,0,6 }; + static const oid pgmReceiverSourceGsi_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,8, /* insert index here */ }; + static const oid pgmReceiverSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,9, /* insert index here */ }; + static const oid pgmReceiverUniqueInstance_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,10, /* insert index here */ }; + +/* + * Set the snmpTrapOid.0 value + */ + snmp_varlist_add_variable (&var_list, + snmptrap_oid, OID_LENGTH(snmptrap_oid), + ASN_OBJECT_ID, + (const u_char*)pgmClosedReceiverTrap_oid, sizeof(pgmClosedReceiverTrap_oid)); +/* + * Add any objects from the trap definition + */ + snmp_varlist_add_variable (&var_list, + pgmReceiverSourceGsi_oid, OID_LENGTH(pgmReceiverSourceGsi_oid), + ASN_OCTET_STR, +/* Set an appropriate value for pgmReceiverSourceGsi */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmReceiverSourcePortNumber_oid, OID_LENGTH(pgmReceiverSourcePortNumber_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmReceiverSourcePortNumber */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmReceiverUniqueInstance_oid, OID_LENGTH(pgmReceiverUniqueInstance_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmReceiverUniqueInstance */ + NULL, 0); +/* + * Add any extra (optional) objects here + */ + +/* + * Send the trap to the list of configured destinations + * and clean up + */ + send_v2trap (var_list); + snmp_free_varbind (var_list); + return SNMP_ERR_NOERROR; +} + +int +send_pgmNakFailuresTrap_trap (void) +{ + pgm_debug ("send_pgmNakFailuresTrap_trap ()"); + + netsnmp_variable_list *var_list = NULL; + static const oid pgmNakFailuresTrap_oid[] = { 1,3,6,1,3,112,2,0,7 }; + static const oid pgmReceiverSourceGsi_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,8, /* insert index here */ }; + static const oid pgmReceiverSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,9, /* insert index here */ }; + static const oid pgmReceiverUniqueInstance_oid[] = { 1,3,6,1,3,112,1,3,100,2,1,10, /* insert index here */ }; + static const oid pgmReceiverNakFailureThresholdTimer_oid[] = { 1,3,6,1,3,112,1,3,100,3,1,14, /* insert index here */ }; + static const oid pgmReceiverNakFailureThreshold_oid[] = { 1,3,6,1,3,112,1,3,100,3,1,15, /* insert index here */ }; + static const oid pgmReceiverNakFailuresLastInterval_oid[] = { 1,3,6,1,3,112,1,3,100,4,1,56, /* insert index here */ }; + static const oid pgmReceiverLastIntervalNakFailures_oid[] = { 1,3,6,1,3,112,1,3,100,4,1,57, /* insert index here */ }; + +/* + * Set the snmpTrapOid.0 value + */ + snmp_varlist_add_variable (&var_list, + snmptrap_oid, OID_LENGTH(snmptrap_oid), + ASN_OBJECT_ID, + (const u_char*)pgmNakFailuresTrap_oid, sizeof(pgmNakFailuresTrap_oid)); +/* + * Add any objects from the trap definition + */ + snmp_varlist_add_variable (&var_list, + pgmReceiverSourceGsi_oid, OID_LENGTH(pgmReceiverSourceGsi_oid), + ASN_OCTET_STR, +/* Set an appropriate value for pgmReceiverSourceGsi */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmReceiverSourcePortNumber_oid, OID_LENGTH(pgmReceiverSourcePortNumber_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmReceiverSourcePortNumber */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmReceiverUniqueInstance_oid, OID_LENGTH(pgmReceiverUniqueInstance_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmReceiverUniqueInstance */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmReceiverNakFailureThresholdTimer_oid, OID_LENGTH(pgmReceiverNakFailureThresholdTimer_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmReceiverNakFailureThresholdTimer */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmReceiverNakFailureThreshold_oid, OID_LENGTH(pgmReceiverNakFailureThreshold_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmReceiverNakFailureThreshold */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmReceiverNakFailuresLastInterval_oid, OID_LENGTH(pgmReceiverNakFailuresLastInterval_oid), + ASN_COUNTER, +/* Set an appropriate value for pgmReceiverNakFailuresLastInterval */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmReceiverLastIntervalNakFailures_oid, OID_LENGTH(pgmReceiverLastIntervalNakFailures_oid), + ASN_COUNTER, +/* Set an appropriate value for pgmReceiverLastIntervalNakFailures */ + NULL, 0); +/* + * Add any extra (optional) objects here + */ + +/* + * Send the trap to the list of configured destinations + * and clean up + */ + send_v2trap (var_list); + snmp_free_varbind (var_list); + return SNMP_ERR_NOERROR; +} + +int +send_pgmNewDlrSourceTrap_trap (void) +{ + pgm_debug ("send_pgmNewDlrSourceTrap_trap ()"); + + netsnmp_variable_list *var_list = NULL; + static const oid pgmNewDlrSourceTrap_oid[] = { 1,3,6,1,3,112,2,0,8 }; + static const oid pgmDlrSourceSourceGsi_oid[] = { 1,3,6,1,3,112,1,4,100,2,1,4, /* insert index here */ }; + static const oid pgmDlrSourceSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,4,100,2,1,5, /* insert index here */ }; + +/* + * Set the snmpTrapOid.0 value + */ + snmp_varlist_add_variable (&var_list, + snmptrap_oid, OID_LENGTH(snmptrap_oid), + ASN_OBJECT_ID, + (const u_char*)pgmNewDlrSourceTrap_oid, sizeof(pgmNewDlrSourceTrap_oid)); +/* + * Add any objects from the trap definition + */ + snmp_varlist_add_variable (&var_list, + pgmDlrSourceSourceGsi_oid, OID_LENGTH(pgmDlrSourceSourceGsi_oid), + ASN_OCTET_STR, +/* Set an appropriate value for pgmDlrSourceSourceGsi */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmDlrSourceSourcePortNumber_oid, OID_LENGTH(pgmDlrSourceSourcePortNumber_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmDlrSourceSourcePortNumber */ + NULL, 0); +/* + * Add any extra (optional) objects here + */ + +/* + * Send the trap to the list of configured destinations + * and clean up + */ + send_v2trap (var_list); + snmp_free_varbind (var_list); + return SNMP_ERR_NOERROR; +} + +int +send_pgmClosedDlrSourceTrap_trap (void) +{ + pgm_debug ("send_pgmClosedDlrSourceTrap_trap ()"); + + netsnmp_variable_list *var_list = NULL; + static const oid pgmClosedDlrSourceTrap_oid[] = { 1,3,6,1,3,112,2,0,9 }; + static const oid pgmDlrSourceSourceGsi_oid[] = { 1,3,6,1,3,112,1,4,100,2,1,4, /* insert index here */ }; + static const oid pgmDlrSourceSourcePortNumber_oid[] = { 1,3,6,1,3,112,1,4,100,2,1,5, /* insert index here */ }; + +/* + * Set the snmpTrapOid.0 value + */ + snmp_varlist_add_variable (&var_list, + snmptrap_oid, OID_LENGTH(snmptrap_oid), + ASN_OBJECT_ID, + (const u_char*)pgmClosedDlrSourceTrap_oid, sizeof(pgmClosedDlrSourceTrap_oid)); + +/* + * Add any objects from the trap definition + */ + snmp_varlist_add_variable (&var_list, + pgmDlrSourceSourceGsi_oid, OID_LENGTH(pgmDlrSourceSourceGsi_oid), + ASN_OCTET_STR, +/* Set an appropriate value for pgmDlrSourceSourceGsi */ + NULL, 0); + snmp_varlist_add_variable (&var_list, + pgmDlrSourceSourcePortNumber_oid, OID_LENGTH(pgmDlrSourceSourcePortNumber_oid), + ASN_UNSIGNED, +/* Set an appropriate value for pgmDlrSourceSourcePortNumber */ + NULL, 0); +/* + * Add any extra (optional) objects here + */ + +/* + * Send the trap to the list of configured destinations + * and clean up + */ + send_v2trap (var_list); + snmp_free_varbind (var_list); + return SNMP_ERR_NOERROR; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/pgmMIB_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/pgmMIB_unittest.c new file mode 100644 index 0000000..4cb4672 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/pgmMIB_unittest.c @@ -0,0 +1,257 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for PGM MIB routines. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include + + +/* mock state */ + +static GStaticRWLock mock_pgm_transport_list_lock = G_STATIC_RW_LOCK_INIT; +static GSList* mock_pgm_transport_list = NULL; + + +/* mock functions for external references */ + +static +netsnmp_handler_registration* +mock_netsnmp_create_handler_registration ( + const char* name, + Netsnmp_Node_Handler* handler_access_method, + oid* reg_oid, + size_t reg_oid_len, + int modes + ) +{ + netsnmp_handler_registration* handler = g_malloc0 (sizeof(netsnmp_handler_registration)); + return handler; +} + +static +void +mock_netsnmp_handler_registration_free ( + netsnmp_handler_registration* handler + ) +{ + g_assert (NULL != handler); + g_free (handler); +} + +static +void +mock_netsnmp_table_helper_add_indexes ( + netsnmp_table_registration_info* tinfo, + ... + ) +{ +} + +static +int +mock_netsnmp_register_table_iterator ( + netsnmp_handler_registration* reginfo, + netsnmp_iterator_info* iinfo + ) +{ + return MIB_REGISTERED_OK; +} + +static +int +mock_netsnmp_set_request_error ( + netsnmp_agent_request_info* reqinfo, + netsnmp_request_info* request, + int error_value + ) +{ + return 0; +} + +static +void* +mock_netsnmp_extract_iterator_context ( + netsnmp_request_info* reqinfo + ) +{ + return (void*)0x1; +} + +static +netsnmp_table_request_info* +mock_netsnmp_extract_table_info ( + netsnmp_request_info* reqinfo + ) +{ + return NULL; +} + +static +int +mock_snmp_set_var_typed_value ( + netsnmp_variable_list* newvar, + u_char type, + const u_char* val_str, + size_t val_len + ) +{ + return 0; +} + +static +netsnmp_variable_list* +mock_snmp_varlist_add_variable ( + netsnmp_variable_list** varlist, + const oid* oid, + size_t name_length, + u_char type, + const u_char* value, + size_t len + ) +{ + return NULL; +} + +static +void +mock_snmp_free_varbind ( + netsnmp_variable_list* var + ) +{ +} + +static +void +mock_snmp_free_var ( + netsnmp_variable_list* var + ) +{ +} + +static +int +mock_snmp_log ( + int priority, + const char* format, + ... + ) +{ + return 0; +} + +static +void +mock_send_v2trap ( + netsnmp_variable_list* var + ) +{ +} + +/** time module */ + +static +void +mock_pgm_time_since_epoch ( + pgm_time_t* pgm_time_t_time, + time_t* time_t_time + ) +{ + *time_t_time = pgm_to_secs (*pgm_time_t_time + 0); +} + + +#define netsnmp_create_handler_registration mock_netsnmp_create_handler_registration +#define netsnmp_handler_registration_free mock_netsnmp_handler_registration_free +#define netsnmp_table_helper_add_indexes mock_netsnmp_table_helper_add_indexes +#define netsnmp_register_table_iterator mock_netsnmp_register_table_iterator +#define netsnmp_set_request_error mock_netsnmp_set_request_error +#define netsnmp_extract_iterator_context mock_netsnmp_extract_iterator_context +#define netsnmp_extract_table_info mock_netsnmp_extract_table_info +#define snmp_set_var_typed_value mock_snmp_set_var_typed_value +#define snmp_varlist_add_variable mock_snmp_varlist_add_variable +#define snmp_free_varbind mock_snmp_free_varbind +#define snmp_free_var mock_snmp_free_var +#define snmp_log mock_snmp_log +#define send_v2trap mock_send_v2trap +#define pgm_transport_list mock_pgm_transport_list +#define pgm_transport_list_lock mock_pgm_transport_list_lock +#define pgm_time_since_epoch mock_pgm_time_since_epoch + +#define PGMMIB_DEBUG +#include "pgmMIB.c" + + +/* target: + * gboolean + * pgm_mib_init ( + * GError** error + * ) + */ + +START_TEST (test_init_pass_001) +{ + GError* err = NULL; + fail_unless (TRUE == pgm_mib_init (&err)); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_init = tcase_create ("init"); + suite_add_tcase (s, tc_init); + tcase_add_test (tc_init, test_init_pass_001); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/plan.txt b/3rdparty/openpgm-svn-r1135/pgm/plan.txt new file mode 100644 index 0000000..b1747ae --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/plan.txt @@ -0,0 +1,238 @@ +pgmdump +------- + +View all packets like tcpdump, but updated to full spec and allow dump of payload. + + +pgmtop +------ + +Dump realtime packet statistics in a ncurses display, mix of top/htop/netop. + + +basic_send +---------- + +Send an ODATA packet and terminate. + +Accept string payload and network parameters on command line. + +Send to multicast or send to unicast AFI. + +IPv4/6. + +Define optional session start, late join tags. + + +spm_idle +-------- + +Idle in an event loop sending out SPM packets. + + +stream_send +----------- + +Send a constant stream of ODATA and SPM packets. + + +basic_http +---------- + +Simple embedded web server + + +basic_recv +---------- + +Listen to packets indicating data loss, view details through web interface. + + +basic_container +--------------- + +Test performance of glib containers for fast allocating for a dynamic transmit window. + + +basic_txw +--------- + +Test performance of a basic transmit window implementation. + + +nak_txw +------- + +Test performance of random access to packets inside the window. + + +stream_send_with_nak +-------------------- + +Respond to NAK's with RDATA. + + +basic_recv_with_nak +------------------- + +Listen to packets and send NAK's to rebuild data. + + +dumpif +------ + +Display all IP based interfaces and basic details. + + +testif +------ + +Test various combinations of network specification. + + +sw_calc +------- + +Basic calculation tests of wrap-around sliding windows and a leading edge. + + +basic_recv_with_rxw +------------------- + +Listen to packets buffered with a receive window. + + +test_cpu_timers +--------------- + +Calculate drift between processors, cores, and hyper-threads. + + +pgmsend +-------- + +basic_send updated to use transmit window. + + +pgmrecv +-------- + +basic_recv_with_rxw without web interface, primary displays messages from pgmsend. + + +syncrecv +-------- + +pgmrecv implemented outside GLib with a synchronous coding paradigm. + + +pgmping +------- + +Dual mode: one to send fixed messages like pgmsend and listen for response, two to listen for +messages and reply. + + +block_send +---------- + +Send APDUs over ODATA. + + +(pgmrecv can receive APDUs) + +test_rs +------- + +Test 8-bit symbol Reed Solomon encoding and decoding with errors & erasures. + +test_fec +-------- + +Test fec creation and recovery. + + +send_with_fec +-------------------- + +Send APDUs over ODATA with FEC. + + + +Scenarios to reproduce +********************** + +- Packet loss in stream causing NAK generation. +- Link saturation in sending causing API feedback. +- Link peak stable speed. +- Maxium NAK generation to determine NCF/RDATA throughput. +- Corrupt packets with invalid IP checksum (? generate IP HDR in sender) +- Corrupt packets with invalid PGM checksum. +- Invalid packet values. +- NAK to NCF latency. +- NAK to RDATA latency. +- Publish bandwidth: total, per packet type, payload, per recipient (?) +- Subscribe bandwidth: total, per packet type, payload, per publisher (?) +- Restarting a session with similar or dissimilar sequence numbering. + +Outstanding questions +********************* + +- Is it faster to use chunks containing multiple packets instead of one MTU + per packet. Does aligning with system page size matter? +- Can g_timers be dropped easily for gettimeofday and avoid floating point math? Possible + to pass timer upstream with contiguous data for easy access. +- Can time evaluation be dropped to at most once per main loop event? +- Does code work 32 bit and is it optimal? +- Should trash stacks be monitored and controlled externally? For example, clearing + up after bursts or administrative control. +- Should trash stacks have a upper limit to then free to the slice allocator? +- Should lost packets be managed as ranges or individual sequence numbers, how + does each method affect performance? + +* The initial draft of PGM included OPT_RANGE option for NAKs to specify a range of lost + packets, this was replaced in the final draft with NAK lists. Some research hints that + ranges are suitable: + + http://www.isoc.org/inet2001/CD_proceedings/T54/T54.htm + http://tools.ietf.org/html/draft-speakman-pgm-spec-01 + +- Are place holders necessary? Can state timeouts be managed without a per sequence number + object? For example by the next data object, or an extra object for an ncf extended window: + note that nak packet generation should easily dwarfs time spent unless advantage is taken + of the additional 62 naks in a opt_nak_list. Caution has to be taken with the cost of + splitting a range when a packet is inserted in the middle, although idealy it should + be sequential from the trailing edge. +- Is it better to have send sockets per transport, or shared, bound to each interface? +- Cost of sharing state helper lists between receive windows? On culling a peer the lists + have to be purged. Saves iterating the hash list of receivers. +- Encapsulated UDP lists two ports, 3305 for broadcast, 3306 for unicast, how is this + supposed to map to regular PGM, and why the split? + +Basic TODO list +*************** + +- Ensure standardised error handling and status reporting. +- Implement mechanism for data-loss feedback. +- OPT_SYN & OPT_FIN on sending side. +- Shared trash stacks between multiple receive windows (contexts). +- Shared trash stacks between transmit and receive windows. +- FEC: compatibility with SmartPGM FEC, MS FEC? +- NAK backoff learning. +- Full conformance testing. (nak backoffs remaining) +- Unit testing. +- System testing with valgrind. +- Performance testing with oprofile. +- Basic DLR. +- Implement PGM sender (only) support thread? +- eventfd instead of pipes for recent Linux kernels. + +Optionals +********* + +- Some form of broadcast statistics for passive monitoring. +- (fix) BCH Reed-Solomon codec as possibly faster alternative, albeit incompatible with Microsoft. +- Recommendations as per the RMT working group of the IETF for AL-FEC codecs: Raptor codes, LDPC- + staircase and LDPC-triangle codes. +- XDR based messaging format as example of binary encoded messaging. + diff --git a/3rdparty/openpgm-svn-r1135/pgm/queue.c b/3rdparty/openpgm-svn-r1135/pgm/queue.c new file mode 100644 index 0000000..351c7ef --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/queue.c @@ -0,0 +1,110 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable double-ended queue. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + + +//#define QUEUE_DEBUG + +bool +pgm_queue_is_empty ( + const pgm_queue_t*const queue + ) +{ + pgm_return_val_if_fail (queue != NULL, TRUE); + + return queue->head == NULL; +} + +void +pgm_queue_push_head_link ( + pgm_queue_t* restrict queue, + pgm_list_t* restrict head_link + ) +{ + pgm_return_if_fail (queue != NULL); + pgm_return_if_fail (head_link != NULL); + pgm_return_if_fail (head_link->prev == NULL); + pgm_return_if_fail (head_link->next == NULL); + + head_link->next = queue->head; + if (queue->head) + queue->head->prev = head_link; + else + queue->tail = head_link; + queue->head = head_link; + queue->length++; +} + +pgm_list_t* +pgm_queue_pop_tail_link ( + pgm_queue_t* queue + ) +{ + pgm_return_val_if_fail (queue != NULL, NULL); + + if (queue->tail) + { + pgm_list_t *node = queue->tail; + + queue->tail = node->prev; + if (queue->tail) + { + queue->tail->next = NULL; + node->prev = NULL; + } + else + queue->head = NULL; + queue->length--; + + return node; + } + + return NULL; +} + +pgm_list_t* +pgm_queue_peek_tail_link ( + pgm_queue_t* queue + ) +{ + pgm_return_val_if_fail (queue != NULL, NULL); + + return queue->tail; +} + +void +pgm_queue_unlink ( + pgm_queue_t* restrict queue, + pgm_list_t* restrict target_link + ) +{ + pgm_return_if_fail (queue != NULL); + pgm_return_if_fail (target_link != NULL); + + if (target_link == queue->tail) + queue->tail = queue->tail->prev; + + queue->head = pgm_list_remove_link (queue->head, target_link); + queue->length--; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/rand.c b/3rdparty/openpgm-svn-r1135/pgm/rand.c new file mode 100644 index 0000000..91b71eb --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/rand.c @@ -0,0 +1,137 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable weak pseudo-random generator. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _WIN32 +# include +# include +#endif +#include + + +//#define RAND_DEBUG + + +/* locals */ + +static pgm_rand_t global_rand = { .seed = 0 }; +static volatile uint32_t rand_ref_count = 0; +static pgm_mutex_t rand_mutex; + + +void +pgm_rand_init (void) +{ + if (pgm_atomic_exchange_and_add32 (&rand_ref_count, 1) > 0) + return; + + pgm_mutex_init (&rand_mutex); +} + +void +pgm_rand_shutdown (void) +{ + pgm_return_if_fail (pgm_atomic_read32 (&rand_ref_count) > 0); + + if (pgm_atomic_exchange_and_add32 (&rand_ref_count, (uint32_t)-1) != 1) + return; + + pgm_mutex_free (&rand_mutex); +} + +void +pgm_rand_create ( + pgm_rand_t* new_rand + ) +{ +/* pre-conditions */ + pgm_assert (NULL != new_rand); + +#ifndef _WIN32 +/* attempt to read seed from kernel + */ + FILE* fp; + do { + fp = fopen ("/dev/urandom", "rb"); + } while (PGM_UNLIKELY(EINTR == errno)); + if (fp) { + size_t items_read; + do { + items_read = fread (&new_rand->seed, sizeof(new_rand->seed), 1, fp); + } while (PGM_UNLIKELY(EINTR == errno)); + fclose (fp); + if (1 == items_read) + return; + } +#endif /* !_WIN32 */ + const pgm_time_t now = pgm_time_update_now(); + new_rand->seed = (uint32_t)pgm_to_msecs (now); +} + +/* derived from POSIX.1-2001 example implementation of rand() + */ + +uint32_t +pgm_rand_int ( + pgm_rand_t* r + ) +{ +/* pre-conditions */ + pgm_assert (NULL != r); + + r->seed = r->seed * 1103515245 + 12345; + return r->seed; +} + +int32_t +pgm_rand_int_range ( + pgm_rand_t* r, + int32_t begin, + int32_t end + ) +{ +/* pre-conditions */ + pgm_assert (NULL != r); + + return begin + pgm_rand_int (r) % (end - begin); +} + +uint32_t +pgm_random_int (void) +{ + pgm_mutex_lock (&rand_mutex); + if (PGM_UNLIKELY(!global_rand.seed)) + pgm_rand_create (&global_rand); + const uint32_t rand_value = pgm_rand_int (&global_rand); + pgm_mutex_unlock (&rand_mutex); + return rand_value; +} + +int32_t +pgm_random_int_range ( + int32_t begin, + int32_t end + ) +{ + const uint32_t rand_value = pgm_random_int(); + return begin + rand_value % (end - begin); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/rand.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/rand.c.c89.patch new file mode 100644 index 0000000..074a3ef --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/rand.c.c89.patch @@ -0,0 +1,34 @@ +--- rand.c 2010-05-21 11:35:31.000000000 +0800 ++++ rand.c89 2010-08-04 15:44:47.000000000 +0800 +@@ -31,7 +31,7 @@ + + /* locals */ + +-static pgm_rand_t global_rand = { .seed = 0 }; ++static pgm_rand_t global_rand = { 0 }; + static volatile uint32_t rand_ref_count = 0; + static pgm_mutex_t rand_mutex; + +@@ -81,8 +81,10 @@ + return; + } + #endif /* !_WIN32 */ ++ { + const pgm_time_t now = pgm_time_update_now(); + new_rand->seed = (uint32_t)pgm_to_msecs (now); ++ } + } + + /* derived from POSIX.1-2001 example implementation of rand() +@@ -119,9 +121,11 @@ + pgm_mutex_lock (&rand_mutex); + if (PGM_UNLIKELY(!global_rand.seed)) + pgm_rand_create (&global_rand); ++ { + const uint32_t rand_value = pgm_rand_int (&global_rand); + pgm_mutex_unlock (&rand_mutex); + return rand_value; ++ } + } + + int32_t diff --git a/3rdparty/openpgm-svn-r1135/pgm/rate_control.c b/3rdparty/openpgm-svn-r1135/pgm/rate_control.c new file mode 100644 index 0000000..11f9e9b --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/rate_control.c @@ -0,0 +1,158 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Rate regulation. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + + +/* create machinery for rate regulation. + * the rate_per_sec is ammortized over millisecond time periods. + * + * NB: bucket MUST be memset 0 before calling. + */ + +void +pgm_rate_create ( + pgm_rate_t* bucket, + const ssize_t rate_per_sec, /* 0 = disable */ + const size_t iphdr_len, + const uint16_t max_tpdu + ) +{ +/* pre-conditions */ + pgm_assert (NULL != bucket); + pgm_assert (rate_per_sec >= max_tpdu); + + bucket->rate_per_sec = rate_per_sec; + bucket->iphdr_len = iphdr_len; + bucket->last_rate_check = pgm_time_update_now (); +/* pre-fill bucket */ + if ((rate_per_sec / 1000) >= max_tpdu) { + bucket->rate_per_msec = bucket->rate_per_sec / 1000; + bucket->rate_limit = bucket->rate_per_msec; + } else { + bucket->rate_limit = bucket->rate_per_sec; + } + pgm_spinlock_init (&bucket->spinlock); +} + +void +pgm_rate_destroy ( + pgm_rate_t* bucket + ) +{ +/* pre-conditions */ + pgm_assert (NULL != bucket); + + pgm_spinlock_free (&bucket->spinlock); +} + +/* check bit bucket whether an operation can proceed or should wait. + * + * returns TRUE when leaky bucket permits unless non-blocking flag is set. + * returns FALSE if operation should block and non-blocking flag is set. + */ + +bool +pgm_rate_check ( + pgm_rate_t* bucket, + const size_t data_size, + const bool is_nonblocking + ) +{ + int64_t new_rate_limit; + +/* pre-conditions */ + pgm_assert (NULL != bucket); + pgm_assert (data_size > 0); + + if (0 == bucket->rate_per_sec) + return TRUE; + + pgm_spinlock_lock (&bucket->spinlock); + pgm_time_t now = pgm_time_update_now(); + pgm_time_t time_since_last_rate_check = now - bucket->last_rate_check; + + if (bucket->rate_per_msec) + { + if (time_since_last_rate_check > pgm_msecs(1)) + new_rate_limit = bucket->rate_per_msec; + else { + new_rate_limit = bucket->rate_limit + ((bucket->rate_per_msec * time_since_last_rate_check) / 1000UL); + if (new_rate_limit > bucket->rate_per_msec) + new_rate_limit = bucket->rate_per_msec; + } + } + else + { + if (time_since_last_rate_check > pgm_secs(1)) + new_rate_limit = bucket->rate_per_sec; + else { + new_rate_limit = bucket->rate_limit + ((bucket->rate_per_sec * time_since_last_rate_check) / 1000000UL); + if (new_rate_limit > bucket->rate_per_sec) + new_rate_limit = bucket->rate_per_sec; + } + } + + new_rate_limit -= ( bucket->iphdr_len + data_size ); + if (is_nonblocking && new_rate_limit < 0) { + pgm_spinlock_unlock (&bucket->spinlock); + return FALSE; + } + + bucket->rate_limit = new_rate_limit; + bucket->last_rate_check = now; + if (bucket->rate_limit < 0) { + ssize_t sleep_amount; + do { + pgm_thread_yield(); + now = pgm_time_update_now(); + time_since_last_rate_check = now - bucket->last_rate_check; + sleep_amount = (ssize_t)pgm_to_secs (bucket->rate_per_sec * time_since_last_rate_check); + } while (sleep_amount + bucket->rate_limit < 0); + bucket->rate_limit += sleep_amount; + bucket->last_rate_check = now; + } + pgm_spinlock_unlock (&bucket->spinlock); + return TRUE; +} + +pgm_time_t +pgm_rate_remaining ( + pgm_rate_t* bucket, + const size_t n + ) +{ +/* pre-conditions */ + pgm_assert (NULL != bucket); + + if (PGM_UNLIKELY(0 == bucket->rate_per_sec)) + return 0; + + pgm_spinlock_lock (&bucket->spinlock); + const pgm_time_t now = pgm_time_update_now(); + const pgm_time_t time_since_last_rate_check = now - bucket->last_rate_check; + const int64_t bucket_bytes = bucket->rate_limit + pgm_to_secs (bucket->rate_per_sec * time_since_last_rate_check) - n; + pgm_spinlock_unlock (&bucket->spinlock); + + return bucket_bytes >= 0 ? 0 : (bucket->rate_per_sec / -bucket_bytes); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/rate_control.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/rate_control.c.c89.patch new file mode 100644 index 0000000..d779a78 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/rate_control.c.c89.patch @@ -0,0 +1,62 @@ +--- rate_control.c 2010-08-04 15:58:08.000000000 +0800 ++++ rate_control.c89 2010-08-04 15:57:59.000000000 +0800 +@@ -77,7 +77,7 @@ + const bool is_nonblocking + ) + { +- int64_t new_rate_limit; ++ ssize_t new_rate_limit; + + /* pre-conditions */ + pgm_assert (NULL != bucket); +@@ -87,6 +87,7 @@ + return TRUE; + + pgm_spinlock_lock (&bucket->spinlock); ++ { + pgm_time_t now = pgm_time_update_now(); + pgm_time_t time_since_last_rate_check = now - bucket->last_rate_check; + +@@ -95,7 +96,9 @@ + if (time_since_last_rate_check > pgm_msecs(1)) + new_rate_limit = bucket->rate_per_msec; + else { ++#pragma warning( disable : 4244 ) + new_rate_limit = bucket->rate_limit + ((bucket->rate_per_msec * time_since_last_rate_check) / 1000UL); ++#pragma warning( default : 4244 ) + if (new_rate_limit > bucket->rate_per_msec) + new_rate_limit = bucket->rate_per_msec; + } +@@ -105,7 +108,9 @@ + if (time_since_last_rate_check > pgm_secs(1)) + new_rate_limit = bucket->rate_per_sec; + else { ++#pragma warning( disable : 4244 ) + new_rate_limit = bucket->rate_limit + ((bucket->rate_per_sec * time_since_last_rate_check) / 1000000UL); ++#pragma warning( default : 4244 ) + if (new_rate_limit > bucket->rate_per_sec) + new_rate_limit = bucket->rate_per_sec; + } +@@ -132,6 +137,7 @@ + } + pgm_spinlock_unlock (&bucket->spinlock); + return TRUE; ++ } + } + + pgm_time_t +@@ -147,12 +153,14 @@ + return 0; + + pgm_spinlock_lock (&bucket->spinlock); ++ { + const pgm_time_t now = pgm_time_update_now(); + const pgm_time_t time_since_last_rate_check = now - bucket->last_rate_check; + const int64_t bucket_bytes = bucket->rate_limit + pgm_to_secs (bucket->rate_per_sec * time_since_last_rate_check) - n; + pgm_spinlock_unlock (&bucket->spinlock); + + return bucket_bytes >= 0 ? 0 : (bucket->rate_per_sec / -bucket_bytes); ++ } + } + + /* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/rate_control_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/rate_control_unittest.c new file mode 100644 index 0000000..7da5128 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/rate_control_unittest.c @@ -0,0 +1,241 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for rate regulation. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __STDC_FORMAT_MACROS +#include +#include +#include +#include +#include +#include + + +/* mock state */ + + +#define pgm_time_now mock_pgm_time_now +#define pgm_time_update_now mock_pgm_time_update_now + +#define RATE_CONTROL_DEBUG +#include "rate_control.c" + +static pgm_time_t mock_pgm_time_now = 0x1; +static pgm_time_t _mock_pgm_time_update_now (void); +pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; + + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + +static +pgm_time_t +_mock_pgm_time_update_now (void) +{ + g_debug ("mock_pgm_time_now: %" PGM_TIME_FORMAT, mock_pgm_time_now); + return mock_pgm_time_now; +} + + +/* target: + * void + * pgm_rate_create ( + * pgm_rate_t* bucket_, + * const ssize_t rate_per_sec, + * const size_t iphdr_len, + * const uint16_t max_tpdu + * ) + */ + +START_TEST (test_create_pass_001) +{ + pgm_rate_t rate; + memset (&rate, 0, sizeof(rate)); + pgm_rate_create (&rate, 100*1000, 10, 1500); +} +END_TEST + +START_TEST (test_create_fail_001) +{ + pgm_rate_create (NULL, 0, 0, 1500); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_rate_destroy ( + * pgm_rate_t* bucket + * ) + */ + +START_TEST (test_destroy_pass_001) +{ + pgm_rate_t rate; + memset (&rate, 0, sizeof(rate)); + pgm_rate_create (&rate, 100*1000, 10, 1500); + pgm_rate_destroy (&rate); +} +END_TEST + +START_TEST (test_destroy_fail_001) +{ + pgm_rate_destroy (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_rate_check ( + * pgm_rate_t* bucket, + * const size_t data_size, + * const bool is_nonblocking + * ) + * + * 001: should use seconds resolution to allow 2 packets through then fault. + */ + +START_TEST (test_check_pass_001) +{ + pgm_rate_t rate; + memset (&rate, 0, sizeof(rate)); + pgm_rate_create (&rate, 2*1010, 10, 1500); + mock_pgm_time_now += pgm_secs(2); + fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + pgm_rate_destroy (&rate); +} +END_TEST + +START_TEST (test_check_fail_001) +{ + pgm_rate_check (NULL, 1000, FALSE); + fail ("reached"); +} +END_TEST + +/* 002: assert that only one packet should pass through small bucket + */ + +START_TEST (test_check_pass_002) +{ + pgm_rate_t rate; + memset (&rate, 0, sizeof(rate)); + pgm_rate_create (&rate, 2*900, 10, 1500); + mock_pgm_time_now += pgm_secs(2); + fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + pgm_rate_destroy (&rate); +} +END_TEST + +/* 003: millisecond resolution should initiate millisecond fills. + */ + +START_TEST (test_check_pass_003) +{ + pgm_rate_t rate; + memset (&rate, 0, sizeof(rate)); + pgm_rate_create (&rate, 2*1010*1000, 10, 1500); + mock_pgm_time_now += pgm_secs(2); + fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); +/* duplicate check at same time point */ + fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); +/* advance time causing a millisecond fill to occur */ + mock_pgm_time_now += pgm_msecs(1); + fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); +/* advance time to fill bucket enough for only one packet */ + mock_pgm_time_now += pgm_usecs(500); + fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); +/* advance time to fill the bucket a little but not enough for one packet */ + mock_pgm_time_now += pgm_usecs(100); + fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); +/* advance time a lot, should be limited to millisecond fill rate */ + mock_pgm_time_now += pgm_secs(10); + fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + fail_unless (TRUE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + fail_unless (FALSE == pgm_rate_check (&rate, 1000, TRUE), "rate_check failed"); + pgm_rate_destroy (&rate); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_create = tcase_create ("create"); + suite_add_tcase (s, tc_create); + tcase_add_test (tc_create, test_create_pass_001); + tcase_add_test_raise_signal (tc_create, test_create_fail_001, SIGABRT); + + TCase* tc_destroy = tcase_create ("destroy"); + suite_add_tcase (s, tc_destroy); + tcase_add_test (tc_destroy, test_destroy_pass_001); + tcase_add_test_raise_signal (tc_destroy, test_destroy_fail_001, SIGABRT); + + TCase* tc_check = tcase_create ("check"); + suite_add_tcase (s, tc_check); + tcase_add_test (tc_check, test_check_pass_001); + tcase_add_test (tc_check, test_check_pass_002); + tcase_add_test (tc_check, test_check_pass_003); + tcase_add_test_raise_signal (tc_check, test_check_fail_001, SIGABRT); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/receiver.c b/3rdparty/openpgm-svn-r1135/pgm/receiver.c new file mode 100644 index 0000000..ea2acea --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/receiver.c @@ -0,0 +1,2292 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM receiver socket. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __STDC_FORMAT_MACROS +#ifdef _MSC_VER +# include +#else +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + + +//#define RECEIVER_DEBUG +//#define SPM_DEBUG + +#ifndef RECEIVER_DEBUG +# define PGM_DISABLE_ASSERT +#endif + +#if !defined(ENOBUFS) && defined(WSAENOBUFS) +# define ENOBUFS WSAENOBUFS +#endif +#if !defined(ECONNRESET) && defined(WSAECONNRESET) +# define ECONNRESET WSAECONNRESET +#endif + +static bool send_spmr (pgm_sock_t*const restrict, pgm_peer_t*const restrict); +static bool send_nak (pgm_sock_t*const restrict, pgm_peer_t*const restrict, const uint32_t); +static bool send_parity_nak (pgm_sock_t*const restrict, pgm_peer_t*const restrict, const unsigned, const unsigned); +static bool send_nak_list (pgm_sock_t*const restrict, pgm_peer_t*const restrict, const struct pgm_sqn_list_t*const restrict); +static bool nak_rb_state (pgm_peer_t*, const pgm_time_t); +static void nak_rpt_state (pgm_peer_t*, const pgm_time_t); +static void nak_rdata_state (pgm_peer_t*, const pgm_time_t); +static inline pgm_peer_t* _pgm_peer_ref (pgm_peer_t*); +static bool on_general_poll (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict); +static bool on_dlr_poll (pgm_sock_t*const restrict, pgm_peer_t*const restrict, struct pgm_sk_buff_t*const restrict); + + +/* helpers for pgm_peer_t */ +static inline +pgm_time_t +next_ack_rb_expiry ( + const pgm_rxw_t* window + ) +{ + pgm_assert (NULL != window); + pgm_assert (NULL != window->ack_backoff_queue.tail); + + const struct pgm_peer_t* peer = (const struct pgm_peer_t*)window->ack_backoff_queue.tail->data; + pgm_assert (NULL != peer); + + pgm_assert (peer->sock->use_pgmcc); + return peer->ack_rb_expiry; +} + +static inline +pgm_time_t +next_nak_rb_expiry ( + const pgm_rxw_t* window + ) +{ + pgm_assert (NULL != window); + pgm_assert (NULL != window->nak_backoff_queue.tail); + + const struct pgm_sk_buff_t* skb = (const struct pgm_sk_buff_t*)window->nak_backoff_queue.tail; + const pgm_rxw_state_t* state = (const pgm_rxw_state_t*)&skb->cb; + return state->timer_expiry; +} + +static inline +pgm_time_t +next_nak_rpt_expiry ( + const pgm_rxw_t* window + ) +{ + pgm_assert (NULL != window); + pgm_assert (NULL != window->wait_ncf_queue.tail); + + const struct pgm_sk_buff_t* skb = (const struct pgm_sk_buff_t*)window->wait_ncf_queue.tail; + const pgm_rxw_state_t* state = (const pgm_rxw_state_t*)&skb->cb; + return state->timer_expiry; +} + +static inline +pgm_time_t +next_nak_rdata_expiry ( + const pgm_rxw_t* window + ) +{ + pgm_assert (NULL != window); + pgm_assert (NULL != window->wait_data_queue.tail); + + const struct pgm_sk_buff_t* skb = (const struct pgm_sk_buff_t*)window->wait_data_queue.tail; + const pgm_rxw_state_t* state = (const pgm_rxw_state_t*)&skb->cb; + return state->timer_expiry; +} + +/* calculate ACK_RB_IVL. + */ +static inline +uint32_t +ack_rb_ivl ( + pgm_sock_t* sock + ) /* not const as rand() updates the seed */ +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (sock->use_pgmcc); + pgm_assert_cmpuint (sock->ack_bo_ivl, >, 1); + + return pgm_rand_int_range (&sock->rand_, 1 /* us */, sock->ack_bo_ivl); +} + +/* calculate NAK_RB_IVL as random time interval 1 - NAK_BO_IVL. + */ +static inline +uint32_t +nak_rb_ivl ( + pgm_sock_t* sock + ) /* not const as rand() updates the seed */ +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert_cmpuint (sock->nak_bo_ivl, >, 1); + + return pgm_rand_int_range (&sock->rand_, 1 /* us */, sock->nak_bo_ivl); +} + +/* mark sequence as recovery failed. + */ + +static +void +cancel_skb ( + pgm_sock_t* restrict sock, + pgm_peer_t* restrict peer, + const struct pgm_sk_buff_t* restrict skb, + const pgm_time_t now + ) +{ + pgm_assert (NULL != sock); + pgm_assert (NULL != peer); + pgm_assert (NULL != skb); + pgm_assert_cmpuint (now, >=, skb->tstamp); + + pgm_trace (PGM_LOG_ROLE_RX_WINDOW, _("Lost data #%u due to cancellation."), skb->sequence); + + const uint32_t fail_time = now - skb->tstamp; + if (!peer->max_fail_time) + peer->max_fail_time = peer->min_fail_time = fail_time; + else if (fail_time > peer->max_fail_time) + peer->max_fail_time = fail_time; + else if (fail_time < peer->min_fail_time) + peer->min_fail_time = fail_time; + + pgm_rxw_lost (peer->window, skb->sequence); + PGM_HISTOGRAM_TIMES("Rx.FailTime", fail_time); + +/* mark receiver window for flushing on next recv() */ + pgm_peer_set_pending (sock, peer); +} + +/* check whether this receiver is the designated acker for the source + */ + +static inline +bool +_pgm_is_acker ( + const pgm_peer_t* restrict peer, + const struct pgm_sk_buff_t* restrict skb + ) +{ + struct sockaddr_storage acker_nla; + +/* pre-conditions */ + pgm_assert (NULL != peer); + pgm_assert (peer->sock->use_pgmcc); + pgm_assert (NULL != skb); + pgm_assert (NULL != skb->pgm_opt_pgmcc_data); + + pgm_nla_to_sockaddr (&skb->pgm_opt_pgmcc_data->opt_nla_afi, (struct sockaddr*)&acker_nla); + return (0 == pgm_sockaddr_cmp ((struct sockaddr*)&acker_nla, (struct sockaddr*)&peer->sock->send_addr)); +} + +/* is the source holding an acker election + */ + +static inline +bool +_pgm_is_acker_election ( + const struct pgm_sk_buff_t* restrict skb + ) +{ + pgm_assert (NULL != skb); + pgm_assert (NULL != skb->pgm_opt_pgmcc_data); + + const unsigned acker_afi = ntohs (skb->pgm_opt_pgmcc_data->opt_nla_afi); + switch (acker_afi) { + case AFI_IP: + if (INADDR_ANY == skb->pgm_opt_pgmcc_data->opt_nla.s_addr) + return TRUE; + break; + + case AFI_IP6: + if (0 == memcmp (&skb->pgm_opt_pgmcc_data->opt_nla, &in6addr_any, sizeof(in6addr_any))) + return TRUE; + break; + + default: break; + } + + return FALSE; +} + +/* add state for an ACK on a data packet. + */ + +static inline +void +_pgm_add_ack ( + pgm_peer_t* const restrict peer, + const pgm_time_t ack_rb_expiry + ) +{ + pgm_assert (NULL != peer); + pgm_assert (peer->sock->use_pgmcc); + + peer->ack_rb_expiry = ack_rb_expiry; + pgm_queue_push_head_link (&peer->window->ack_backoff_queue, &peer->ack_link); +} + +/* remove outstanding ACK + */ + +static inline +void +_pgm_remove_ack ( + pgm_peer_t* const restrict peer + ) +{ + pgm_assert (NULL != peer); + pgm_assert (peer->sock->use_pgmcc); + pgm_assert (!pgm_queue_is_empty (&peer->window->ack_backoff_queue)); + + pgm_queue_unlink (&peer->window->ack_backoff_queue, &peer->ack_link); + peer->ack_rb_expiry = 0; +} + +/* increase reference count for peer object + * + * on success, returns peer object. + */ + +static inline +pgm_peer_t* +_pgm_peer_ref ( + pgm_peer_t* peer + ) +{ +/* pre-conditions */ + pgm_assert (NULL != peer); + + pgm_atomic_inc32 (&peer->ref_count); + return peer; +} + +/* decrease reference count of peer object, destroying on last reference. + */ + +void +pgm_peer_unref ( + pgm_peer_t* peer + ) +{ +/* pre-conditions */ + pgm_assert (NULL != peer); + + if (pgm_atomic_exchange_and_add32 (&peer->ref_count, (uint32_t)-1) != 1) + return; + +/* receive window */ + pgm_rxw_destroy (peer->window); + peer->window = NULL; + +/* object */ + pgm_free (peer); + peer = NULL; +} + +/* find PGM options in received SKB. + * + * returns TRUE if opt_fragment is found, otherwise FALSE is returned. + */ + +static +bool +get_pgm_options ( + struct pgm_sk_buff_t* const skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + pgm_assert (NULL != skb->pgm_data); + + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(skb->pgm_data + 1); + bool found_opt = FALSE; + + pgm_assert (opt_header->opt_type == PGM_OPT_LENGTH); + pgm_assert (opt_header->opt_length == sizeof(struct pgm_opt_length)); + + pgm_debug ("get_pgm_options (skb:%p)", + (const void*)skb); + + skb->pgm_opt_fragment = NULL; + skb->pgm_opt_pgmcc_data = NULL; + +/* always at least two options, first is always opt_length */ + do { + opt_header = (struct pgm_opt_header*)((char*)opt_header + opt_header->opt_length); +/* option overflow */ + if (PGM_UNLIKELY((char*)opt_header > (char*)skb->data)) + break; + + switch (opt_header->opt_type & PGM_OPT_MASK) { + case PGM_OPT_FRAGMENT: + skb->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + found_opt = TRUE; + break; + + case PGM_OPT_PGMCC_DATA: + skb->pgm_opt_pgmcc_data = (struct pgm_opt_pgmcc_data*)(opt_header + 1); + found_opt = TRUE; + break; + + default: break; + } + + } while (!(opt_header->opt_type & PGM_OPT_END)); + return found_opt; +} + +/* a peer in the context of the sock is another party on the network sending PGM + * packets. for each peer we need a receive window and network layer address (nla) to + * which nak requests can be forwarded to. + * + * on success, returns new peer object. + */ + +pgm_peer_t* +pgm_new_peer ( + pgm_sock_t* const restrict sock, + const pgm_tsi_t* const restrict tsi, + const struct sockaddr* const restrict src_addr, + const socklen_t src_addrlen, + const struct sockaddr* const restrict dst_addr, + const socklen_t dst_addrlen, + const pgm_time_t now + ) +{ + pgm_peer_t* peer; + +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != src_addr); + pgm_assert (src_addrlen > 0); + pgm_assert (NULL != dst_addr); + pgm_assert (dst_addrlen > 0); + +#ifdef PGM_DEBUG + char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop (src_addr, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (dst_addr, daddr, sizeof(daddr)); + pgm_debug ("pgm_new_peer (sock:%p tsi:%s src-addr:%s src-addrlen:%u dst-addr:%s dst-addrlen:%u)", + (void*)sock, pgm_tsi_print (tsi), saddr, (unsigned)src_addrlen, daddr, (unsigned)dst_addrlen); +#endif + + peer = pgm_new0 (pgm_peer_t, 1); + peer->expiry = now + sock->peer_expiry; + peer->sock = sock; + memcpy (&peer->tsi, tsi, sizeof(pgm_tsi_t)); + memcpy (&peer->group_nla, dst_addr, dst_addrlen); + memcpy (&peer->local_nla, src_addr, src_addrlen); +/* port at same location for sin/sin6 */ + ((struct sockaddr_in*)&peer->local_nla)->sin_port = htons (sock->udp_encap_ucast_port); + ((struct sockaddr_in*)&peer->nla)->sin_port = htons (sock->udp_encap_ucast_port); + +/* lock on rx window */ + peer->window = pgm_rxw_create (&peer->tsi, + sock->max_tpdu, + sock->rxw_sqns, + sock->rxw_secs, + sock->rxw_max_rte, + sock->ack_c_p); + peer->spmr_expiry = now + sock->spmr_expiry; + +/* Prepare ack_link */ + peer->ack_link.data = peer; + +/* add peer to hash table and linked list */ + pgm_rwlock_writer_lock (&sock->peers_lock); + pgm_peer_t* entry = _pgm_peer_ref (peer); + pgm_hashtable_insert (sock->peers_hashtable, &peer->tsi, entry); + peer->peers_link.data = peer; + sock->peers_list = pgm_list_prepend_link (sock->peers_list, &peer->peers_link); + pgm_rwlock_writer_unlock (&sock->peers_lock); + + pgm_timer_lock (sock); + if (pgm_time_after( sock->next_poll, peer->spmr_expiry )) + sock->next_poll = peer->spmr_expiry; + pgm_timer_unlock (sock); + return peer; +} + +/* copy any contiguous buffers in the peer list to the provided + * message vector. + * returns -ENOBUFS if the vector is full, returns -ECONNRESET if + * data loss is detected, returns 0 when all peers flushed. + */ + +int +pgm_flush_peers_pending ( + pgm_sock_t* const restrict sock, + struct pgm_msgv_t** restrict pmsg, + const struct pgm_msgv_t* const msg_end, /* at least pmsg + 1, same object */ + size_t* const restrict bytes_read, /* added to, not set */ + unsigned* const restrict data_read + ) +{ + int retval = 0; + +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != pmsg); + pgm_assert (NULL != *pmsg); + pgm_assert (NULL != msg_end); + pgm_assert (NULL != bytes_read); + pgm_assert (NULL != data_read); + + pgm_debug ("pgm_flush_peers_pending (sock:%p pmsg:%p msg-end:%p bytes-read:%p data-read:%p)", + (const void*)sock, (const void*)pmsg, (const void*)msg_end, (const void*)bytes_read, (const void*)data_read); + + while (sock->peers_pending) + { + pgm_peer_t* peer = sock->peers_pending->data; + if (peer->last_commit && peer->last_commit < sock->last_commit) + pgm_rxw_remove_commit (peer->window); + const ssize_t peer_bytes = pgm_rxw_readv (peer->window, pmsg, msg_end - *pmsg + 1); + + if (peer->last_cumulative_losses != ((pgm_rxw_t*)peer->window)->cumulative_losses) + { + sock->is_reset = TRUE; + peer->lost_count = ((pgm_rxw_t*)peer->window)->cumulative_losses - peer->last_cumulative_losses; + peer->last_cumulative_losses = ((pgm_rxw_t*)peer->window)->cumulative_losses; + } + + if (peer_bytes >= 0) + { + (*bytes_read) += peer_bytes; + (*data_read) ++; + peer->last_commit = sock->last_commit; + if (*pmsg > msg_end) { /* commit full */ + retval = -ENOBUFS; + break; + } + } else + peer->last_commit = 0; + if (PGM_UNLIKELY(sock->is_reset)) { + retval = -ECONNRESET; + break; + } +/* clear this reference and move to next */ + sock->peers_pending = pgm_slist_remove_first (sock->peers_pending); + } + + return retval; +} + +/* edge trigerred has receiver pending events + */ + +bool +pgm_peer_has_pending ( + pgm_peer_t* const peer + ) +{ +/* pre-conditions */ + pgm_assert (NULL != peer); + + if (NULL == peer->pending_link.data && ((pgm_rxw_t*)peer->window)->has_event) { + ((pgm_rxw_t*)peer->window)->has_event = 0; + return TRUE; + } + return FALSE; +} + +/* set receiver in pending event queue + */ + +void +pgm_peer_set_pending ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict peer + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != peer); + + if (peer->pending_link.data) return; + peer->pending_link.data = peer; + sock->peers_pending = pgm_slist_prepend_link (sock->peers_pending, &peer->pending_link); +} + +/* Create a new error SKB detailing data loss. + */ + +void +pgm_set_reset_error ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict source, + struct pgm_msgv_t* const restrict msgv + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != source); + pgm_assert (NULL != msgv); + + struct pgm_sk_buff_t* error_skb = pgm_alloc_skb (0); + error_skb->sock = sock; + error_skb->tstamp = pgm_time_update_now (); + memcpy (&error_skb->tsi, &source->tsi, sizeof(pgm_tsi_t)); + error_skb->sequence = source->lost_count; + msgv->msgv_skb[0] = error_skb; + msgv->msgv_len = 1; +} + +/* SPM indicate start of a session, continued presence of a session, or flushing final packets + * of a session. + * + * returns TRUE on valid packet, FALSE on invalid packet or duplicate SPM sequence number. + */ + +bool +pgm_on_spm ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict source, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != source); + pgm_assert (NULL != skb); + + pgm_debug("pgm_on_spm (sock:%p source:%p skb:%p)", + (const void*)sock, (const void*)source, (const void*)skb); + + if (PGM_UNLIKELY(!pgm_verify_spm (skb))) { + pgm_trace(PGM_LOG_ROLE_NETWORK,_("Discarded invalid SPM.")); + source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]++; + return FALSE; + } + + const struct pgm_spm* spm = (struct pgm_spm*) skb->data; + const struct pgm_spm6* spm6 = (struct pgm_spm6*)skb->data; + const uint32_t spm_sqn = ntohl (spm->spm_sqn); + +/* check for advancing sequence number, or first SPM */ + if (PGM_LIKELY(pgm_uint32_gte (spm_sqn, source->spm_sqn))) + { +/* copy NLA for replies */ + pgm_nla_to_sockaddr (&spm->spm_nla_afi, (struct sockaddr*)&source->nla); + +/* save sequence number */ + source->spm_sqn = spm_sqn; + +/* update receive window */ + const pgm_time_t nak_rb_expiry = skb->tstamp + nak_rb_ivl (sock); + const unsigned naks = pgm_rxw_update (source->window, + ntohl (spm->spm_lead), + ntohl (spm->spm_trail), + skb->tstamp, + nak_rb_expiry); + if (naks) { + pgm_timer_lock (sock); + if (pgm_time_after (sock->next_poll, nak_rb_expiry)) + sock->next_poll = nak_rb_expiry; + pgm_timer_unlock (sock); + } + +/* mark receiver window for flushing on next recv() */ + const pgm_rxw_t* window = source->window; + if (window->cumulative_losses != source->last_cumulative_losses && + !source->pending_link.data) + { + sock->is_reset = TRUE; + source->lost_count = window->cumulative_losses - source->last_cumulative_losses; + source->last_cumulative_losses = window->cumulative_losses; + pgm_peer_set_pending (sock, source); + } + } + else + { /* does not advance SPM sequence number */ + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded duplicate SPM.")); + source->cumulative_stats[PGM_PC_RECEIVER_DUP_SPMS]++; + return FALSE; + } + +/* check whether peer can generate parity packets */ + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) + { + const struct pgm_opt_length* opt_len = (AF_INET6 == source->nla.ss_family) ? + (const struct pgm_opt_length*)(spm6 + 1) : + (const struct pgm_opt_length*)(spm + 1); + if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed SPM.")); + source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]++; + return FALSE; + } + if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed SPM.")); + source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]++; + return FALSE; + } +/* TODO: check for > 16 options & past packet end */ + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); + if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_PARITY_PRM) + { + const struct pgm_opt_parity_prm* opt_parity_prm = (const struct pgm_opt_parity_prm*)(opt_header + 1); + if (PGM_UNLIKELY((opt_parity_prm->opt_reserved & PGM_PARITY_PRM_MASK) == 0)) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed SPM.")); + source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]++; + return FALSE; + } + + const uint32_t parity_prm_tgs = ntohl (opt_parity_prm->parity_prm_tgs); + if (PGM_UNLIKELY(parity_prm_tgs < 2 || parity_prm_tgs > 128)) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed SPM.")); + source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_SPMS]++; + return FALSE; + } + + source->has_proactive_parity = opt_parity_prm->opt_reserved & PGM_PARITY_PRM_PRO; + source->has_ondemand_parity = opt_parity_prm->opt_reserved & PGM_PARITY_PRM_OND; + if (source->has_proactive_parity || source->has_ondemand_parity) { + source->is_fec_enabled = 1; + pgm_rxw_update_fec (source->window, parity_prm_tgs); + } + } + } while (!(opt_header->opt_type & PGM_OPT_END)); + } + +/* either way bump expiration timer */ + source->expiry = skb->tstamp + sock->peer_expiry; + source->spmr_expiry = 0; + if (source->spmr_tstamp > 0) { + PGM_HISTOGRAM_TIMES("Rx.SpmRequestResponseTime", skb->tstamp - source->spmr_tstamp); + source->spmr_tstamp = 0; + } + return TRUE; +} + +/* Multicast peer-to-peer NAK handling, pretty much the same as a NCF but different direction + * + * if NAK is valid, returns TRUE. on error, FALSE is returned. + */ + +bool +pgm_on_peer_nak ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict peer, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != peer); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_peer_nak (sock:%p peer:%p skb:%p)", + (const void*)sock, (const void*)peer, (const void*)skb); + + if (PGM_UNLIKELY(!pgm_verify_nak (skb))) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded invalid multicast NAK.")); + peer->cumulative_stats[PGM_PC_RECEIVER_NAK_ERRORS]++; + return FALSE; + } + + const struct pgm_nak* nak = (struct pgm_nak*) skb->data; + const struct pgm_nak6* nak6 = (struct pgm_nak6*)skb->data; + +/* NAK_SRC_NLA must not contain our sock unicast NLA */ + struct sockaddr_storage nak_src_nla; + pgm_nla_to_sockaddr (&nak->nak_src_nla_afi, (struct sockaddr*)&nak_src_nla); + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nak_src_nla, (struct sockaddr*)&sock->send_addr) == 0)) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded multicast NAK on NLA mismatch.")); + return FALSE; + } + +/* NAK_GRP_NLA contains one of our sock receive multicast groups: the sources send multicast group */ + struct sockaddr_storage nak_grp_nla; + pgm_nla_to_sockaddr ((AF_INET6 == nak_src_nla.ss_family) ? &nak6->nak6_grp_nla_afi : &nak->nak_grp_nla_afi, (struct sockaddr*)&nak_grp_nla); + bool found = FALSE; + for (unsigned i = 0; i < sock->recv_gsr_len; i++) + { + if (pgm_sockaddr_cmp ((struct sockaddr*)&nak_grp_nla, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0) + { + found = TRUE; + break; + } + } + + if (PGM_UNLIKELY(!found)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded multicast NAK on multicast group mismatch.")); + return FALSE; + } + +/* handle as NCF */ + int status = pgm_rxw_confirm (peer->window, + ntohl (nak->nak_sqn), + skb->tstamp, + skb->tstamp + sock->nak_rdata_ivl, + skb->tstamp + nak_rb_ivl(sock)); + if (PGM_RXW_UPDATED == status || PGM_RXW_APPENDED == status) + peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]++; + +/* check NAK list */ + const uint32_t* nak_list = NULL; + unsigned nak_list_len = 0; + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) + { + const struct pgm_opt_length* opt_len = (AF_INET6 == nak_src_nla.ss_family) ? + (const struct pgm_opt_length*)(nak6 + 1) : + (const struct pgm_opt_length*)(nak + 1); + if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed multicast NAK.")); + peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]++; + return FALSE; + } + if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed multicast NAK.")); + peer->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]++; + return FALSE; + } +/* TODO: check for > 16 options & past packet end */ + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); + if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_NAK_LIST) + { + nak_list = ((const struct pgm_opt_nak_list*)(opt_header + 1))->opt_sqn; + nak_list_len = ( opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(uint8_t) ) / sizeof(uint32_t); + break; + } + } while (!(opt_header->opt_type & PGM_OPT_END)); + } + + while (nak_list_len) { + status = pgm_rxw_confirm (peer->window, + ntohl (*nak_list), + skb->tstamp, + skb->tstamp + sock->nak_rdata_ivl, + skb->tstamp + nak_rb_ivl(sock)); + if (PGM_RXW_UPDATED == status || PGM_RXW_APPENDED == status) + peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]++; + nak_list++; + nak_list_len--; + } + +/* mark receiver window for flushing on next recv() */ + const pgm_rxw_t* window = peer->window; + if (window->cumulative_losses != peer->last_cumulative_losses && + !peer->pending_link.data) + { + sock->is_reset = TRUE; + peer->lost_count = window->cumulative_losses - peer->last_cumulative_losses; + peer->last_cumulative_losses = window->cumulative_losses; + pgm_peer_set_pending (sock, peer); + } + return TRUE; +} + +/* NCF confirming receipt of a NAK from this sock or another on the LAN segment. + * + * Packet contents will match exactly the sent NAK, although not really that helpful. + * + * if NCF is valid, returns TRUE. on error, FALSE is returned. + */ + +bool +pgm_on_ncf ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict source, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != source); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_ncf (sock:%p source:%p skb:%p)", + (const void*)sock, (const void*)source, (const void*)skb); + + if (PGM_UNLIKELY(!pgm_verify_ncf (skb))) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded invalid NCF.")); + source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]++; + return FALSE; + } + + const struct pgm_nak* ncf = (struct pgm_nak*) skb->data; + const struct pgm_nak6* ncf6 = (struct pgm_nak6*)skb->data; + +/* NCF_SRC_NLA may contain our sock unicast NLA, we don't really care */ + struct sockaddr_storage ncf_src_nla; + pgm_nla_to_sockaddr (&ncf->nak_src_nla_afi, (struct sockaddr*)&ncf_src_nla); + +#if 0 + if (PGM(pgm_sockaddr_cmp ((struct sockaddr*)&ncf_src_nla, (struct sockaddr*)&sock->send_addr) != 0)) { + g_trace ("INFO", "Discarded NCF on NLA mismatch."); + peer->cumulative_stats[PGM_PC_RECEIVER_PACKETS_DISCARDED]++; + return FALSE; + } +#endif + +/* NCF_GRP_NLA contains our sock multicast group */ + struct sockaddr_storage ncf_grp_nla; + pgm_nla_to_sockaddr ((AF_INET6 == ncf_src_nla.ss_family) ? &ncf6->nak6_grp_nla_afi : &ncf->nak_grp_nla_afi, (struct sockaddr*)&ncf_grp_nla); + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&ncf_grp_nla, (struct sockaddr*)&sock->send_gsr.gsr_group) != 0)) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded NCF on multicast group mismatch.")); + return FALSE; + } + + const pgm_time_t ncf_rdata_ivl = skb->tstamp + sock->nak_rdata_ivl; + const pgm_time_t ncf_rb_ivl = skb->tstamp + nak_rb_ivl(sock); + int status = pgm_rxw_confirm (source->window, + ntohl (ncf->nak_sqn), + skb->tstamp, + ncf_rdata_ivl, + ncf_rb_ivl); + if (PGM_RXW_UPDATED == status || PGM_RXW_APPENDED == status) + { + const pgm_time_t ncf_ivl = (PGM_RXW_APPENDED == status) ? ncf_rb_ivl : ncf_rdata_ivl; + pgm_timer_lock (sock); + if (pgm_time_after (sock->next_poll, ncf_ivl)) { + sock->next_poll = ncf_ivl; + } + pgm_timer_unlock (sock); + source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]++; + } + +/* check NCF list */ + const uint32_t* ncf_list = NULL; + unsigned ncf_list_len = 0; + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) + { + const struct pgm_opt_length* opt_len = (AF_INET6 == ncf_src_nla.ss_family) ? + (const struct pgm_opt_length*)(ncf6 + 1) : + (const struct pgm_opt_length*)(ncf + 1); + if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed NCF.")); + source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]++; + return FALSE; + } + if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded malformed NCF.")); + source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_NCFS]++; + return FALSE; + } +/* TODO: check for > 16 options & past packet end */ + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); + if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_NAK_LIST) + { + ncf_list = ((const struct pgm_opt_nak_list*)(opt_header + 1))->opt_sqn; + ncf_list_len = ( opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(uint8_t) ) / sizeof(uint32_t); + break; + } + } while (!(opt_header->opt_type & PGM_OPT_END)); + } + + pgm_debug ("NCF contains 1+%d sequence numbers.", ncf_list_len); + while (ncf_list_len) + { + status = pgm_rxw_confirm (source->window, + ntohl (*ncf_list), + skb->tstamp, + ncf_rdata_ivl, + ncf_rb_ivl); + if (PGM_RXW_UPDATED == status || PGM_RXW_APPENDED == status) + source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]++; + ncf_list++; + ncf_list_len--; + } + +/* mark receiver window for flushing on next recv() */ + const pgm_rxw_t* window = source->window; + if (window->cumulative_losses != source->last_cumulative_losses && + !source->pending_link.data) + { + sock->is_reset = TRUE; + source->lost_count = window->cumulative_losses - source->last_cumulative_losses; + source->last_cumulative_losses = window->cumulative_losses; + pgm_peer_set_pending (sock, source); + } + return TRUE; +} + +/* send SPM-request to a new peer, this packet type has no contents + * + * on success, TRUE is returned, if operation would block FALSE is + * returned. + */ + +static +bool +send_spmr ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict source + ) +{ + ssize_t sent; + +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != source); + + pgm_debug ("send_spmr (sock:%p source:%p)", + (const void*)sock, (const void*)source); + + const size_t tpdu_length = sizeof(struct pgm_header); + char buf[ tpdu_length ]; + struct pgm_header* header = (struct pgm_header*)buf; + memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); +/* dport & sport reversed communicating upstream */ + header->pgm_sport = sock->dport; + header->pgm_dport = source->tsi.sport; + header->pgm_type = PGM_SPMR; + header->pgm_options = 0; + header->pgm_tsdu_length = 0; + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + +/* send multicast SPMR TTL 1 */ + sent = pgm_sendto_hops (sock, + FALSE, /* not rate limited */ + FALSE, /* regular socket */ + 1, + header, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len ((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) + return FALSE; + +/* send unicast SPMR with regular TTL */ + sent = pgm_sendto (sock, + FALSE, + FALSE, + header, + tpdu_length, + (struct sockaddr*)&source->local_nla, + pgm_sockaddr_len ((struct sockaddr*)&source->local_nla)); + if (sent < 0 && EAGAIN == errno) + return FALSE; + + sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT] += tpdu_length * 2; + return TRUE; +} + +/* send selective NAK for one sequence number. + * + * on success, TRUE is returned, returns FALSE if would block on operation. + */ + +static +bool +send_nak ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict source, + const uint32_t sequence + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != source); + + pgm_debug ("send_nak (sock:%p peer:%p sequence:%" PRIu32 ")", + (void*)sock, (void*)source, sequence); + + size_t tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); + if (AF_INET6 == source->nla.ss_family) + tpdu_length += sizeof(struct pgm_nak6) - sizeof(struct pgm_nak); + char buf[ tpdu_length ]; + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* nak = (struct pgm_nak* )(header + 1); + struct pgm_nak6* nak6 = (struct pgm_nak6*)(header + 1); + memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); + +/* dport & sport swap over for a nak */ + header->pgm_sport = sock->dport; + header->pgm_dport = source->tsi.sport; + header->pgm_type = PGM_NAK; + header->pgm_options = 0; + header->pgm_tsdu_length = 0; + +/* NAK */ + nak->nak_sqn = htonl (sequence); + +/* source nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&source->nla, (char*)&nak->nak_src_nla_afi); + +/* group nla: we match the NAK NLA to the same as advertised by the source, we might + * be listening to multiple multicast groups + */ + pgm_sockaddr_to_nla ((struct sockaddr*)&source->group_nla, + (AF_INET6 == source->nla.ss_family) ? (char*)&nak6->nak6_grp_nla_afi : (char*)&nak->nak_grp_nla_afi); + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + TRUE, /* with router alert */ + header, + tpdu_length, + (struct sockaddr*)&source->nla, + pgm_sockaddr_len((struct sockaddr*)&source->nla)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) + return FALSE; + + source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT]++; + source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT]++; + return TRUE; +} + +/* Send a parity NAK requesting on-demand parity packet generation. + * + * on success, TRUE is returned, returns FALSE if operation would block. + */ + +static +bool +send_parity_nak ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict source, + const uint32_t nak_tg_sqn, /* transmission group (shifted) */ + const uint32_t nak_pkt_cnt /* count of parity packets to request */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != source); + pgm_assert (nak_pkt_cnt > 0); + + pgm_debug ("send_parity_nak (sock:%p source:%p nak-tg-sqn:%" PRIu32 " nak-pkt-cnt:%" PRIu32 ")", + (void*)sock, (void*)source, nak_tg_sqn, nak_pkt_cnt); + + size_t tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); + if (AF_INET6 == source->nla.ss_family) + tpdu_length += sizeof(struct pgm_nak6) - sizeof(struct pgm_nak); + char buf[ tpdu_length ]; + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* nak = (struct pgm_nak* )(header + 1); + struct pgm_nak6* nak6 = (struct pgm_nak6*)(header + 1); + memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); + +/* dport & sport swap over for a nak */ + header->pgm_sport = sock->dport; + header->pgm_dport = source->tsi.sport; + header->pgm_type = PGM_NAK; + header->pgm_options = PGM_OPT_PARITY; /* this is a parity packet */ + header->pgm_tsdu_length = 0; + +/* NAK */ + nak->nak_sqn = htonl (nak_tg_sqn | (nak_pkt_cnt - 1) ); + +/* source nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&source->nla, (char*)&nak->nak_src_nla_afi); + +/* group nla: we match the NAK NLA to the same as advertised by the source, we might + * be listening to multiple multicast groups + */ + pgm_sockaddr_to_nla ((struct sockaddr*)&source->group_nla, + (AF_INET6 == source->nla.ss_family) ? (char*)&nak6->nak6_grp_nla_afi : (char*)&nak->nak_grp_nla_afi ); + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + TRUE, /* with router alert */ + header, + tpdu_length, + (struct sockaddr*)&source->nla, + pgm_sockaddr_len((struct sockaddr*)&source->nla)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) + return FALSE; + + source->cumulative_stats[PGM_PC_RECEIVER_PARITY_NAK_PACKETS_SENT]++; + source->cumulative_stats[PGM_PC_RECEIVER_PARITY_NAKS_SENT]++; + return TRUE; +} + +/* A NAK packet with a OPT_NAK_LIST option extension + * + * on success, TRUE is returned. on error, FALSE is returned. + */ + +static +bool +send_nak_list ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict source, + const struct pgm_sqn_list_t* const restrict sqn_list + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != source); + pgm_assert (NULL != sqn_list); + pgm_assert_cmpuint (sqn_list->len, >, 1); + pgm_assert_cmpuint (sqn_list->len, <=, 63); + +#ifdef RECEIVER_DEBUG + char list[1024]; + sprintf (list, "%" PRIu32, sqn_list->sqn[0]); + for (unsigned i = 1; i < sqn_list->len; i++) { + char sequence[2 + strlen("4294967295")]; + sprintf (sequence, " %" PRIu32, sqn_list->sqn[i]); + strcat (list, sequence); + } + pgm_debug("send_nak_list (sock:%p source:%p sqn-list:[%s])", + (const void*)sock, (const void*)source, list); +#endif + + size_t tpdu_length = sizeof(struct pgm_header) + + sizeof(struct pgm_nak) + + sizeof(struct pgm_opt_length) + /* includes header */ + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ); + if (AF_INET6 == source->nla.ss_family) + tpdu_length += sizeof(struct pgm_nak6) - sizeof(struct pgm_nak); + char buf[ tpdu_length ]; + if (PGM_UNLIKELY(pgm_mem_gc_friendly)) + memset (buf, 0, tpdu_length); + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* nak = (struct pgm_nak* )(header + 1); + struct pgm_nak6* nak6 = (struct pgm_nak6*)(header + 1); + memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); + +/* dport & sport swap over for a nak */ + header->pgm_sport = sock->dport; + header->pgm_dport = source->tsi.sport; + header->pgm_type = PGM_NAK; + header->pgm_options = PGM_OPT_PRESENT | PGM_OPT_NETWORK; + header->pgm_tsdu_length = 0; + +/* NAK */ + nak->nak_sqn = htonl (sqn_list->sqn[0]); + +/* source nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&source->nla, (char*)&nak->nak_src_nla_afi); + +/* group nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&source->group_nla, + (AF_INET6 == source->nla.ss_family) ? (char*)&nak6->nak6_grp_nla_afi : (char*)&nak->nak_grp_nla_afi); + +/* OPT_NAK_LIST */ + struct pgm_opt_length* opt_len = (AF_INET6 == source->nla.ss_family) ? (struct pgm_opt_length*)(nak6 + 1) : (struct pgm_opt_length*)(nak + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ); + struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); + opt_nak_list->opt_reserved = 0; + + for (unsigned i = 1; i < sqn_list->len; i++) + opt_nak_list->opt_sqn[i-1] = htonl (sqn_list->sqn[i]); + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + FALSE, /* regular socket */ + header, + tpdu_length, + (struct sockaddr*)&source->nla, + pgm_sockaddr_len((struct sockaddr*)&source->nla)); + if ( sent != (ssize_t)tpdu_length ) + return FALSE; + + source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT]++; + source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT] += 1 + sqn_list->len; + return TRUE; +} + +/* send ACK upstream to source + * + * on success, TRUE is returned. on error, FALSE is returned. + */ + +static +bool +send_ack ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict source, + const pgm_time_t now + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (sock->use_pgmcc); + pgm_assert (NULL != source); + + pgm_debug ("send_ack (sock:%p source:%p now:%" PGM_TIME_FORMAT ")", + (const void*)sock, (const void*)source, now); + + size_t tpdu_length = sizeof(struct pgm_header) + + sizeof(struct pgm_ack) + + sizeof(struct pgm_opt_length) + /* includes header */ + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_pgmcc_feedback); + if (AF_INET6 == sock->send_addr.ss_family) + tpdu_length += sizeof(struct pgm_opt6_pgmcc_feedback) - sizeof(struct pgm_opt_pgmcc_feedback); + char buf[ tpdu_length ]; + if (PGM_UNLIKELY(pgm_mem_gc_friendly)) + memset (buf, 0, tpdu_length); + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_ack* ack = (struct pgm_ack*)(header + 1); + memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); + +/* dport & sport swap over for an ack */ + header->pgm_sport = sock->dport; + header->pgm_dport = source->tsi.sport; + header->pgm_type = PGM_ACK; + header->pgm_options = PGM_OPT_PRESENT; + header->pgm_tsdu_length = 0; + +/* ACK */ + ack->ack_rx_max = htonl (pgm_rxw_lead (source->window)); + ack->ack_bitmap = htonl (source->window->bitmap); + +/* OPT_PGMCC_FEEDBACK */ + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(ack + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + (AF_INET6 == sock->send_addr.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_feedback) : + sizeof(struct pgm_opt_pgmcc_feedback) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_PGMCC_FEEDBACK | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + ( (AF_INET6 == sock->send_addr.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_feedback) : + sizeof(struct pgm_opt_pgmcc_feedback) ); + struct pgm_opt_pgmcc_feedback* opt_pgmcc_feedback = (struct pgm_opt_pgmcc_feedback*)(opt_header + 1); + opt_pgmcc_feedback->opt_reserved = 0; + + const uint32_t t = source->ack_last_tstamp + pgm_to_msecs( now - source->last_data_tstamp ); + opt_pgmcc_feedback->opt_tstamp = htonl (t); + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->send_addr, (char*)&opt_pgmcc_feedback->opt_nla_afi); + opt_pgmcc_feedback->opt_loss_rate = htons ((uint16_t)source->window->data_loss); + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + FALSE, /* regular socket */ + header, + tpdu_length, + (struct sockaddr*)&source->nla, + pgm_sockaddr_len((struct sockaddr*)&source->nla)); + if ( sent != (ssize_t)tpdu_length ) + return FALSE; + + source->cumulative_stats[PGM_PC_RECEIVER_ACKS_SENT]++; + return TRUE; +} + +/* check all receiver windows for ACKer elections, on expiration send an ACK. + * + * returns TRUE on success, returns FALSE if operation would block. + */ + +static +bool +ack_rb_state ( + pgm_peer_t* peer, + const pgm_time_t now + ) +{ +/* pre-conditions */ + pgm_assert (NULL != peer); + pgm_assert (peer->sock->use_pgmcc); + + pgm_debug ("ack_rb_state (peer:%p now:%" PGM_TIME_FORMAT ")", + (const void*)peer, now); + + pgm_rxw_t* window = peer->window; + pgm_sock_t* sock = peer->sock; + pgm_list_t* list; + + list = window->ack_backoff_queue.tail; + if (!list) { + pgm_assert (window->ack_backoff_queue.head == NULL); + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Backoff queue is empty in ack_rb_state.")); + return TRUE; + } else { + pgm_assert (window->ack_backoff_queue.head != NULL); + } + +/* have not learned this peers NLA */ + const bool is_valid_nla = (0 != peer->nla.ss_family); + + while (list) + { + pgm_list_t* next_list_el = list->prev; + +/* check for ACK backoff expiration */ + if (pgm_time_after_eq(now, peer->ack_rb_expiry)) + { +/* unreliable delivery */ + _pgm_remove_ack (peer); + + if (PGM_UNLIKELY(!is_valid_nla)) { + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Unable to send ACK due to unknown NLA.")); + list = next_list_el; + continue; + } + + pgm_assert (!pgm_sockaddr_is_addr_unspecified ((struct sockaddr*)&peer->nla)); + + if (!send_ack (sock, peer, now)) + return FALSE; + } + else + { /* packet expires some time later */ + break; + } + + list = next_list_el; + } + + if (window->ack_backoff_queue.length == 0) + { + pgm_assert ((struct rxw_packet*)window->ack_backoff_queue.head == NULL); + pgm_assert ((struct rxw_packet*)window->ack_backoff_queue.tail == NULL); + } + else + { + pgm_assert ((struct rxw_packet*)window->ack_backoff_queue.head != NULL); + pgm_assert ((struct rxw_packet*)window->ack_backoff_queue.tail != NULL); + } + + if (window->ack_backoff_queue.tail) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiry set in %f seconds."), + pgm_to_secsf(next_ack_rb_expiry(window) - now)); + } + else + { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("ACK backoff queue empty.")); + } + return TRUE; +} + +/* check all receiver windows for packets in BACK-OFF_STATE, on expiration send a NAK. + * update sock::next_nak_rb_timestamp for next expiration time. + * + * peer object is locked before entry. + * + * returns TRUE on success, returns FALSE if operation would block. + */ + +static +bool +nak_rb_state ( + pgm_peer_t* peer, + const pgm_time_t now + ) +{ +/* pre-conditions */ + pgm_assert (NULL != peer); + + pgm_debug ("nak_rb_state (peer:%p now:%" PGM_TIME_FORMAT ")", + (const void*)peer, now); + + pgm_rxw_t* window = peer->window; + pgm_sock_t* sock = peer->sock; + pgm_list_t* list; + struct pgm_sqn_list_t nak_list = { .len = 0 }; + +/* send all NAKs first, lack of data is blocking contiguous processing and its + * better to get the notification out a.s.a.p. even though it might be waiting + * in a kernel queue. + * + * alternative: after each packet check for incoming data and return to the + * event loop. bias for shorter loops as retry count increases. + */ + list = window->nak_backoff_queue.tail; + if (!list) { + pgm_assert (window->nak_backoff_queue.head == NULL); + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Backoff queue is empty in nak_rb_state.")); + return TRUE; + } else { + pgm_assert (window->nak_backoff_queue.head != NULL); + } + + unsigned dropped_invalid = 0; + +/* have not learned this peers NLA */ + const bool is_valid_nla = 0 != peer->nla.ss_family; + +/* TODO: process BOTH selective and parity NAKs? */ + +/* calculate current transmission group for parity enabled peers */ + if (peer->has_ondemand_parity) + { + const uint32_t tg_sqn_mask = 0xffffffff << window->tg_sqn_shift; + +/* NAKs only generated previous to current transmission group */ + const uint32_t current_tg_sqn = window->lead & tg_sqn_mask; + + uint32_t nak_tg_sqn = 0; + uint32_t nak_pkt_cnt = 0; + +/* parity NAK generation */ + + while (list) + { + pgm_list_t* next_list_el = list->prev; + struct pgm_sk_buff_t* skb = (struct pgm_sk_buff_t*)list; + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + +/* check this packet for state expiration */ + if (pgm_time_after_eq (now, state->timer_expiry)) + { + if (PGM_UNLIKELY(!is_valid_nla)) { + dropped_invalid++; + pgm_rxw_lost (window, skb->sequence); +/* mark receiver window for flushing on next recv() */ + pgm_peer_set_pending (sock, peer); + list = next_list_el; + continue; + } + +/* TODO: parity nak lists */ + const uint32_t tg_sqn = skb->sequence & tg_sqn_mask; + if ( ( nak_pkt_cnt && tg_sqn == nak_tg_sqn ) || + ( !nak_pkt_cnt && tg_sqn != current_tg_sqn ) ) + { + pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_NCF); + + if (!nak_pkt_cnt++) + nak_tg_sqn = tg_sqn; + state->nak_transmit_count++; + +#ifdef PGM_ABSOLUTE_EXPIRY + state->timer_expiry += sock->nak_rpt_ivl; + while (pgm_time_after_eq (now, state->timer_expiry)) { + state->timer_expiry += sock->nak_rpt_ivl; + state->ncf_retry_count++; + } +#else + state->timer_expiry = now + sock->nak_rpt_ivl; +#endif + pgm_timer_lock (sock); + if (pgm_time_after (sock->next_poll, state->timer_expiry)) + sock->next_poll = state->timer_expiry; + pgm_timer_unlock (sock); + } + else + { /* different transmission group */ + break; + } + } + else + { /* packet expires some time later */ + break; + } + + list = next_list_el; + } + + if (nak_pkt_cnt && !send_parity_nak (sock, peer, nak_tg_sqn, nak_pkt_cnt)) + return FALSE; + } + else + { + +/* select NAK generation */ + + while (list) + { + pgm_list_t* next_list_el = list->prev; + struct pgm_sk_buff_t* skb = (struct pgm_sk_buff_t*)list; + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + +/* check this packet for state expiration */ + if (pgm_time_after_eq(now, state->timer_expiry)) + { + if (PGM_UNLIKELY(!is_valid_nla)) { + dropped_invalid++; + pgm_rxw_lost (window, skb->sequence); +/* mark receiver window for flushing on next recv() */ + pgm_peer_set_pending (sock, peer); + list = next_list_el; + continue; + } + + pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_NCF); + nak_list.sqn[nak_list.len++] = skb->sequence; + state->nak_transmit_count++; + +/* we have two options here, calculate the expiry time in the new state relative to the current + * state execution time, skipping missed expirations due to delay in state processing, or base + * from the actual current time. + */ +#ifdef PGM_ABSOLUTE_EXPIRY + state->timer_expiry += sock->nak_rpt_ivl; + while (pgm_time_after_eq(now, state->timer_expiry)){ + state->timer_expiry += sock->nak_rpt_ivl; + state->ncf_retry_count++; + } +#else + state->timer_expiry = now + sock->nak_rpt_ivl; +pgm_trace(PGM_LOG_ROLE_NETWORK,_("nak_rpt_expiry in %f seconds."), + pgm_to_secsf( state->timer_expiry - now ) ); +#endif + pgm_timer_lock (sock); + if (pgm_time_after (sock->next_poll, state->timer_expiry)) + sock->next_poll = state->timer_expiry; + pgm_timer_unlock (sock); + + if (nak_list.len == PGM_N_ELEMENTS(nak_list.sqn)) { + if (sock->can_send_nak && !send_nak_list (sock, peer, &nak_list)) + return FALSE; + nak_list.len = 0; + } + } + else + { /* packet expires some time later */ + break; + } + + list = next_list_el; + } + + if (sock->can_send_nak && nak_list.len) + { + if (nak_list.len > 1 && !send_nak_list (sock, peer, &nak_list)) + return FALSE; + else if (!send_nak (sock, peer, nak_list.sqn[0])) + return FALSE; + } + + } + + if (PGM_UNLIKELY(dropped_invalid)) + { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Dropped %u messages due to invalid NLA."), dropped_invalid); + +/* mark receiver window for flushing on next recv() */ + if (window->cumulative_losses != peer->last_cumulative_losses && + !peer->pending_link.data) + { + sock->is_reset = TRUE; + peer->lost_count = window->cumulative_losses - peer->last_cumulative_losses; + peer->last_cumulative_losses = window->cumulative_losses; + pgm_peer_set_pending (sock, peer); + } + } + + if (window->nak_backoff_queue.length == 0) + { + pgm_assert ((struct rxw_packet*)window->nak_backoff_queue.head == NULL); + pgm_assert ((struct rxw_packet*)window->nak_backoff_queue.tail == NULL); + } + else + { + pgm_assert ((struct rxw_packet*)window->nak_backoff_queue.head != NULL); + pgm_assert ((struct rxw_packet*)window->nak_backoff_queue.tail != NULL); + } + + if (window->nak_backoff_queue.tail) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiry set in %f seconds."), + pgm_to_secsf(next_nak_rb_expiry(window) - now)); + } + else + { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("NAK backoff queue empty.")); + } + return TRUE; +} + +/* check this peer for NAK state timers, uses the tail of each queue for the nearest + * timer execution. + * + * returns TRUE on complete sweep, returns FALSE if operation would block. + */ + +bool +pgm_check_peer_state ( + pgm_sock_t*const sock, + const pgm_time_t now + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + + pgm_debug ("pgm_check_peer_state (sock:%p now:%" PGM_TIME_FORMAT ")", + (const void*)sock, now); + + if (!sock->peers_list) + return TRUE; + + pgm_list_t* list = sock->peers_list; + do { + pgm_list_t* next = list->next; + pgm_peer_t* peer = list->data; + pgm_rxw_t* window = peer->window; + + if (peer->spmr_expiry) + { + if (pgm_time_after_eq (now, peer->spmr_expiry)) + { + if (sock->can_send_nak) { + if (!send_spmr (sock, peer)) { + return FALSE; + } + peer->spmr_tstamp = now; + } + peer->spmr_expiry = 0; + } + } + + if (window->ack_backoff_queue.tail) + { + pgm_assert (sock->use_pgmcc); + + if (pgm_time_after_eq (now, next_ack_rb_expiry (window))) + if (!ack_rb_state (peer, now)) { + return FALSE; + } + } + + if (window->nak_backoff_queue.tail) + { + if (pgm_time_after_eq (now, next_nak_rb_expiry (window))) + if (!nak_rb_state (peer, now)) { + return FALSE; + } + } + + if (window->wait_ncf_queue.tail) + { + if (pgm_time_after_eq (now, next_nak_rpt_expiry (window))) + nak_rpt_state (peer, now); + } + + if (window->wait_data_queue.tail) + { + if (pgm_time_after_eq (now, next_nak_rdata_expiry (window))) + nak_rdata_state (peer, now); + } + +/* expired, remove from hash table and linked list */ + if (pgm_time_after_eq (now, peer->expiry)) + { + if (peer->pending_link.data) + { + pgm_trace (PGM_LOG_ROLE_SESSION,_("Peer expiration postponed due to committing data, tsi %s"), pgm_tsi_print (&peer->tsi)); + peer->expiry += sock->peer_expiry; + } + else if (window->committed_count) + { + pgm_trace (PGM_LOG_ROLE_SESSION,_("Peer expiration postponed due to committed data, tsi %s"), pgm_tsi_print (&peer->tsi)); + peer->expiry += sock->peer_expiry; + } + else + { + pgm_trace (PGM_LOG_ROLE_SESSION,_("Peer expired, tsi %s"), pgm_tsi_print (&peer->tsi)); + pgm_hashtable_remove (sock->peers_hashtable, &peer->tsi); + sock->peers_list = pgm_list_remove_link (sock->peers_list, &peer->peers_link); + if (sock->last_hash_value == peer) + sock->last_hash_value = NULL; + pgm_peer_unref (peer); + } + } + + list = next; + } while (list); + +/* check for waiting contiguous packets */ + if (sock->peers_pending && !sock->is_pending_read) + { + pgm_debug ("prod rx thread"); + pgm_notify_send (&sock->pending_notify); + sock->is_pending_read = TRUE; + } + return TRUE; +} + +/* find the next state expiration time among the socks peers. + * + * on success, returns the earliest of the expiration parameter or next + * peer expiration time. + */ + +pgm_time_t +pgm_min_receiver_expiry ( + pgm_time_t expiration, /* absolute time */ + pgm_sock_t* sock + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + + pgm_debug ("pgm_min_receiver_expiry (expiration:%" PGM_TIME_FORMAT " sock:%p)", + expiration, (const void*)sock); + + if (!sock->peers_list) + return expiration; + + pgm_list_t* list = sock->peers_list; + do { + pgm_list_t* next = list->next; + pgm_peer_t* peer = (pgm_peer_t*)list->data; + pgm_rxw_t* window = peer->window; + + if (peer->spmr_expiry) + { + if (pgm_time_after_eq (expiration, peer->spmr_expiry)) + expiration = peer->spmr_expiry; + } + + if (window->ack_backoff_queue.tail) + { + pgm_assert (sock->use_pgmcc); + if (pgm_time_after_eq (expiration, next_ack_rb_expiry (window))) + expiration = next_ack_rb_expiry (window); + } + + if (window->nak_backoff_queue.tail) + { + if (pgm_time_after_eq (expiration, next_nak_rb_expiry (window))) + expiration = next_nak_rb_expiry (window); + } + + if (window->wait_ncf_queue.tail) + { + if (pgm_time_after_eq (expiration, next_nak_rpt_expiry (window))) + expiration = next_nak_rpt_expiry (window); + } + + if (window->wait_data_queue.tail) + { + if (pgm_time_after_eq (expiration, next_nak_rdata_expiry (window))) + expiration = next_nak_rdata_expiry (window); + } + + list = next; + } while (list); + + return expiration; +} + +/* check WAIT_NCF_STATE, on expiration move back to BACK-OFF_STATE, on exceeding NAK_NCF_RETRIES + * cancel the sequence number. + */ +static +void +nak_rpt_state ( + pgm_peer_t* peer, + const pgm_time_t now + ) +{ +/* pre-conditions */ + pgm_assert (NULL != peer); + + pgm_debug ("nak_rpt_state (peer:%p now:%" PGM_TIME_FORMAT ")", + (void*)peer, now); + + pgm_rxw_t* window = peer->window; + pgm_sock_t* sock = peer->sock; + pgm_list_t* list = window->wait_ncf_queue.tail; + + unsigned dropped_invalid = 0; + unsigned dropped = 0; + +/* have not learned this peers NLA */ + const bool is_valid_nla = 0 != peer->nla.ss_family; + + while (list) + { + pgm_list_t* next_list_el = list->prev; + struct pgm_sk_buff_t* skb = (struct pgm_sk_buff_t*)list; + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + +/* check this packet for state expiration */ + if (pgm_time_after_eq (now, state->timer_expiry)) + { + if (PGM_UNLIKELY(!is_valid_nla)) { + dropped_invalid++; + pgm_rxw_lost (window, skb->sequence); +/* mark receiver window for flushing on next recv() */ + pgm_peer_set_pending (sock, peer); + list = next_list_el; + continue; + } + + if (++state->ncf_retry_count >= sock->nak_ncf_retries) + { + dropped++; + cancel_skb (sock, peer, skb, now); + peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_NCF_RETRIES_EXCEEDED]++; + } + else + { +/* retry */ +// state->timer_expiry += nak_rb_ivl(sock); + state->timer_expiry = now + nak_rb_ivl (sock); + pgm_rxw_state (window, skb, PGM_PKT_STATE_BACK_OFF); + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("NCF retry #%u attempt %u/%u."), skb->sequence, state->ncf_retry_count, sock->nak_ncf_retries); + } + } + else + { +/* packet expires some time later */ + pgm_trace(PGM_LOG_ROLE_RX_WINDOW,_("NCF retry #%u is delayed %f seconds."), + skb->sequence, pgm_to_secsf (state->timer_expiry - now)); + break; + } + + list = next_list_el; + } + + if (window->wait_ncf_queue.length == 0) + { + pgm_assert ((pgm_rxw_state_t*)window->wait_ncf_queue.head == NULL); + pgm_assert ((pgm_rxw_state_t*)window->wait_ncf_queue.tail == NULL); + } + else + { + pgm_assert ((pgm_rxw_state_t*)window->wait_ncf_queue.head != NULL); + pgm_assert ((pgm_rxw_state_t*)window->wait_ncf_queue.tail != NULL); + } + + if (PGM_UNLIKELY(dropped_invalid)) { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Dropped %u messages due to invalid NLA."), dropped_invalid); + } + + if (PGM_UNLIKELY(dropped)) { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Dropped %u messages due to ncf cancellation, " + "rxw_sqns %" PRIu32 + " bo %" PRIu32 + " ncf %" PRIu32 + " wd %" PRIu32 + " lost %" PRIu32 + " frag %" PRIu32), + dropped, + pgm_rxw_length (window), + window->nak_backoff_queue.length, + window->wait_ncf_queue.length, + window->wait_data_queue.length, + window->lost_count, + window->fragment_count); + } + +/* mark receiver window for flushing on next recv() */ + if (PGM_UNLIKELY(window->cumulative_losses != peer->last_cumulative_losses && + !peer->pending_link.data)) + { + sock->is_reset = TRUE; + peer->lost_count = window->cumulative_losses - peer->last_cumulative_losses; + peer->last_cumulative_losses = window->cumulative_losses; + pgm_peer_set_pending (sock, peer); + } + + if (window->wait_ncf_queue.tail) + { + if (next_nak_rpt_expiry (window) > now) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiry set in %f seconds."), pgm_to_secsf (next_nak_rpt_expiry (window) - now)); + } else { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiry set in -%f seconds."), pgm_to_secsf (now - next_nak_rpt_expiry (window))); + } + } + else + { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Wait ncf queue empty.")); + } +} + +/* check WAIT_DATA_STATE, on expiration move back to BACK-OFF_STATE, on exceeding NAK_DATA_RETRIES + * canel the sequence number. + */ +static +void +nak_rdata_state ( + pgm_peer_t* peer, + const pgm_time_t now + ) +{ +/* pre-conditions */ + pgm_assert (NULL != peer); + + pgm_debug ("nak_rdata_state (peer:%p now:%" PGM_TIME_FORMAT ")", + (const void*)peer, now); + + pgm_rxw_t* window = peer->window; + pgm_sock_t* sock = peer->sock; + pgm_list_t* list = window->wait_data_queue.tail; + + unsigned dropped_invalid = 0; + unsigned dropped = 0; + +/* have not learned this peers NLA */ + const bool is_valid_nla = 0 != peer->nla.ss_family; + + while (list) + { + pgm_list_t* next_list_el = list->prev; + struct pgm_sk_buff_t* rdata_skb = (struct pgm_sk_buff_t*)list; + pgm_assert (NULL != rdata_skb); + pgm_rxw_state_t* rdata_state = (pgm_rxw_state_t*)&rdata_skb->cb; + +/* check this packet for state expiration */ + if (pgm_time_after_eq (now, rdata_state->timer_expiry)) + { + if (PGM_UNLIKELY(!is_valid_nla)) { + dropped_invalid++; + pgm_rxw_lost (window, rdata_skb->sequence); +/* mark receiver window for flushing on next recv() */ + pgm_peer_set_pending (sock, peer); + list = next_list_el; + continue; + } + + if (++rdata_state->data_retry_count >= sock->nak_data_retries) + { + dropped++; + cancel_skb (sock, peer, rdata_skb, now); + peer->cumulative_stats[PGM_PC_RECEIVER_NAKS_FAILED_DATA_RETRIES_EXCEEDED]++; + list = next_list_el; + continue; + } + +// rdata_state->timer_expiry += nak_rb_ivl(sock); + rdata_state->timer_expiry = now + nak_rb_ivl (sock); + pgm_rxw_state (window, rdata_skb, PGM_PKT_STATE_BACK_OFF); + +/* retry back to back-off state */ + pgm_trace(PGM_LOG_ROLE_RX_WINDOW,_("Data retry #%u attempt %u/%u."), rdata_skb->sequence, rdata_state->data_retry_count, sock->nak_data_retries); + } + else + { /* packet expires some time later */ + break; + } + + + list = next_list_el; + } + + if (window->wait_data_queue.length == 0) + { + pgm_assert (NULL == (pgm_rxw_state_t*)window->wait_data_queue.head); + pgm_assert (NULL == (pgm_rxw_state_t*)window->wait_data_queue.tail); + } + else + { + pgm_assert (NULL != (pgm_rxw_state_t*)window->wait_data_queue.head); + pgm_assert (NULL != (pgm_rxw_state_t*)window->wait_data_queue.tail); + } + + if (PGM_UNLIKELY(dropped_invalid)) { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Dropped %u messages due to invalid NLA."), dropped_invalid); + } + + if (PGM_UNLIKELY(dropped)) { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Dropped %u messages due to data cancellation."), dropped); + } + +/* mark receiver window for flushing on next recv() */ + if (PGM_UNLIKELY(window->cumulative_losses != peer->last_cumulative_losses && + !peer->pending_link.data)) + { + sock->is_reset = TRUE; + peer->lost_count = window->cumulative_losses - peer->last_cumulative_losses; + peer->last_cumulative_losses = window->cumulative_losses; + pgm_peer_set_pending (sock, peer); + } + + if (window->wait_data_queue.tail) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiry set in %f seconds."), pgm_to_secsf (next_nak_rdata_expiry (window) - now)); + } else { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Wait data queue empty.")); + } +} + +/* ODATA or RDATA packet with any of the following options: + * + * OPT_FRAGMENT - this TPDU part of a larger APDU. + * + * Ownership of skb is taken and must be passed to the receive window or destroyed. + * + * returns TRUE is skb has been replaced, FALSE is remains unchanged and can be recycled. + */ + +bool +pgm_on_data ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict source, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != source); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_data (sock:%p source:%p skb:%p)", + (void*)sock, (void*)source, (void*)skb); + + unsigned msg_count = 0; + const pgm_time_t nak_rb_expiry = skb->tstamp + nak_rb_ivl (sock); + pgm_time_t ack_rb_expiry = 0; + const unsigned tsdu_length = ntohs (skb->pgm_header->pgm_tsdu_length); + + skb->pgm_data = skb->data; + + const unsigned opt_total_length = (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) ? ntohs(*(uint16_t*)( (char*)( skb->pgm_data + 1 ) + sizeof(uint16_t))) : 0; + +/* advance data pointer to payload */ + pgm_skb_pull (skb, sizeof(struct pgm_data) + opt_total_length); + + if (opt_total_length > 0 && /* there are options */ + get_pgm_options (skb) && /* valid options */ + sock->use_pgmcc && /* PGMCC is enabled */ + NULL != skb->pgm_opt_pgmcc_data && /* PGMCC options */ + 0 == source->ack_rb_expiry) /* not partaking in a current election */ + { + ack_rb_expiry = skb->tstamp + ack_rb_ivl (sock); + } + + const int add_status = pgm_rxw_add (source->window, skb, skb->tstamp, nak_rb_expiry); + +/* skb reference is now invalid */ + bool flush_naks = FALSE; + + switch (add_status) { + case PGM_RXW_MISSING: + flush_naks = TRUE; +/* fall through */ + case PGM_RXW_INSERTED: + case PGM_RXW_APPENDED: + msg_count++; + break; + + case PGM_RXW_DUPLICATE: + source->cumulative_stats[PGM_PC_RECEIVER_DUP_DATAS]++; + goto discarded; + + case PGM_RXW_MALFORMED: + source->cumulative_stats[PGM_PC_RECEIVER_MALFORMED_ODATA]++; +/* fall through */ + case PGM_RXW_BOUNDS: +discarded: + return FALSE; + + default: pgm_assert_not_reached(); break; + } + +/* valid data */ + PGM_HISTOGRAM_COUNTS("Rx.DataBytesReceived", tsdu_length); + source->cumulative_stats[PGM_PC_RECEIVER_DATA_BYTES_RECEIVED] += tsdu_length; + source->cumulative_stats[PGM_PC_RECEIVER_DATA_MSGS_RECEIVED] += msg_count; + +/* congestion control */ + if (0 != ack_rb_expiry) + { +/* save source timestamp and local timestamp for RTT calculation */ + source->ack_last_tstamp = ntohl (skb->pgm_opt_pgmcc_data->opt_tstamp); + source->last_data_tstamp = skb->tstamp; + if (_pgm_is_acker (source, skb)) + { + if (PGM_UNLIKELY(pgm_sockaddr_is_addr_unspecified ((struct sockaddr*)&source->nla))) + { + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Unable to send ACK due to unknown NLA.")); + } + else if (PGM_UNLIKELY(!send_ack (sock, source, skb->tstamp))) + { + pgm_debug ("send_ack failed"); + } + ack_rb_expiry = 0; + } + else if (_pgm_is_acker_election (skb)) + { + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("ACKer election.")); + _pgm_add_ack (source, ack_rb_expiry); + } + else if (0 != source->window->ack_backoff_queue.length) + { +/* purge ACK backoff queue as host is not elected ACKer */ + _pgm_remove_ack (source); + ack_rb_expiry = 0; + } + else + { +/* no election, not the elected ACKer, no outstanding ACKs */ + ack_rb_expiry = 0; + } + } + + if (flush_naks || 0 != ack_rb_expiry) { +/* flush out 1st time nak packets */ + pgm_timer_lock (sock); + if (flush_naks && pgm_time_after (sock->next_poll, nak_rb_expiry)) + sock->next_poll = nak_rb_expiry; + if (0 != ack_rb_expiry && pgm_time_after (sock->next_poll, ack_rb_expiry)) + sock->next_poll = ack_rb_expiry; + pgm_timer_unlock (sock); + } + return TRUE; +} + +/* POLLs are generated by PGM Parents (Sources or Network Elements). + * + * returns TRUE on valid packet, FALSE on invalid packet. + */ + +bool +pgm_on_poll ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict source, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != source); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_poll (sock:%p source:%p skb:%p)", + (void*)sock, (void*)source, (void*)skb); + + if (PGM_UNLIKELY(!pgm_verify_poll (skb))) { + pgm_trace(PGM_LOG_ROLE_NETWORK,_("Discarded invalid POLL.")); + return FALSE; + } + + struct pgm_poll* poll4 = (struct pgm_poll*) skb->data; + struct pgm_poll6* poll6 = (struct pgm_poll6*)skb->data; + uint32_t poll_rand; + memcpy (&poll_rand, (AFI_IP6 == ntohs (poll4->poll_nla_afi)) ? poll6->poll6_rand : poll4->poll_rand, sizeof(poll_rand)); + const uint32_t poll_mask = (AFI_IP6 == ntohs (poll4->poll_nla_afi)) ? ntohl (poll6->poll6_mask) : ntohl (poll4->poll_mask); + +/* Check for probability match */ + if (poll_mask && + (sock->rand_node_id & poll_mask) != poll_rand) + { +/* discard early */ + return FALSE; + } + +/* scoped per path nla + * TODO: manage list of pollers per peer + */ + const uint32_t poll_sqn = ntohl (poll4->poll_sqn); + const uint16_t poll_round = ntohs (poll4->poll_round); + +/* Check for new poll round */ + if (poll_round && + poll_sqn != source->last_poll_sqn) + { + return FALSE; + } + +/* save sequence and round of valid poll */ + source->last_poll_sqn = poll_sqn; + source->last_poll_round = poll_round; + + const uint16_t poll_s_type = ntohs (poll4->poll_s_type); + +/* Check poll type */ + switch (poll_s_type) { + case PGM_POLL_GENERAL: + return on_general_poll (sock, source, skb); + + case PGM_POLL_DLR: + return on_dlr_poll (sock, source, skb); + + default: +/* unknown sub-type, discard */ + break; + } + + return FALSE; +} + +/* Used to count PGM children */ + +static +bool +on_general_poll ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict source, + struct pgm_sk_buff_t* const restrict skb + ) +{ + struct pgm_poll* poll4 = (struct pgm_poll*) skb->data; + struct pgm_poll6* poll6 = (struct pgm_poll6*)skb->data; + +/* TODO: cancel any pending poll-response */ + +/* defer response based on provided back-off interval */ + const uint32_t poll_bo_ivl = (AFI_IP6 == ntohs (poll4->poll_nla_afi)) ? ntohl (poll6->poll6_bo_ivl) : ntohl (poll4->poll_bo_ivl); + source->polr_expiry = skb->tstamp + pgm_rand_int_range (&sock->rand_, 0, poll_bo_ivl); + pgm_nla_to_sockaddr (&poll4->poll_nla_afi, (struct sockaddr*)&source->poll_nla); +/* TODO: schedule poll-response */ + + return TRUE; +} + +/* Used to count off-tree DLRs */ + +static +bool +on_dlr_poll ( + PGM_GNUC_UNUSED pgm_sock_t* const restrict sock, + PGM_GNUC_UNUSED pgm_peer_t* const restrict source, + PGM_GNUC_UNUSED struct pgm_sk_buff_t* const restrict skb + ) +{ +/* we are not a DLR */ + return FALSE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/receiver.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/receiver.c.c89.patch new file mode 100644 index 0000000..a8c3e6d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/receiver.c.c89.patch @@ -0,0 +1,887 @@ +--- receiver.c 2010-08-05 11:18:06.000000000 +0800 ++++ receiver.c89 2010-08-05 11:39:03.000000000 +0800 +@@ -71,8 +71,10 @@ + pgm_assert (NULL != window); + pgm_assert (NULL != window->ack_backoff_queue.tail); + ++ { + const struct pgm_peer_t* peer = (const struct pgm_peer_t*)window->ack_backoff_queue.tail; + return peer->ack_rb_expiry; ++ } + } + + static inline +@@ -84,9 +86,11 @@ + pgm_assert (NULL != window); + pgm_assert (NULL != window->nak_backoff_queue.tail); + ++ { + const struct pgm_sk_buff_t* skb = (const struct pgm_sk_buff_t*)window->nak_backoff_queue.tail; + const pgm_rxw_state_t* state = (const pgm_rxw_state_t*)&skb->cb; + return state->timer_expiry; ++ } + } + + static inline +@@ -98,9 +102,11 @@ + pgm_assert (NULL != window); + pgm_assert (NULL != window->wait_ncf_queue.tail); + ++ { + const struct pgm_sk_buff_t* skb = (const struct pgm_sk_buff_t*)window->wait_ncf_queue.tail; + const pgm_rxw_state_t* state = (const pgm_rxw_state_t*)&skb->cb; + return state->timer_expiry; ++ } + } + + static inline +@@ -112,9 +118,11 @@ + pgm_assert (NULL != window); + pgm_assert (NULL != window->wait_data_queue.tail); + ++ { + const struct pgm_sk_buff_t* skb = (const struct pgm_sk_buff_t*)window->wait_data_queue.tail; + const pgm_rxw_state_t* state = (const pgm_rxw_state_t*)&skb->cb; + return state->timer_expiry; ++ } + } + + /* calculate ACK_RB_IVL. +@@ -127,9 +135,9 @@ + { + /* pre-conditions */ + pgm_assert (NULL != sock); +- pgm_assert_cmpuint (sock->ack_bo_ivl, >, 1); ++ pgm_assert_cmpuint ((unsigned int)sock->ack_bo_ivl, >, 1); + +- return pgm_rand_int_range (&sock->rand_, 1 /* us */, sock->ack_bo_ivl); ++ return pgm_rand_int_range (&sock->rand_, 1 /* us */, (unsigned int)sock->ack_bo_ivl); + } + + /* calculate NAK_RB_IVL as random time interval 1 - NAK_BO_IVL. +@@ -142,9 +150,9 @@ + { + /* pre-conditions */ + pgm_assert (NULL != sock); +- pgm_assert_cmpuint (sock->nak_bo_ivl, >, 1); ++ pgm_assert_cmpuint ((unsigned int)sock->nak_bo_ivl, >, 1); + +- return pgm_rand_int_range (&sock->rand_, 1 /* us */, sock->nak_bo_ivl); ++ return pgm_rand_int_range (&sock->rand_, 1 /* us */, (unsigned int)sock->nak_bo_ivl); + } + + /* mark sequence as recovery failed. +@@ -162,11 +170,12 @@ + pgm_assert (NULL != sock); + pgm_assert (NULL != peer); + pgm_assert (NULL != skb); +- pgm_assert_cmpuint (now, >=, skb->tstamp); ++ pgm_assert_cmpuint ((unsigned int)now, >=, (unsigned int)skb->tstamp); + + pgm_trace (PGM_LOG_ROLE_RX_WINDOW, _("Lost data #%u due to cancellation."), skb->sequence); + +- const uint32_t fail_time = now - skb->tstamp; ++ { ++ const uint32_t fail_time = (uint32_t)(now - skb->tstamp); + if (!peer->max_fail_time) + peer->max_fail_time = peer->min_fail_time = fail_time; + else if (fail_time > peer->max_fail_time) +@@ -176,6 +185,7 @@ + + pgm_rxw_lost (peer->window, skb->sequence); + PGM_HISTOGRAM_TIMES("Rx.FailTime", fail_time); ++ } + + /* mark receiver window for flushing on next recv() */ + pgm_peer_set_pending (sock, peer); +@@ -214,6 +224,7 @@ + pgm_assert (NULL != skb); + pgm_assert (NULL != skb->pgm_opt_pgmcc_data); + ++ { + const unsigned acker_afi = ntohs (skb->pgm_opt_pgmcc_data->opt_nla_afi); + switch (acker_afi) { + case AFI_IP: +@@ -230,6 +241,7 @@ + } + + return FALSE; ++ } + } + + /* add state for an ACK on a data packet. +@@ -316,6 +328,7 @@ + pgm_assert (NULL != skb); + pgm_assert (NULL != skb->pgm_data); + ++ { + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(skb->pgm_data + 1); + bool found_opt = FALSE; + +@@ -351,6 +364,7 @@ + + } while (!(opt_header->opt_type & PGM_OPT_END)); + return found_opt; ++ } + } + + /* a peer in the context of the sock is another party on the network sending PGM +@@ -381,11 +395,13 @@ + pgm_assert (dst_addrlen > 0); + + #ifdef PGM_DEBUG ++ { + char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop (src_addr, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (dst_addr, daddr, sizeof(daddr)); + pgm_debug ("pgm_new_peer (sock:%p tsi:%s src-addr:%s src-addrlen:%u dst-addr:%s dst-addrlen:%u)", + (void*)sock, pgm_tsi_print (tsi), saddr, (unsigned)src_addrlen, daddr, (unsigned)dst_addrlen); ++ } + #endif + + peer = pgm_new0 (pgm_peer_t, 1); +@@ -409,10 +425,12 @@ + + /* add peer to hash table and linked list */ + pgm_rwlock_writer_lock (&sock->peers_lock); ++ { + pgm_peer_t* entry = _pgm_peer_ref (peer); + pgm_hashtable_insert (sock->peers_hashtable, &peer->tsi, entry); + peer->peers_link.data = peer; + sock->peers_list = pgm_list_prepend_link (sock->peers_list, &peer->peers_link); ++ } + pgm_rwlock_writer_unlock (&sock->peers_lock); + + pgm_timer_lock (sock); +@@ -455,6 +473,7 @@ + pgm_peer_t* peer = sock->peers_pending->data; + if (peer->last_commit && peer->last_commit < sock->last_commit) + pgm_rxw_remove_commit (peer->window); ++ { + const ssize_t peer_bytes = pgm_rxw_readv (peer->window, pmsg, msg_end - *pmsg + 1); + + if (peer->last_cumulative_losses != ((pgm_rxw_t*)peer->window)->cumulative_losses) +@@ -481,6 +500,7 @@ + } + /* clear this reference and move to next */ + sock->peers_pending = pgm_slist_remove_first (sock->peers_pending); ++ } + } + + return retval; +@@ -537,6 +557,7 @@ + pgm_assert (NULL != source); + pgm_assert (NULL != msgv); + ++ { + struct pgm_sk_buff_t* error_skb = pgm_alloc_skb (0); + error_skb->sock = sock; + error_skb->tstamp = pgm_time_update_now (); +@@ -544,6 +565,7 @@ + error_skb->sequence = source->lost_count; + msgv->msgv_skb[0] = error_skb; + msgv->msgv_len = 1; ++ } + } + + /* SPM indicate start of a session, continued presence of a session, or flushing final packets +@@ -573,6 +595,7 @@ + return FALSE; + } + ++ { + const struct pgm_spm* spm = (struct pgm_spm*) skb->data; + const struct pgm_spm6* spm6 = (struct pgm_spm6*)skb->data; + const uint32_t spm_sqn = ntohl (spm->spm_sqn); +@@ -587,6 +610,7 @@ + source->spm_sqn = spm_sqn; + + /* update receive window */ ++ { + const pgm_time_t nak_rb_expiry = skb->tstamp + nak_rb_ivl (sock); + const unsigned naks = pgm_rxw_update (source->window, + ntohl (spm->spm_lead), +@@ -601,6 +625,7 @@ + } + + /* mark receiver window for flushing on next recv() */ ++ { + const pgm_rxw_t* window = source->window; + if (window->cumulative_losses != source->last_cumulative_losses && + !source->pending_link.data) +@@ -610,6 +635,8 @@ + source->last_cumulative_losses = window->cumulative_losses; + pgm_peer_set_pending (sock, source); + } ++ } ++ } + } + else + { /* does not advance SPM sequence number */ +@@ -637,6 +664,7 @@ + return FALSE; + } + /* TODO: check for > 16 options & past packet end */ ++ { + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); +@@ -650,6 +678,7 @@ + return FALSE; + } + ++ { + const uint32_t parity_prm_tgs = ntohl (opt_parity_prm->parity_prm_tgs); + if (PGM_UNLIKELY(parity_prm_tgs < 2 || parity_prm_tgs > 128)) + { +@@ -664,8 +693,10 @@ + source->is_fec_enabled = 1; + pgm_rxw_update_fec (source->window, parity_prm_tgs); + } ++ } + } + } while (!(opt_header->opt_type & PGM_OPT_END)); ++ } + } + + /* either way bump expiration timer */ +@@ -676,6 +707,7 @@ + source->spmr_tstamp = 0; + } + return TRUE; ++ } + } + + /* Multicast peer-to-peer NAK handling, pretty much the same as a NCF but different direction +@@ -705,6 +737,7 @@ + return FALSE; + } + ++ { + const struct pgm_nak* nak = (struct pgm_nak*) skb->data; + const struct pgm_nak6* nak6 = (struct pgm_nak6*)skb->data; + +@@ -718,10 +751,14 @@ + } + + /* NAK_GRP_NLA contains one of our sock receive multicast groups: the sources send multicast group */ ++ { + struct sockaddr_storage nak_grp_nla; + pgm_nla_to_sockaddr ((AF_INET6 == nak_src_nla.ss_family) ? &nak6->nak6_grp_nla_afi : &nak->nak_grp_nla_afi, (struct sockaddr*)&nak_grp_nla); ++ { + bool found = FALSE; +- for (unsigned i = 0; i < sock->recv_gsr_len; i++) ++ { ++ unsigned i; ++ for (i = 0; i < sock->recv_gsr_len; i++) + { + if (pgm_sockaddr_cmp ((struct sockaddr*)&nak_grp_nla, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0) + { +@@ -729,6 +766,7 @@ + break; + } + } ++ } + + if (PGM_UNLIKELY(!found)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded multicast NAK on multicast group mismatch.")); +@@ -736,6 +774,7 @@ + } + + /* handle as NCF */ ++ { + int status = pgm_rxw_confirm (peer->window, + ntohl (nak->nak_sqn), + skb->tstamp, +@@ -745,6 +784,7 @@ + peer->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SUPPRESSED]++; + + /* check NAK list */ ++ { + const uint32_t* nak_list = NULL; + unsigned nak_list_len = 0; + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) +@@ -765,6 +805,7 @@ + return FALSE; + } + /* TODO: check for > 16 options & past packet end */ ++ { + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); +@@ -775,6 +816,7 @@ + break; + } + } while (!(opt_header->opt_type & PGM_OPT_END)); ++ } + } + + while (nak_list_len) { +@@ -790,6 +832,7 @@ + } + + /* mark receiver window for flushing on next recv() */ ++ { + const pgm_rxw_t* window = peer->window; + if (window->cumulative_losses != peer->last_cumulative_losses && + !peer->pending_link.data) +@@ -800,6 +843,12 @@ + pgm_peer_set_pending (sock, peer); + } + return TRUE; ++ } ++ } ++ } ++ } ++ } ++ } + } + + /* NCF confirming receipt of a NAK from this sock or another on the LAN segment. +@@ -831,6 +880,7 @@ + return FALSE; + } + ++ { + const struct pgm_nak* ncf = (struct pgm_nak*) skb->data; + const struct pgm_nak6* ncf6 = (struct pgm_nak6*)skb->data; + +@@ -847,6 +897,7 @@ + #endif + + /* NCF_GRP_NLA contains our sock multicast group */ ++ { + struct sockaddr_storage ncf_grp_nla; + pgm_nla_to_sockaddr ((AF_INET6 == ncf_src_nla.ss_family) ? &ncf6->nak6_grp_nla_afi : &ncf->nak_grp_nla_afi, (struct sockaddr*)&ncf_grp_nla); + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&ncf_grp_nla, (struct sockaddr*)&sock->send_gsr.gsr_group) != 0)) +@@ -855,6 +906,7 @@ + return FALSE; + } + ++ { + const pgm_time_t ncf_rdata_ivl = skb->tstamp + sock->nak_rdata_ivl; + const pgm_time_t ncf_rb_ivl = skb->tstamp + nak_rb_ivl(sock); + int status = pgm_rxw_confirm (source->window, +@@ -874,6 +926,7 @@ + } + + /* check NCF list */ ++ { + const uint32_t* ncf_list = NULL; + unsigned ncf_list_len = 0; + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) +@@ -894,6 +947,7 @@ + return FALSE; + } + /* TODO: check for > 16 options & past packet end */ ++ { + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); +@@ -904,6 +958,7 @@ + break; + } + } while (!(opt_header->opt_type & PGM_OPT_END)); ++ } + } + + pgm_debug ("NCF contains 1+%d sequence numbers.", ncf_list_len); +@@ -921,6 +976,7 @@ + } + + /* mark receiver window for flushing on next recv() */ ++ { + const pgm_rxw_t* window = source->window; + if (window->cumulative_losses != source->last_cumulative_losses && + !source->pending_link.data) +@@ -931,6 +987,11 @@ + pgm_peer_set_pending (sock, source); + } + return TRUE; ++ } ++ } ++ } ++ } ++ } + } + + /* send SPM-request to a new peer, this packet type has no contents +@@ -953,8 +1014,9 @@ + pgm_debug ("send_spmr (sock:%p source:%p)", + (const void*)sock, (const void*)source); + ++ { + const size_t tpdu_length = sizeof(struct pgm_header); +- char buf[ tpdu_length ]; ++ char* buf = pgm_newa (char, tpdu_length); + struct pgm_header* header = (struct pgm_header*)buf; + memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); + /* dport & sport reversed communicating upstream */ +@@ -968,6 +1030,7 @@ + + /* send multicast SPMR TTL 1 */ + pgm_sockaddr_multicast_hops (sock->send_sock, sock->send_gsr.gsr_group.ss_family, 1); ++ { + ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + FALSE, /* regular socket */ +@@ -992,6 +1055,8 @@ + + sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT] += tpdu_length * 2; + return TRUE; ++ } ++ } + } + + /* send selective NAK for one sequence number. +@@ -1014,10 +1079,12 @@ + pgm_debug ("send_nak (sock:%p peer:%p sequence:%" PRIu32 ")", + (void*)sock, (void*)source, sequence); + ++ { + size_t tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); + if (AF_INET6 == source->nla.ss_family) + tpdu_length += sizeof(struct pgm_nak6) - sizeof(struct pgm_nak); +- char buf[ tpdu_length ]; ++ { ++ char* buf = pgm_newa (char, tpdu_length); + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* nak = (struct pgm_nak* )(header + 1); + struct pgm_nak6* nak6 = (struct pgm_nak6*)(header + 1); +@@ -1045,6 +1112,7 @@ + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + ++ { + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + TRUE, /* with router alert */ +@@ -1058,6 +1126,9 @@ + source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT]++; + source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT]++; + return TRUE; ++ } ++ } ++ } + } + + /* Send a parity NAK requesting on-demand parity packet generation. +@@ -1082,10 +1153,12 @@ + pgm_debug ("send_parity_nak (sock:%p source:%p nak-tg-sqn:%" PRIu32 " nak-pkt-cnt:%" PRIu32 ")", + (void*)sock, (void*)source, nak_tg_sqn, nak_pkt_cnt); + ++ { + size_t tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); + if (AF_INET6 == source->nla.ss_family) + tpdu_length += sizeof(struct pgm_nak6) - sizeof(struct pgm_nak); +- char buf[ tpdu_length ]; ++ { ++ char* buf = pgm_newa (char, tpdu_length); + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* nak = (struct pgm_nak* )(header + 1); + struct pgm_nak6* nak6 = (struct pgm_nak6*)(header + 1); +@@ -1112,6 +1185,7 @@ + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + ++ { + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + TRUE, /* with router alert */ +@@ -1125,6 +1199,9 @@ + source->cumulative_stats[PGM_PC_RECEIVER_PARITY_NAK_PACKETS_SENT]++; + source->cumulative_stats[PGM_PC_RECEIVER_PARITY_NAKS_SENT]++; + return TRUE; ++ } ++ } ++ } + } + + /* A NAK packet with a OPT_NAK_LIST option extension +@@ -1148,17 +1225,23 @@ + pgm_assert_cmpuint (sqn_list->len, <=, 63); + + #ifdef RECEIVER_DEBUG ++ { + char list[1024]; + sprintf (list, "%" PRIu32, sqn_list->sqn[0]); +- for (unsigned i = 1; i < sqn_list->len; i++) { ++ { ++ unsigned i; ++ for (i = 1; i < sqn_list->len; i++) { + char sequence[2 + strlen("4294967295")]; + sprintf (sequence, " %" PRIu32, sqn_list->sqn[i]); + strcat (list, sequence); + } ++ } + pgm_debug("send_nak_list (sock:%p source:%p sqn-list:[%s])", + (const void*)sock, (const void*)source, list); ++ } + #endif + ++ { + size_t tpdu_length = sizeof(struct pgm_header) + + sizeof(struct pgm_nak) + + sizeof(struct pgm_opt_length) + /* includes header */ +@@ -1167,9 +1250,11 @@ + ( (sqn_list->len-1) * sizeof(uint32_t) ); + if (AF_INET6 == source->nla.ss_family) + tpdu_length += sizeof(struct pgm_nak6) - sizeof(struct pgm_nak); +- char buf[ tpdu_length ]; ++ { ++ char* buf = pgm_newa (char, tpdu_length); + if (PGM_UNLIKELY(pgm_mem_gc_friendly)) + memset (buf, 0, tpdu_length); ++ { + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* nak = (struct pgm_nak* )(header + 1); + struct pgm_nak6* nak6 = (struct pgm_nak6*)(header + 1); +@@ -1193,6 +1278,7 @@ + (AF_INET6 == source->nla.ss_family) ? (char*)&nak6->nak6_grp_nla_afi : (char*)&nak->nak_grp_nla_afi); + + /* OPT_NAK_LIST */ ++ { + struct pgm_opt_length* opt_len = (AF_INET6 == source->nla.ss_family) ? (struct pgm_opt_length*)(nak6 + 1) : (struct pgm_opt_length*)(nak + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); +@@ -1200,19 +1286,25 @@ + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ) ); ++ { + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ); ++ { + struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); + opt_nak_list->opt_reserved = 0; + +- for (unsigned i = 1; i < sqn_list->len; i++) ++ { ++ unsigned i; ++ for (i = 1; i < sqn_list->len; i++) + opt_nak_list->opt_sqn[i-1] = htonl (sqn_list->sqn[i]); ++ } + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + ++ { + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + FALSE, /* regular socket */ +@@ -1226,6 +1318,13 @@ + source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAK_PACKETS_SENT]++; + source->cumulative_stats[PGM_PC_RECEIVER_SELECTIVE_NAKS_SENT] += 1 + sqn_list->len; + return TRUE; ++ } ++ } ++ } ++ } ++ } ++ } ++ } + } + + /* send ACK upstream to source +@@ -1248,6 +1347,7 @@ + pgm_debug ("send_ack (sock:%p source:%p now:%" PGM_TIME_FORMAT ")", + (const void*)sock, (const void*)source, now); + ++ { + size_t tpdu_length = sizeof(struct pgm_header) + + sizeof(struct pgm_ack) + + sizeof(struct pgm_opt_length) + /* includes header */ +@@ -1255,9 +1355,11 @@ + sizeof(struct pgm_opt_pgmcc_feedback); + if (AF_INET6 == sock->send_addr.ss_family) + tpdu_length += sizeof(struct pgm_opt6_pgmcc_feedback) - sizeof(struct pgm_opt_pgmcc_feedback); +- char buf[ tpdu_length ]; ++ { ++ char* buf = pgm_newa (char, tpdu_length); + if (PGM_UNLIKELY(pgm_mem_gc_friendly)) + memset (buf, 0, tpdu_length); ++ { + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_ack* ack = (struct pgm_ack*)(header + 1); + memcpy (header->pgm_gsi, &source->tsi.gsi, sizeof(pgm_gsi_t)); +@@ -1274,6 +1376,7 @@ + ack->ack_bitmap = htonl (source->window->bitmap); + + /* OPT_PGMCC_FEEDBACK */ ++ { + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(ack + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); +@@ -1282,16 +1385,19 @@ + (AF_INET6 == sock->send_addr.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_feedback) : + sizeof(struct pgm_opt_pgmcc_feedback) ); ++ { + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_PGMCC_FEEDBACK | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + ( (AF_INET6 == sock->send_addr.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_feedback) : + sizeof(struct pgm_opt_pgmcc_feedback) ); ++ { + struct pgm_opt_pgmcc_feedback* opt_pgmcc_feedback = (struct pgm_opt_pgmcc_feedback*)(opt_header + 1); + opt_pgmcc_feedback->opt_reserved = 0; + +- const uint32_t t = source->ack_last_tstamp + pgm_to_msecs( now - source->last_data_tstamp ); ++ { ++ const uint32_t t = (uint32_t)(source->ack_last_tstamp + pgm_to_msecs( now - source->last_data_tstamp )); + opt_pgmcc_feedback->opt_tstamp = htonl (t); + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->send_addr, (char*)&opt_pgmcc_feedback->opt_nla_afi); + opt_pgmcc_feedback->opt_loss_rate = htons ((uint16_t)source->window->data_loss); +@@ -1299,6 +1405,7 @@ + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + ++ { + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + FALSE, /* regular socket */ +@@ -1311,6 +1418,14 @@ + + source->cumulative_stats[PGM_PC_RECEIVER_ACKS_SENT]++; + return TRUE; ++ } ++ } ++ } ++ } ++ } ++ } ++ } ++ } + } + + /* check all receiver windows for ACKer elections, on expiration send an ACK. +@@ -1331,6 +1446,7 @@ + pgm_debug ("ack_rb_state (peer:%p now:%" PGM_TIME_FORMAT ")", + (const void*)peer, now); + ++ { + pgm_rxw_t* window = peer->window; + pgm_sock_t* sock = peer->sock; + pgm_list_t* list; +@@ -1345,6 +1461,7 @@ + } + + /* have not learned this peers NLA */ ++ { + const bool is_valid_nla = (0 != peer->nla.ss_family); + + while (list) +@@ -1397,6 +1514,8 @@ + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("ACK backoff queue empty.")); + } + return TRUE; ++ } ++ } + } + + /* check all receiver windows for packets in BACK-OFF_STATE, on expiration send a NAK. +@@ -1420,10 +1539,11 @@ + pgm_debug ("nak_rb_state (peer:%p now:%" PGM_TIME_FORMAT ")", + (const void*)peer, now); + ++ { + pgm_rxw_t* window = peer->window; + pgm_sock_t* sock = peer->sock; + pgm_list_t* list; +- struct pgm_sqn_list_t nak_list = { .len = 0 }; ++ struct pgm_sqn_list_t nak_list = { 0 }; + + /* send all NAKs first, lack of data is blocking contiguous processing and its + * better to get the notification out a.s.a.p. even though it might be waiting +@@ -1441,6 +1561,7 @@ + pgm_assert (window->nak_backoff_queue.head != NULL); + } + ++ { + unsigned dropped_invalid = 0; + + /* have not learned this peers NLA */ +@@ -1480,6 +1601,7 @@ + } + + /* TODO: parity nak lists */ ++ { + const uint32_t tg_sqn = skb->sequence & tg_sqn_mask; + if ( ( nak_pkt_cnt && tg_sqn == nak_tg_sqn ) || + ( !nak_pkt_cnt && tg_sqn != current_tg_sqn ) ) +@@ -1508,6 +1630,7 @@ + { /* different transmission group */ + break; + } ++ } + } + else + { /* packet expires some time later */ +@@ -1627,6 +1750,8 @@ + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("NAK backoff queue empty.")); + } + return TRUE; ++ } ++ } + } + + /* check this peer for NAK state timers, uses the tail of each queue for the nearest +@@ -1650,6 +1775,7 @@ + if (!sock->peers_list) + return TRUE; + ++ { + pgm_list_t* list = sock->peers_list; + do { + pgm_list_t* next = list->next; +@@ -1733,6 +1859,7 @@ + sock->is_pending_read = TRUE; + } + return TRUE; ++ } + } + + /* find the next state expiration time among the socks peers. +@@ -1756,6 +1883,7 @@ + if (!sock->peers_list) + return expiration; + ++ { + pgm_list_t* list = sock->peers_list; + do { + pgm_list_t* next = list->next; +@@ -1796,6 +1924,7 @@ + } while (list); + + return expiration; ++ } + } + + /* check WAIT_NCF_STATE, on expiration move back to BACK-OFF_STATE, on exceeding NAK_NCF_RETRIES +@@ -1814,6 +1943,7 @@ + pgm_debug ("nak_rpt_state (peer:%p now:%" PGM_TIME_FORMAT ")", + (void*)peer, now); + ++ { + pgm_rxw_t* window = peer->window; + pgm_sock_t* sock = peer->sock; + pgm_list_t* list = window->wait_ncf_queue.tail; +@@ -1923,6 +2053,7 @@ + { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Wait ncf queue empty.")); + } ++ } + } + + /* check WAIT_DATA_STATE, on expiration move back to BACK-OFF_STATE, on exceeding NAK_DATA_RETRIES +@@ -1941,6 +2072,7 @@ + pgm_debug ("nak_rdata_state (peer:%p now:%" PGM_TIME_FORMAT ")", + (const void*)peer, now); + ++ { + pgm_rxw_t* window = peer->window; + pgm_sock_t* sock = peer->sock; + pgm_list_t* list = window->wait_data_queue.tail; +@@ -1956,6 +2088,7 @@ + pgm_list_t* next_list_el = list->prev; + struct pgm_sk_buff_t* rdata_skb = (struct pgm_sk_buff_t*)list; + pgm_assert (NULL != rdata_skb); ++ { + pgm_rxw_state_t* rdata_state = (pgm_rxw_state_t*)&rdata_skb->cb; + + /* check this packet for state expiration */ +@@ -1991,8 +2124,8 @@ + break; + } + +- + list = next_list_el; ++ } + } + + if (window->wait_data_queue.length == 0) +@@ -2029,6 +2162,7 @@ + } else { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Wait data queue empty.")); + } ++ } + } + + /* ODATA or RDATA packet with any of the following options: +@@ -2055,6 +2189,7 @@ + pgm_debug ("pgm_on_data (sock:%p source:%p skb:%p)", + (void*)sock, (void*)source, (void*)skb); + ++ { + unsigned msg_count = 0; + const pgm_time_t nak_rb_expiry = skb->tstamp + nak_rb_ivl (sock); + pgm_time_t ack_rb_expiry = 0; +@@ -2062,6 +2197,7 @@ + + skb->pgm_data = skb->data; + ++ { + const unsigned opt_total_length = (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) ? ntohs(*(uint16_t*)( (char*)( skb->pgm_data + 1 ) + sizeof(uint16_t))) : 0; + + /* advance data pointer to payload */ +@@ -2076,6 +2212,7 @@ + ack_rb_expiry = skb->tstamp + ack_rb_ivl (sock); + } + ++ { + const int add_status = pgm_rxw_add (source->window, skb, skb->tstamp, nak_rb_expiry); + + /* skb reference is now invalid */ +@@ -2155,6 +2292,9 @@ + pgm_timer_unlock (sock); + } + return TRUE; ++ } ++ } ++ } + } + + /* POLLs are generated by PGM Parents (Sources or Network Elements). +@@ -2182,10 +2322,12 @@ + return FALSE; + } + ++ { + struct pgm_poll* poll4 = (struct pgm_poll*) skb->data; + struct pgm_poll6* poll6 = (struct pgm_poll6*)skb->data; + uint32_t poll_rand; + memcpy (&poll_rand, (AFI_IP6 == ntohs (poll4->poll_nla_afi)) ? poll6->poll6_rand : poll4->poll_rand, sizeof(poll_rand)); ++ { + const uint32_t poll_mask = (AFI_IP6 == ntohs (poll4->poll_nla_afi)) ? ntohl (poll6->poll6_mask) : ntohl (poll4->poll_mask); + + /* Check for probability match */ +@@ -2199,6 +2341,7 @@ + /* scoped per path nla + * TODO: manage list of pollers per peer + */ ++ { + const uint32_t poll_sqn = ntohl (poll4->poll_sqn); + const uint16_t poll_round = ntohs (poll4->poll_round); + +@@ -2213,6 +2356,7 @@ + source->last_poll_sqn = poll_sqn; + source->last_poll_round = poll_round; + ++ { + const uint16_t poll_s_type = ntohs (poll4->poll_s_type); + + /* Check poll type */ +@@ -2229,6 +2373,10 @@ + } + + return FALSE; ++ } ++ } ++ } ++ } + } + + /* Used to count PGM children */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/receiver.c.rej b/3rdparty/openpgm-svn-r1135/pgm/receiver.c.rej new file mode 100644 index 0000000..bb4bac3 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/receiver.c.rej @@ -0,0 +1,37 @@ +*************** +*** 71,77 **** + pgm_assert (NULL != window); + pgm_assert (NULL != window->ack_backoff_queue.tail); + +- const struct pgm_peer_t* peer = (const struct pgm_peer_t*)window->ack_backoff_queue.tail; + pgm_assert (peer->sock->use_pgmcc); + return peer->ack_rb_expiry; + } +--- 71,79 ---- + pgm_assert (NULL != window); + pgm_assert (NULL != window->ack_backoff_queue.tail); + ++ const struct pgm_peer_t* peer = (const struct pgm_peer_t*)window->ack_backoff_queue.tail->data; ++ pgm_assert (NULL != peer); ++ + pgm_assert (peer->sock->use_pgmcc); + return peer->ack_rb_expiry; + } +*************** +*** 416,421 **** + sock->ack_c_p); + peer->spmr_expiry = now + sock->spmr_expiry; + + /* add peer to hash table and linked list */ + pgm_rwlock_writer_lock (&sock->peers_lock); + pgm_peer_t* entry = _pgm_peer_ref (peer); +--- 418,426 ---- + sock->ack_c_p); + peer->spmr_expiry = now + sock->spmr_expiry; + ++ /* Prepare ack_link */ ++ peer->ack_link.data = peer; ++ + /* add peer to hash table and linked list */ + pgm_rwlock_writer_lock (&sock->peers_lock); + pgm_peer_t* entry = _pgm_peer_ref (peer); diff --git a/3rdparty/openpgm-svn-r1135/pgm/receiver_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/receiver_unittest.c new file mode 100644 index 0000000..959afe3 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/receiver_unittest.c @@ -0,0 +1,902 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for PGM receiver transport. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include + + +/* mock state */ + +#define TEST_NETWORK "" +#define TEST_PORT 7500 +#define TEST_MAX_TPDU 1500 +#define TEST_TXW_SQNS 32 +#define TEST_RXW_SQNS 32 +#define TEST_HOPS 16 +#define TEST_SPM_AMBIENT ( pgm_secs(30) ) +#define TEST_SPM_HEARTBEAT_INIT { pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(1300), pgm_secs(7), pgm_secs(16), pgm_secs(25), pgm_secs(30) } +#define TEST_PEER_EXPIRY ( pgm_secs(300) ) +#define TEST_SPMR_EXPIRY ( pgm_msecs(250) ) +#define TEST_NAK_BO_IVL ( pgm_msecs(50) ) +#define TEST_NAK_RPT_IVL ( pgm_secs(2) ) +#define TEST_NAK_RDATA_IVL ( pgm_secs(2) ) +#define TEST_NAK_DATA_RETRIES 5 +#define TEST_NAK_NCF_RETRIES 2 + + +#define pgm_histogram_add mock_pgm_histogram_add +#define pgm_verify_spm mock_pgm_verify_spm +#define pgm_verify_nak mock_pgm_verify_nak +#define pgm_verify_ncf mock_pgm_verify_ncf +#define pgm_verify_poll mock_pgm_verify_poll +#define pgm_sendto_hops mock_pgm_sendto_hops +#define pgm_time_now mock_pgm_time_now +#define pgm_time_update_now mock_pgm_time_update_now +#define pgm_rxw_destroy mock_pgm_rxw_destroy +#define pgm_rxw_create mock_pgm_rxw_create +#define pgm_rxw_update mock_pgm_rxw_update +#define pgm_rxw_update_fec mock_pgm_rxw_update_fec +#define pgm_rxw_confirm mock_pgm_rxw_confirm +#define pgm_rxw_lost mock_pgm_rxw_lost +#define pgm_rxw_state mock_pgm_rxw_state +#define pgm_rxw_add mock_pgm_rxw_add +#define pgm_rxw_remove_commit mock_pgm_rxw_remove_commit +#define pgm_rxw_readv mock_pgm_rxw_readv +#define pgm_csum_fold mock_pgm_csum_fold +#define pgm_compat_csum_partial mock_pgm_compat_csum_partial +#define pgm_histogram_init mock_pgm_histogram_init +#define pgm_setsockopt mock_pgm_setsockopt + + +#define RECEIVER_DEBUG +#include "receiver.c" + + +static +void +mock_setup (void) +{ + if (!g_thread_supported ()) g_thread_init (NULL); +} + +static +struct pgm_sock_t* +generate_sock (void) +{ + struct pgm_sock_t* sock = g_malloc0 (sizeof(struct pgm_sock_t)); + return sock; +} + +static +pgm_peer_t* +generate_peer (void) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_peer_t* peer = g_malloc0 (sizeof(pgm_peer_t)); + peer->window = g_malloc0 (sizeof(pgm_rxw_t)); + pgm_atomic_inc32 (&peer->ref_count); + return peer; +} + +/** socket module */ +static +int +mock_pgm_poll_info ( + pgm_sock_t* const sock, + struct pollfd* fds, + int* n_fds, + int events + ) +{ +} + +static +gboolean +mock_pgm_on_nak ( + pgm_sock_t* const sock, + struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +static +gboolean +mock_pgm_on_nnak ( + pgm_sock_t* const sock, + struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +static +gboolean +mock_pgm_on_spmr ( + pgm_sock_t* const sock, + pgm_peer_t* const peer, + struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +/** net module */ +PGM_GNUC_INTERNAL +ssize_t +mock_pgm_sendto_hops ( + pgm_sock_t* sock, + bool use_rate_limit, + bool use_router_alert, + int hops, + const void* buf, + size_t len, + const struct sockaddr* to, + socklen_t tolen + ) +{ + return len; +} + +/** time module */ +static pgm_time_t mock_pgm_time_now = 0x1; +static pgm_time_t _mock_pgm_time_update_now (void); +pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; + +pgm_time_t +_mock_pgm_time_update_now (void) +{ + return mock_pgm_time_now; +} + +/* packet module */ +bool +mock_pgm_verify_spm ( + const struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +bool +mock_pgm_verify_nak ( + const struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +bool +mock_pgm_verify_ncf ( + const struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +bool +mock_pgm_verify_poll ( + const struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +/* receive window module */ +pgm_rxw_t* +mock_pgm_rxw_create ( + const pgm_tsi_t* tsi, + const uint16_t tpdu_size, + const unsigned sqns, + const unsigned secs, + const ssize_t max_rte, + const uint32_t ack_c_p + ) +{ + return g_malloc0 (sizeof(pgm_rxw_t)); +} + +void +mock_pgm_rxw_destroy ( + pgm_rxw_t* const window + ) +{ + g_assert (NULL != window); + g_free (window); +} + +int +mock_pgm_rxw_confirm ( + pgm_rxw_t* const window, + const uint32_t sequence, + const pgm_time_t now, + const pgm_time_t nak_rdata_expiry, + const pgm_time_t nak_rb_expiry + ) +{ + return PGM_RXW_DUPLICATE; +} + +void +mock_pgm_rxw_lost ( + pgm_rxw_t* const window, + const uint32_t sequence + ) +{ +} + +void +mock_pgm_rxw_state ( + pgm_rxw_t* const window, + struct pgm_sk_buff_t* const skb, + const int new_state + ) +{ +} + +unsigned +mock_pgm_rxw_update ( + pgm_rxw_t* const window, + const uint32_t txw_lead, + const uint32_t txw_trail, + const pgm_time_t now, + const pgm_time_t nak_rb_expiry + ) +{ + return 0; +} + +void +mock_pgm_rxw_update_fec ( + pgm_rxw_t* const window, + const uint8_t rs_k + ) +{ +} + +int +mock_pgm_rxw_add ( + pgm_rxw_t* const window, + struct pgm_sk_buff_t* const skb, + const pgm_time_t now, + const pgm_time_t nak_rb_expiry + ) +{ + return PGM_RXW_APPENDED; +} + +void +mock_pgm_rxw_remove_commit ( + pgm_rxw_t* const window + ) +{ +} + +ssize_t +mock_pgm_rxw_readv ( + pgm_rxw_t* const window, + struct pgm_msgv_t** pmsg, + const unsigned pmsglen + ) +{ + return 0; +} + +/* checksum module */ +uint16_t +mock_pgm_csum_fold ( + uint32_t csum + ) +{ + return 0x0; +} + +uint32_t +mock_pgm_compat_csum_partial ( + const void* addr, + uint16_t len, + uint32_t csum + ) +{ + return 0x0; +} + +void +mock_pgm_histogram_init ( + pgm_histogram_t* histogram + ) +{ +} + +void +mock_pgm_histogram_add ( + pgm_histogram_t* histogram, + int value + ) +{ +} + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + +bool +mock_pgm_setsockopt ( + pgm_sock_t* const sock, + const int level, + const int optname, + const void* optval, + const socklen_t optlen + ) +{ + if (NULL == sock) + return FALSE; + return TRUE; +} + +/* target: + * void + * pgm_peer_unref ( + * pgm_peer_t* peer + * ) + */ + +/* last ref */ +START_TEST (test_peer_unref_pass_001) +{ + pgm_peer_t* peer = generate_peer(); + pgm_peer_unref (peer); +} +END_TEST + +/* non-last ref */ +START_TEST (test_peer_unref_pass_002) +{ + pgm_peer_t* peer = _pgm_peer_ref (generate_peer()); + pgm_peer_unref (peer); +} +END_TEST + + +START_TEST (test_peer_unref_fail_001) +{ + pgm_peer_unref (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_check_peer_state ( + * pgm_sock_t* sock, + * const pgm_time_t now + * ) + */ + +START_TEST (test_check_peer_state_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + sock->is_bound = TRUE; + pgm_check_peer_state (sock, mock_pgm_time_now); +} +END_TEST + +START_TEST (test_check_peer_state_fail_001) +{ + pgm_check_peer_state (NULL, mock_pgm_time_now); + fail ("reached"); +} +END_TEST + +/* target: + * pgm_time_t + * pgm_min_receiver_expiry ( + * pgm_time_t expiration, + * pgm_sock_t* sock + * ) + */ + +START_TEST (test_min_receiver_expiry_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + sock->is_bound = TRUE; + const pgm_time_t expiration = pgm_secs(1); + pgm_time_t next_expiration = pgm_min_receiver_expiry (expiration, sock); +} +END_TEST + +START_TEST (test_min_receiver_expiry_fail_001) +{ + const pgm_time_t expiration = pgm_secs(1); + pgm_min_receiver_expiry (expiration, NULL); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_RXW_SQNS, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_rxw_sqns_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + const int level = IPPROTO_PGM; + const int optname = PGM_RXW_SQNS; + const int rxw_sqns = 100; + const void* optval = &rxw_sqns; + const socklen_t optlen = sizeof(int); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_rxw_sqns failed"); +} +END_TEST + +START_TEST (test_set_rxw_sqns_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_RXW_SQNS; + const int rxw_sqns = 100; + const void* optval = &rxw_sqns; + const socklen_t optlen = sizeof(int); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_rxw_sqns failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_RXW_SECS, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_rxw_secs_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + const int level = IPPROTO_PGM; + const int optname = PGM_RXW_SECS; + const int rxw_secs = 10; + const void* optval = &rxw_secs; + const socklen_t optlen = sizeof(int); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_rxw_secs failed"); +} +END_TEST + +START_TEST (test_set_rxw_secs_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_RXW_SECS; + const int rxw_secs = 10; + const void* optval = &rxw_secs; + const socklen_t optlen = sizeof(int); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_rxw_secs failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_RXW_MAX_RTE, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_rxw_max_rte_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + const int level = IPPROTO_PGM; + const int optname = PGM_RXW_MAX_RTE; + const int rxw_max_rte = 100*1000; + const void* optval = &rxw_max_rte; + const socklen_t optlen = sizeof(int); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_rxw_max_rte failed"); +} +END_TEST + +START_TEST (test_set_rxw_max_rte_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_RXW_MAX_RTE; + const int rxw_max_rte = 100*1000; + const void* optval = &rxw_max_rte; + const socklen_t optlen = sizeof(int); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_rxw_max_rte failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_PEER_EXPIRY, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_peer_expiry_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + const int level = IPPROTO_PGM; + const int optname = PGM_PEER_EXPIRY; + const int peer_expiry = pgm_secs(100); + const void* optval = &peer_expiry; + const socklen_t optlen = sizeof(int); +/* pre-checking should verify value to spm ambient interval + sock->spm_ambient_interval = pgm_secs(30); + */ + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_peer_expiry failed"); +} +END_TEST + +START_TEST (test_set_peer_expiry_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_PEER_EXPIRY; + const int peer_expiry = pgm_secs(100); + const void* optval = &peer_expiry; + const socklen_t optlen = sizeof(int); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_peer_expiry failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_SPMR_EXPIRY, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_spmr_expiry_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + const int level = IPPROTO_PGM; + const int optname = PGM_SPMR_EXPIRY; + const int spmr_expiry = pgm_secs(10); + const void* optval = &spmr_expiry; + const socklen_t optlen = sizeof(int); +/* pre-checking should verify value to spm ambient interval + sock->spm_ambient_interval = pgm_secs(30); + */ + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_spmr_expiry failed"); +} +END_TEST + +START_TEST (test_set_spmr_expiry_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_SPMR_EXPIRY; + const int spmr_expiry = pgm_secs(10); + const void* optval = &spmr_expiry; + const socklen_t optlen = sizeof(int); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_spmr_expiry failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_NAK_BO_IVL, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_nak_bo_ivl_pass_001) +{ + const int level = IPPROTO_PGM; + pgm_sock_t* sock = generate_sock (); + const int optname = PGM_NAK_BO_IVL; + const int nak_bo_ivl = pgm_msecs(1000); + const void* optval = &nak_bo_ivl; + const socklen_t optlen = sizeof(int); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_nak_bo_ivl failed"); +} +END_TEST + +START_TEST (test_set_nak_bo_ivl_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_NAK_BO_IVL; + const int nak_bo_ivl = pgm_msecs(1000); + const void* optval = &nak_bo_ivl; + const socklen_t optlen = sizeof(int); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_nak_bo_ivl failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_NAK_RPT_IVL, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_nak_rpt_ivl_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + const int level = IPPROTO_PGM; + const int optname = PGM_NAK_RPT_IVL; + const int nak_rpt_ivl = pgm_msecs(1000); + const void* optval = &nak_rpt_ivl; + const socklen_t optlen = sizeof(int); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_nak_rpt_ivl failed"); +} +END_TEST + +START_TEST (test_set_nak_rpt_ivl_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_NAK_RPT_IVL; + const int nak_rpt_ivl = pgm_msecs(1000); + const void* optval = &nak_rpt_ivl; + const socklen_t optlen = sizeof(int); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_nak_rpt_ivl failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_NAK_RDATA_IVL, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_nak_rdata_ivl_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + const int level = IPPROTO_PGM; + const int optname = PGM_NAK_RDATA_IVL; + const int nak_rdata_ivl = pgm_msecs(1000); + const void* optval = &nak_rdata_ivl; + const socklen_t optlen = sizeof(int); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_nak_rdata_ivl failed"); +} +END_TEST + +START_TEST (test_set_nak_rdata_ivl_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_NAK_RDATA_IVL; + const int nak_rdata_ivl = pgm_msecs(1000); + const void* optval = &nak_rdata_ivl; + const socklen_t optlen = sizeof(int); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_nak_rdata_ivl failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_NAK_DATA_RETRIES, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_nak_data_retries_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + const int level = IPPROTO_PGM; + const int optname = PGM_NAK_DATA_RETRIES; + const int retries = 1000; + const void* optval = &retries; + const socklen_t optlen = sizeof(int); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_nak_data_retries failed"); +} +END_TEST + +START_TEST (test_set_nak_data_retries_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_NAK_DATA_RETRIES; + const int retries = 1000; + const void* optval = &retries; + const socklen_t optlen = sizeof(int); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_nak_data_retries failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_NAK_NCF_RETRIES, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_nak_ncf_retries_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + const int level = IPPROTO_PGM; + const int optname = PGM_NAK_NCF_RETRIES; + const int retries = 1000; + const void* optval = &retries; + const socklen_t optlen = sizeof(int); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_ncf_data_retries failed"); +} +END_TEST + +START_TEST (test_set_nak_ncf_retries_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_NAK_NCF_RETRIES; + const int retries = 1000; + const void* optval = &retries; + const socklen_t optlen = sizeof(int); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_ncf_data_retries failed"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_peer_unref = tcase_create ("peer_unref"); + suite_add_tcase (s, tc_peer_unref); + tcase_add_checked_fixture (tc_peer_unref, mock_setup, NULL); + tcase_add_test (tc_peer_unref, test_peer_unref_pass_001); + tcase_add_test_raise_signal (tc_peer_unref, test_peer_unref_fail_001, SIGABRT); + +/* formally check-peer-nak-state */ + TCase* tc_check_peer_state = tcase_create ("check-peer-state"); + suite_add_tcase (s, tc_check_peer_state); + tcase_add_checked_fixture (tc_check_peer_state, mock_setup, NULL); + tcase_add_test (tc_check_peer_state, test_check_peer_state_pass_001); + tcase_add_test_raise_signal (tc_check_peer_state, test_check_peer_state_fail_001, SIGABRT); + +/* formally min-nak-expiry */ + TCase* tc_min_receiver_expiry = tcase_create ("min-receiver-expiry"); + suite_add_tcase (s, tc_min_receiver_expiry); + tcase_add_checked_fixture (tc_min_receiver_expiry, mock_setup, NULL); + tcase_add_test (tc_min_receiver_expiry, test_min_receiver_expiry_pass_001); + tcase_add_test_raise_signal (tc_min_receiver_expiry, test_min_receiver_expiry_fail_001, SIGABRT); + + TCase* tc_set_rxw_sqns = tcase_create ("set-rxw_sqns"); + suite_add_tcase (s, tc_set_rxw_sqns); + tcase_add_checked_fixture (tc_set_rxw_sqns, mock_setup, NULL); + tcase_add_test (tc_set_rxw_sqns, test_set_rxw_sqns_pass_001); + tcase_add_test (tc_set_rxw_sqns, test_set_rxw_sqns_fail_001); + + TCase* tc_set_rxw_secs = tcase_create ("set-rxw-secs"); + suite_add_tcase (s, tc_set_rxw_secs); + tcase_add_checked_fixture (tc_set_rxw_secs, mock_setup, NULL); + tcase_add_test (tc_set_rxw_secs, test_set_rxw_secs_pass_001); + tcase_add_test (tc_set_rxw_secs, test_set_rxw_secs_fail_001); + + TCase* tc_set_rxw_max_rte = tcase_create ("set-rxw-max-rte"); + suite_add_tcase (s, tc_set_rxw_max_rte); + tcase_add_checked_fixture (tc_set_rxw_max_rte, mock_setup, NULL); + tcase_add_test (tc_set_rxw_max_rte, test_set_rxw_max_rte_pass_001); + tcase_add_test (tc_set_rxw_max_rte, test_set_rxw_max_rte_fail_001); + + TCase* tc_set_peer_expiry = tcase_create ("set-peer-expiry"); + suite_add_tcase (s, tc_set_peer_expiry); + tcase_add_checked_fixture (tc_set_peer_expiry, mock_setup, NULL); + tcase_add_test (tc_set_peer_expiry, test_set_peer_expiry_pass_001); + tcase_add_test (tc_set_peer_expiry, test_set_peer_expiry_fail_001); + + TCase* tc_set_spmr_expiry = tcase_create ("set-spmr-expiry"); + suite_add_tcase (s, tc_set_spmr_expiry); + tcase_add_checked_fixture (tc_set_spmr_expiry, mock_setup, NULL); + tcase_add_test (tc_set_spmr_expiry, test_set_spmr_expiry_pass_001); + tcase_add_test (tc_set_spmr_expiry, test_set_spmr_expiry_fail_001); + + TCase* tc_set_nak_bo_ivl = tcase_create ("set-nak-bo-ivl"); + suite_add_tcase (s, tc_set_nak_bo_ivl); + tcase_add_checked_fixture (tc_set_nak_bo_ivl, mock_setup, NULL); + tcase_add_test (tc_set_nak_bo_ivl, test_set_nak_bo_ivl_pass_001); + tcase_add_test (tc_set_nak_bo_ivl, test_set_nak_bo_ivl_fail_001); + + TCase* tc_set_nak_rpt_ivl = tcase_create ("set-nak-rpt-ivl"); + suite_add_tcase (s, tc_set_nak_rpt_ivl); + tcase_add_checked_fixture (tc_set_nak_rpt_ivl, mock_setup, NULL); + tcase_add_test (tc_set_nak_rpt_ivl, test_set_nak_rpt_ivl_pass_001); + tcase_add_test (tc_set_nak_rpt_ivl, test_set_nak_rpt_ivl_fail_001); + + TCase* tc_set_nak_rdata_ivl = tcase_create ("set-nak-rdata-ivl"); + suite_add_tcase (s, tc_set_nak_rdata_ivl); + tcase_add_checked_fixture (tc_set_nak_rdata_ivl, mock_setup, NULL); + tcase_add_test (tc_set_nak_rdata_ivl, test_set_nak_rdata_ivl_pass_001); + tcase_add_test (tc_set_nak_rdata_ivl, test_set_nak_rdata_ivl_fail_001); + + TCase* tc_set_nak_data_retries = tcase_create ("set-nak-data-retries"); + suite_add_tcase (s, tc_set_nak_data_retries); + tcase_add_checked_fixture (tc_set_nak_data_retries, mock_setup, NULL); + tcase_add_test (tc_set_nak_data_retries, test_set_nak_data_retries_pass_001); + tcase_add_test (tc_set_nak_data_retries, test_set_nak_data_retries_fail_001); + + TCase* tc_set_nak_ncf_retries = tcase_create ("set-nak-ncf-retries"); + suite_add_tcase (s, tc_set_nak_ncf_retries); + tcase_add_checked_fixture (tc_set_nak_ncf_retries, mock_setup, NULL); + tcase_add_test (tc_set_nak_ncf_retries, test_set_nak_ncf_retries_pass_001); + tcase_add_test (tc_set_nak_ncf_retries, test_set_nak_ncf_retries_fail_001); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/recv.c b/3rdparty/openpgm-svn-r1135/pgm/recv.c new file mode 100644 index 0000000..595beec --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/recv.c @@ -0,0 +1,1062 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Transport recv API. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#ifndef _WIN32 +# include +# include +# include /* _GNU_SOURCE for in6_pktinfo */ +#else +# include +# include +#endif +#include +#include +#include +#include +#include +#include + + +//#define RECV_DEBUG + +#ifndef RECV_DEBUG +# define PGM_DISABLE_ASSERT +#endif + +#ifdef _WIN32 +# define cmsghdr wsacmsghdr +# define CMSG_FIRSTHDR(msg) WSA_CMSG_FIRSTHDR(msg) +# define CMSG_NXTHDR(msg, cmsg) WSA_CMSG_NXTHDR(msg, cmsg) +# define CMSG_DATA(cmsg) WSA_CMSG_DATA(cmsg) +# define CMSG_SPACE(len) WSA_CMSG_SPACE(len) +# define CMSG_LEN(len) WSA_CMSG_LEN(len) +#endif + + +/* read a packet into a PGM skbuff + * on success returns packet length, on closed socket returns 0, + * on error returns -1. + */ + +static +ssize_t +recvskb ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb, + const int flags, + struct sockaddr* const restrict src_addr, + const socklen_t src_addrlen, + struct sockaddr* const restrict dst_addr, + const socklen_t dst_addrlen + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + pgm_assert (NULL != src_addr); + pgm_assert (src_addrlen > 0); + pgm_assert (NULL != dst_addr); + pgm_assert (dst_addrlen > 0); + + pgm_debug ("recvskb (sock:%p skb:%p flags:%d src-addr:%p src-addrlen:%d dst-addr:%p dst-addrlen:%d)", + (void*)sock, (void*)skb, flags, (void*)src_addr, (int)src_addrlen, (void*)dst_addr, (int)dst_addrlen); + + if (PGM_UNLIKELY(sock->is_destroyed)) + return 0; + +#ifdef CONFIG_TARGET_WINE + socklen_t fromlen = src_addrlen; + const ssize_t len = recvfrom (sock->recv_sock, skb->head, sock->max_tpdu, 0, src_addr, &fromlen); + if (len <= 0) + return len; +#else + struct pgm_iovec iov = { + .iov_base = skb->head, + .iov_len = sock->max_tpdu + }; + char aux[ 1024 ]; +# ifndef _WIN32 + struct msghdr msg = { + .msg_name = src_addr, + .msg_namelen = src_addrlen, + .msg_iov = (void*)&iov, + .msg_iovlen = 1, + .msg_control = aux, + .msg_controllen = sizeof(aux), + .msg_flags = 0 + }; + + ssize_t len = recvmsg (sock->recv_sock, &msg, flags); + if (len <= 0) + return len; +# else /* !_WIN32 */ + WSAMSG msg = { + .name = (LPSOCKADDR)src_addr, + .namelen = src_addrlen, + .lpBuffers = (LPWSABUF)&iov, + .dwBufferCount = 1, + .dwFlags = 0 + }; + msg.Control.buf = aux; + msg.Control.len = sizeof(aux); + DWORD len; + if (SOCKET_ERROR == pgm_WSARecvMsg (sock->recv_sock, &msg, &len, NULL, NULL)) { + return -1; + } +# endif /* !_WIN32 */ +#endif /* !CONFIG_TARGET_WINE */ + +#ifdef PGM_DEBUG + if (PGM_UNLIKELY(pgm_loss_rate > 0)) { + const unsigned percent = pgm_rand_int_range (&sock->rand_, 0, 100); + if (percent <= pgm_loss_rate) { + pgm_debug ("Simulated packet loss"); +# ifndef _WIN32 + errno = EAGAIN; +# else + WSASetLastError (WSAEWOULDBLOCK); +# endif + return -1; + } + } +#endif + + skb->sock = sock; + skb->tstamp = pgm_time_update_now(); + skb->data = skb->head; + skb->len = len; + skb->zero_padded = 0; + skb->tail = (char*)skb->data + len; + +#ifdef CONFIG_TARGET_WINE + pgm_assert (pgm_sockaddr_len (&sock->recv_gsr[0].gsr_group) <= dst_addrlen); + memcpy (dst_addr, &sock->recv_gsr[0].gsr_group, pgm_sockaddr_len (&sock->recv_gsr[0].gsr_group)); +#else + if (sock->udp_encap_ucast_port || + AF_INET6 == pgm_sockaddr_family (src_addr)) + { +#ifdef CONFIG_HAVE_WSACMSGHDR + WSACMSGHDR* cmsg; +#else + struct cmsghdr* cmsg; +#endif + for (cmsg = CMSG_FIRSTHDR(&msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) + { +/* both IP_PKTINFO and IP_RECVDSTADDR exist on OpenSolaris, so capture + * each type if defined. + */ +#ifdef IP_PKTINFO + if (IPPROTO_IP == cmsg->cmsg_level && + IP_PKTINFO == cmsg->cmsg_type) + { + const void* pktinfo = CMSG_DATA(cmsg); +/* discard on invalid address */ + if (PGM_UNLIKELY(NULL == pktinfo)) { + pgm_debug ("in_pktinfo is NULL"); + return -1; + } + const struct in_pktinfo* in = pktinfo; + struct sockaddr_in s4; + memset (&s4, 0, sizeof(s4)); + s4.sin_family = AF_INET; + s4.sin_addr.s_addr = in->ipi_addr.s_addr; + memcpy (dst_addr, &s4, sizeof(s4)); + break; + } +#endif +#ifdef IP_RECVDSTADDR + if (IPPROTO_IP == cmsg->cmsg_level && + IP_RECVDSTADDR == cmsg->cmsg_type) + { + const void* recvdstaddr = CMSG_DATA(cmsg); +/* discard on invalid address */ + if (PGM_UNLIKELY(NULL == recvdstaddr)) { + pgm_debug ("in_recvdstaddr is NULL"); + return -1; + } + const struct in_addr* in = recvdstaddr; + struct sockaddr_in s4; + memset (&s4, 0, sizeof(s4)); + s4.sin_family = AF_INET; + s4.sin_addr.s_addr = in->s_addr; + memcpy (dst_addr, &s4, sizeof(s4)); + break; + } +#endif +#if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR) +# error "No defined CMSG type for IPv4 destination address." +#endif + + if (IPPROTO_IPV6 == cmsg->cmsg_level && + IPV6_PKTINFO == cmsg->cmsg_type) + { + const void* pktinfo = CMSG_DATA(cmsg); +/* discard on invalid address */ + if (PGM_UNLIKELY(NULL == pktinfo)) { + pgm_debug ("in6_pktinfo is NULL"); + return -1; + } + const struct in6_pktinfo* in6 = pktinfo; + struct sockaddr_in6 s6; + memset (&s6, 0, sizeof(s6)); + s6.sin6_family = AF_INET6; + s6.sin6_addr = in6->ipi6_addr; + s6.sin6_scope_id = in6->ipi6_ifindex; + memcpy (dst_addr, &s6, sizeof(s6)); +/* does not set flow id */ + break; + } + } + } +#endif + return len; +} + +/* upstream = receiver to source, peer-to-peer = receive to receiver + * + * NB: SPMRs can be upstream or peer-to-peer, if the packet is multicast then its + * a peer-to-peer message, if its unicast its an upstream message. + * + * returns TRUE on valid processed packet, returns FALSE on discarded packet. + */ + +static +bool +on_upstream ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + pgm_assert_cmpuint (skb->pgm_header->pgm_dport, ==, sock->tsi.sport); + + pgm_debug ("on_upstream (sock:%p skb:%p)", + (const void*)sock, (const void*)skb); + + if (PGM_UNLIKELY(!sock->can_send_data)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet for muted source.")); + goto out_discarded; + } + +/* unicast upstream message, note that dport & sport are reversed */ + if (PGM_UNLIKELY(skb->pgm_header->pgm_sport != sock->dport)) { +/* its upstream/peer-to-peer for another session */ + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet on data-destination port mismatch.")); + goto out_discarded; + } + + if (PGM_UNLIKELY(!pgm_gsi_equal (&skb->tsi.gsi, &sock->tsi.gsi))) { +/* its upstream/peer-to-peer for another session */ + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet on data-destination port mismatch.")); + goto out_discarded; + } + +/* advance SKB pointer to PGM type header */ + skb->data = (char*)skb->data + sizeof(struct pgm_header); + skb->len -= sizeof(struct pgm_header); + + switch (skb->pgm_header->pgm_type) { + case PGM_NAK: + if (PGM_UNLIKELY(!pgm_on_nak (sock, skb))) + goto out_discarded; + break; + + case PGM_NNAK: + if (PGM_UNLIKELY(!pgm_on_nnak (sock, skb))) + goto out_discarded; + break; + + case PGM_SPMR: + if (PGM_UNLIKELY(!pgm_on_spmr (sock, NULL, skb))) + goto out_discarded; + break; + + case PGM_ACK: + if (PGM_UNLIKELY(!pgm_on_ack (sock, skb))) + goto out_discarded; + break; + + case PGM_POLR: + default: + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded unsupported PGM type packet.")); + goto out_discarded; + } + + return TRUE; +out_discarded: + sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]++; + return FALSE; +} + +/* peer to peer message, either multicast NAK or multicast SPMR. + * + * returns TRUE on valid processed packet, returns FALSE on discarded packet. + */ + +static +bool +on_peer ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb, + pgm_peer_t** restrict source + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + pgm_assert_cmpuint (skb->pgm_header->pgm_dport, !=, sock->tsi.sport); + pgm_assert (NULL != source); + + pgm_debug ("on_peer (sock:%p skb:%p source:%p)", + (const void*)sock, (const void*)skb, (const void*)source); + +/* we are not the source */ + if (PGM_UNLIKELY(!sock->can_recv_data)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet for muted receiver.")); + goto out_discarded; + } + +/* unicast upstream message, note that dport & sport are reversed */ + if (PGM_UNLIKELY(skb->pgm_header->pgm_sport != sock->dport)) { +/* its upstream/peer-to-peer for another session */ + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet on data-destination port mismatch.")); + goto out_discarded; + } + +/* check to see the source this peer-to-peer message is about is in our peer list */ + pgm_tsi_t upstream_tsi; + memcpy (&upstream_tsi.gsi, &skb->tsi.gsi, sizeof(pgm_gsi_t)); + upstream_tsi.sport = skb->pgm_header->pgm_dport; + + pgm_rwlock_reader_lock (&sock->peers_lock); + *source = pgm_hashtable_lookup (sock->peers_hashtable, &upstream_tsi); + pgm_rwlock_reader_unlock (&sock->peers_lock); + if (PGM_UNLIKELY(NULL == *source)) { +/* this source is unknown, we don't care about messages about it */ + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded peer packet about new source.")); + goto out_discarded; + } + +/* advance SKB pointer to PGM type header */ + skb->data = (char*)skb->data + sizeof(struct pgm_header); + skb->len -= sizeof(struct pgm_header); + + switch (skb->pgm_header->pgm_type) { + case PGM_NAK: + if (PGM_UNLIKELY(!pgm_on_peer_nak (sock, *source, skb))) + goto out_discarded; + break; + + case PGM_SPMR: + if (PGM_UNLIKELY(!pgm_on_spmr (sock, *source, skb))) + goto out_discarded; + break; + + case PGM_NNAK: + case PGM_POLR: + default: + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded unsupported PGM type packet.")); + goto out_discarded; + } + + return TRUE; +out_discarded: + if (*source) + (*source)->cumulative_stats[PGM_PC_RECEIVER_PACKETS_DISCARDED]++; + else if (sock->can_send_data) + sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]++; + return FALSE; +} + +/* source to receiver message + * + * returns TRUE on valid processed packet, returns FALSE on discarded packet. + */ + +static +bool +on_downstream ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb, + struct sockaddr* const restrict src_addr, + struct sockaddr* const restrict dst_addr, + pgm_peer_t** restrict source + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + pgm_assert (NULL != src_addr); + pgm_assert (NULL != dst_addr); + pgm_assert (NULL != source); + +#ifdef RECV_DEBUG + char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop (src_addr, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (dst_addr, daddr, sizeof(daddr)); + pgm_debug ("on_downstream (sock:%p skb:%p src-addr:%s dst-addr:%s source:%p)", + (const void*)sock, (const void*)skb, saddr, daddr, (const void*)source); +#endif + + if (PGM_UNLIKELY(!sock->can_recv_data)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet for muted receiver.")); + goto out_discarded; + } + +/* pgm packet DPORT contains our sock DPORT */ + if (PGM_UNLIKELY(skb->pgm_header->pgm_dport != sock->dport)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded packet on data-destination port mismatch.")); + goto out_discarded; + } + +/* search for TSI peer context or create a new one */ + if (PGM_LIKELY(pgm_tsi_hash (&skb->tsi) == sock->last_hash_key && + NULL != sock->last_hash_value)) + { + *source = sock->last_hash_value; + } + else + { + pgm_rwlock_reader_lock (&sock->peers_lock); + *source = pgm_hashtable_lookup_extended (sock->peers_hashtable, &skb->tsi, &sock->last_hash_key); + pgm_rwlock_reader_unlock (&sock->peers_lock); + if (PGM_UNLIKELY(NULL == *source)) { + *source = pgm_new_peer (sock, + &skb->tsi, + (struct sockaddr*)src_addr, pgm_sockaddr_len(src_addr), + (struct sockaddr*)dst_addr, pgm_sockaddr_len(dst_addr), + skb->tstamp); + } + sock->last_hash_value = *source; + } + + (*source)->cumulative_stats[PGM_PC_RECEIVER_BYTES_RECEIVED] += skb->len; + (*source)->last_packet = skb->tstamp; + + skb->data = (void*)( skb->pgm_header + 1 ); + skb->len -= sizeof(struct pgm_header); + +/* handle PGM packet type */ + switch (skb->pgm_header->pgm_type) { + case PGM_ODATA: + case PGM_RDATA: + if (PGM_UNLIKELY(!pgm_on_data (sock, *source, skb))) + goto out_discarded; + sock->rx_buffer = pgm_alloc_skb (sock->max_tpdu); + break; + + case PGM_NCF: + if (PGM_UNLIKELY(!pgm_on_ncf (sock, *source, skb))) + goto out_discarded; + break; + + case PGM_SPM: + if (PGM_UNLIKELY(!pgm_on_spm (sock, *source, skb))) + goto out_discarded; + +/* update group NLA if appropriate */ + if (PGM_LIKELY(pgm_sockaddr_is_addr_multicast ((struct sockaddr*)dst_addr))) + memcpy (&(*source)->group_nla, dst_addr, pgm_sockaddr_len(dst_addr)); + break; + +#ifdef CONFIG_PGM_POLLING + case PGM_POLL: + if (PGM_UNLIKELY(!pgm_on_poll (sock, *source, skb))) + goto out_discarded; + break; +#endif + + default: + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded unsupported PGM type packet.")); + goto out_discarded; + } + + return TRUE; +out_discarded: + if (*source) + (*source)->cumulative_stats[PGM_PC_RECEIVER_PACKETS_DISCARDED]++; + else if (sock->can_send_data) + sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]++; + return FALSE; +} + +/* process a pgm packet + * + * returns TRUE on valid processed packet, returns FALSE on discarded packet. + */ +static +bool +on_pgm ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb, + struct sockaddr* const restrict src_addr, + struct sockaddr* const restrict dst_addr, + pgm_peer_t** restrict source + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + pgm_assert (NULL != src_addr); + pgm_assert (NULL != dst_addr); + pgm_assert (NULL != source); + +#ifdef RECV_DEBUG + char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop (src_addr, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (dst_addr, daddr, sizeof(daddr)); + pgm_debug ("on_pgm (sock:%p skb:%p src-addr:%s dst-addr:%s source:%p)", + (const void*)sock, (const void*)skb, saddr, daddr, (const void*)source); +#endif + + if (PGM_IS_DOWNSTREAM (skb->pgm_header->pgm_type)) + return on_downstream (sock, skb, src_addr, dst_addr, source); + if (skb->pgm_header->pgm_dport == sock->tsi.sport) + { + if (PGM_IS_UPSTREAM (skb->pgm_header->pgm_type) || + PGM_IS_PEER (skb->pgm_header->pgm_type)) + { + return on_upstream (sock, skb); + } + } + else if (PGM_IS_PEER (skb->pgm_header->pgm_type)) + return on_peer (sock, skb, source); + + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Discarded PGM packet.")); + if (sock->can_send_data) + sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]++; + return FALSE; +} + +/* block on receiving socket whilst holding sock::waiting-mutex + * returns EAGAIN for waiting data, returns EINTR for waiting timer event, + * returns ENOENT on closed sock, and returns EFAULT for libc error. + */ + +static +int +wait_for_event ( + pgm_sock_t* const sock + ) +{ + int n_fds = 3; + +/* pre-conditions */ + pgm_assert (NULL != sock); + + pgm_debug ("wait_for_event (sock:%p)", (const void*)sock); + + do { + if (PGM_UNLIKELY(sock->is_destroyed)) + return ENOENT; + + if (sock->can_send_data && !pgm_txw_retransmit_is_empty (sock->window)) +/* tight loop on blocked send */ + pgm_on_deferred_nak (sock); + +#ifdef CONFIG_HAVE_POLL + struct pollfd fds[ n_fds ]; + memset (fds, 0, sizeof(fds)); + const int status = pgm_poll_info (sock, fds, &n_fds, POLLIN); + pgm_assert (-1 != status); +#else + fd_set readfds; + FD_ZERO(&readfds); + const int status = pgm_select_info (sock, &readfds, NULL, &n_fds); + pgm_assert (-1 != status); +#endif /* CONFIG_HAVE_POLL */ + +/* flush any waiting notifications */ + if (sock->is_pending_read) { + pgm_notify_clear (&sock->pending_notify); + sock->is_pending_read = FALSE; + } + + int timeout; + if (sock->can_send_data && !pgm_txw_retransmit_is_empty (sock->window)) + timeout = 0; + else + timeout = pgm_timer_expiration (sock); + +#ifdef CONFIG_HAVE_POLL + const int ready = poll (fds, n_fds, timeout /* μs */ / 1000 /* to ms */); +#else + struct timeval tv_timeout = { + .tv_sec = timeout > 1000000L ? timeout / 1000000UL : 0, + .tv_usec = timeout > 1000000L ? timeout % 1000000UL : timeout + }; + const int ready = select (n_fds, &readfds, NULL, NULL, &tv_timeout); +#endif + if (PGM_UNLIKELY(-1 == ready)) { + pgm_debug ("block returned errno=%i",errno); + return EFAULT; + } else if (ready > 0) { + pgm_debug ("recv again on empty"); + return EAGAIN; + } + } while (pgm_timer_check (sock)); + pgm_debug ("state generated event"); + return EINTR; +} + +/* data incoming on receive sockets, can be from a sender or receiver, or simply bogus. + * for IPv4 we receive the IP header to handle fragmentation, for IPv6 we cannot, but the + * underlying stack handles this for us. + * + * recvmsgv reads a vector of apdus each contained in a IO scatter/gather array. + * + * can be called due to event from incoming socket(s) or timer induced data loss. + * + * On success, returns PGM_IO_STATUS_NORMAL and saves the count of bytes read + * into _bytes_read. With non-blocking sockets a block returns + * PGM_IO_STATUS_WOULD_BLOCK. When rate limited sending repair data, returns + * PGM_IO_STATUS_RATE_LIMITED and caller should wait. During recovery state, + * returns PGM_IO_STATUS_TIMER_PENDING and caller should also wait. On + * unrecoverable dataloss, returns PGM_IO_STATUS_CONN_RESET. If connection is + * closed, returns PGM_IO_STATUS_EOF. On error, returns PGM_IO_STATUS_ERROR. + */ + +int +pgm_recvmsgv ( + pgm_sock_t* const restrict sock, + struct pgm_msgv_t* const restrict msg_start, + const size_t msg_len, + const int flags, /* MSG_DONTWAIT for non-blocking */ + size_t* restrict _bytes_read, /* may be NULL */ + pgm_error_t** restrict error + ) +{ + int status = PGM_IO_STATUS_WOULD_BLOCK; + + pgm_debug ("pgm_recvmsgv (sock:%p msg-start:%p msg-len:%zu flags:%d bytes-read:%p error:%p)", + (void*)sock, (void*)msg_start, msg_len, flags, (void*)_bytes_read, (void*)error); + +/* parameters */ + pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); + if (PGM_LIKELY(msg_len)) pgm_return_val_if_fail (NULL != msg_start, PGM_IO_STATUS_ERROR); + +/* shutdown */ + if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + +/* state */ + if (PGM_UNLIKELY(!sock->is_bound || sock->is_destroyed)) + { + pgm_rwlock_reader_unlock (&sock->lock); + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + } + +/* pre-conditions */ + pgm_assert (NULL != sock->rx_buffer); + pgm_assert (sock->max_tpdu > 0); + if (sock->can_recv_data) { + pgm_assert (NULL != sock->peers_hashtable); + pgm_assert_cmpuint (sock->nak_bo_ivl, >, 1); + pgm_assert (pgm_notify_is_valid (&sock->pending_notify)); + } + +/* receiver */ + pgm_mutex_lock (&sock->receiver_mutex); + + if (PGM_UNLIKELY(sock->is_reset)) { + pgm_assert (NULL != sock->peers_pending); + pgm_assert (NULL != sock->peers_pending->data); + pgm_peer_t* peer = sock->peers_pending->data; + if (flags & MSG_ERRQUEUE) + pgm_set_reset_error (sock, peer, msg_start); + else if (error) { + char tsi[PGM_TSISTRLEN]; + pgm_tsi_print_r (&peer->tsi, tsi, sizeof(tsi)); + pgm_set_error (error, + PGM_ERROR_DOMAIN_RECV, + PGM_ERROR_CONNRESET, + _("Transport has been reset on unrecoverable loss from %s."), + tsi); + } + if (!sock->is_abort_on_reset) + sock->is_reset = !sock->is_reset; + pgm_mutex_unlock (&sock->receiver_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_RESET; + } + +/* timer status */ + if (pgm_timer_check (sock) && + !pgm_timer_dispatch (sock)) + { +/* block on send-in-recv */ + status = PGM_IO_STATUS_RATE_LIMITED; + } +/* NAK status */ + else if (sock->can_send_data) + { + if (!pgm_txw_retransmit_is_empty (sock->window)) + { + if (!pgm_on_deferred_nak (sock)) + status = PGM_IO_STATUS_RATE_LIMITED; + } + else + pgm_notify_clear (&sock->rdata_notify); + } + + size_t bytes_read = 0; + unsigned data_read = 0; + struct pgm_msgv_t* pmsg = msg_start; + const struct pgm_msgv_t* msg_end = msg_start + msg_len - 1; + + if (PGM_UNLIKELY(0 == ++(sock->last_commit))) + ++(sock->last_commit); + + /* second, flush any remaining contiguous messages from previous call(s) */ + if (sock->peers_pending) { + if (0 != pgm_flush_peers_pending (sock, &pmsg, msg_end, &bytes_read, &data_read)) + goto out; +/* returns on: reset or full buffer */ + } + +/* read the data: + * + * We cannot actually block here as packets pushed by the timers need to be addressed too. + */ + struct sockaddr_storage src, dst; + ssize_t len; + size_t bytes_received = 0; + +recv_again: + + len = recvskb (sock, + sock->rx_buffer, /* PGM skbuff */ + 0, + (struct sockaddr*)&src, + sizeof(src), + (struct sockaddr*)&dst, + sizeof(dst)); + if (len < 0) + { +#ifndef _WIN32 + const int save_errno = errno; + if (PGM_LIKELY(EAGAIN == save_errno)) { + goto check_for_repeat; + } + status = PGM_IO_STATUS_ERROR; + pgm_set_error (error, + PGM_ERROR_DOMAIN_RECV, + pgm_error_from_errno (save_errno), + _("Transport socket error: %s"), + strerror (save_errno)); +#else + const int save_wsa_errno = WSAGetLastError (); + if (PGM_LIKELY(WSAEWOULDBLOCK == save_wsa_errno)) { + goto check_for_repeat; + } + status = PGM_IO_STATUS_ERROR; + pgm_set_error (error, + PGM_ERROR_DOMAIN_RECV, + pgm_error_from_wsa_errno (save_wsa_errno), + _("Transport socket error: %s"), + pgm_wsastrerror (save_wsa_errno)); +#endif /* !_WIN32 */ + goto out; + } + else if (0 == len) + { +/* cannot return NORMAL/0 as that is valid payload with SKB */ + status = PGM_IO_STATUS_EOF; + goto out; + } + else + { + bytes_received += len; + } + + pgm_error_t* err = NULL; + const bool is_valid = (sock->udp_encap_ucast_port || AF_INET6 == src.ss_family) ? + pgm_parse_udp_encap (sock->rx_buffer, &err) : + pgm_parse_raw (sock->rx_buffer, (struct sockaddr*)&dst, &err); + if (PGM_UNLIKELY(!is_valid)) + { +/* inherently cannot determine PGM_PC_RECEIVER_CKSUM_ERRORS unless only one receiver */ + pgm_trace (PGM_LOG_ROLE_NETWORK, + _("Discarded invalid packet: %s"), + (err && err->message) ? err->message : "(null)"); + pgm_error_free (err); + if (sock->can_send_data) { + if (err && PGM_ERROR_CKSUM == err->code) + sock->cumulative_stats[PGM_PC_SOURCE_CKSUM_ERRORS]++; + sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]++; + } + goto recv_again; + } + + pgm_peer_t* source = NULL; + if (PGM_UNLIKELY(!on_pgm (sock, sock->rx_buffer, (struct sockaddr*)&src, (struct sockaddr*)&dst, &source))) + goto recv_again; + +/* check whether this source has waiting data */ + if (source && pgm_peer_has_pending (source)) { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("New pending data.")); + pgm_peer_set_pending (sock, source); + } + +flush_pending: +/* flush any congtiguous packets generated by the receipt of this packet */ + if (sock->peers_pending) + { + if (0 != pgm_flush_peers_pending (sock, &pmsg, msg_end, &bytes_read, &data_read)) + { +/* recv vector is now full */ + goto out; + } + } + +check_for_repeat: +/* repeat if non-blocking and not full */ + if (sock->is_nonblocking || + flags & MSG_DONTWAIT) + { + if (len > 0 && pmsg <= msg_end) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Recv again on not-full")); + goto recv_again; /* \:D/ */ + } + } + else + { +/* repeat if blocking and empty, i.e. received non data packet. + */ + if (0 == data_read) { + const int wait_status = wait_for_event (sock); + switch (wait_status) { + case EAGAIN: + goto recv_again; + case EINTR: + if (!pgm_timer_dispatch (sock)) + goto check_for_repeat; + goto flush_pending; + case ENOENT: + pgm_mutex_unlock (&sock->receiver_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_EOF; + case EFAULT: + pgm_set_error (error, + PGM_ERROR_DOMAIN_RECV, + pgm_error_from_errno (errno), + _("Waiting for event: %s"), +#ifndef _WIN32 + strerror (errno) +#else + pgm_wsastrerror (WSAGetLastError()) /* from select() */ +#endif + ); + pgm_mutex_unlock (&sock->receiver_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_ERROR; + default: + pgm_assert_not_reached(); + } + } + } + +out: + if (0 == data_read) + { +/* clear event notification */ + if (sock->is_pending_read) { + pgm_notify_clear (&sock->pending_notify); + sock->is_pending_read = FALSE; + } +/* report data loss */ + if (PGM_UNLIKELY(sock->is_reset)) { + pgm_assert (NULL != sock->peers_pending); + pgm_assert (NULL != sock->peers_pending->data); + pgm_peer_t* peer = sock->peers_pending->data; + if (flags & MSG_ERRQUEUE) + pgm_set_reset_error (sock, peer, msg_start); + else if (error) { + char tsi[PGM_TSISTRLEN]; + pgm_tsi_print_r (&peer->tsi, tsi, sizeof(tsi)); + pgm_set_error (error, + PGM_ERROR_DOMAIN_RECV, + PGM_ERROR_CONNRESET, + _("Transport has been reset on unrecoverable loss from %s."), + tsi); + } + if (!sock->is_abort_on_reset) + sock->is_reset = !sock->is_reset; + pgm_mutex_unlock (&sock->receiver_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_RESET; + } + pgm_mutex_unlock (&sock->receiver_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + if (PGM_IO_STATUS_WOULD_BLOCK == status && + ( sock->can_send_data || + ( sock->can_recv_data && NULL != sock->peers_list ))) + { + status = PGM_IO_STATUS_TIMER_PENDING; + } + return status; + } + + if (sock->peers_pending) + { +/* set event notification for additional available data */ + if (sock->is_pending_read && sock->is_edge_triggered_recv) + { +/* empty pending-pipe */ + pgm_notify_clear (&sock->pending_notify); + sock->is_pending_read = FALSE; + } + else if (!sock->is_pending_read && !sock->is_edge_triggered_recv) + { +/* fill pending-pipe */ + pgm_notify_send (&sock->pending_notify); + sock->is_pending_read = TRUE; + } + } + + if (NULL != _bytes_read) + *_bytes_read = bytes_read; + pgm_mutex_unlock (&sock->receiver_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_NORMAL; +} + +/* read one contiguous apdu and return as a IO scatter/gather array. msgv is owned by + * the caller, tpdu contents are owned by the receive window. + * + * on success, returns PGM_IO_STATUS_NORMAL. + */ + +int +pgm_recvmsg ( + pgm_sock_t* const restrict sock, + struct pgm_msgv_t* const restrict msgv, + const int flags, /* MSG_DONTWAIT for non-blocking */ + size_t* restrict bytes_read, /* may be NULL */ + pgm_error_t** restrict error + ) +{ + pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); + pgm_return_val_if_fail (NULL != msgv, PGM_IO_STATUS_ERROR); + + pgm_debug ("pgm_recvmsg (sock:%p msgv:%p flags:%d bytes_read:%p error:%p)", + (const void*)sock, (const void*)msgv, flags, (const void*)bytes_read, (const void*)error); + + return pgm_recvmsgv (sock, msgv, 1, flags, bytes_read, error); +} + +/* vanilla read function. copies from the receive window to the provided buffer + * location. the caller must provide an adequately sized buffer to store the largest + * expected apdu or else it will be truncated. + * + * on success, returns PGM_IO_STATUS_NORMAL. + */ + +int +pgm_recvfrom ( + pgm_sock_t* const restrict sock, + void* restrict buf, + const size_t buflen, + const int flags, /* MSG_DONTWAIT for non-blocking */ + size_t* restrict _bytes_read, /* may be NULL */ + struct pgm_sockaddr_t* restrict from, /* may be NULL */ + socklen_t* restrict fromlen, + pgm_error_t** restrict error + ) +{ + struct pgm_msgv_t msgv; + size_t bytes_read = 0; + + pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); + if (PGM_LIKELY(buflen)) pgm_return_val_if_fail (NULL != buf, PGM_IO_STATUS_ERROR); + if (fromlen) { + pgm_return_val_if_fail (NULL != from, PGM_IO_STATUS_ERROR); + pgm_return_val_if_fail (sizeof (struct pgm_sockaddr_t) == *fromlen, PGM_IO_STATUS_ERROR); + } + + pgm_debug ("pgm_recvfrom (sock:%p buf:%p buflen:%zu flags:%d bytes-read:%p from:%p from:%p error:%p)", + (const void*)sock, buf, buflen, flags, (const void*)_bytes_read, (const void*)from, (const void*)fromlen, (const void*)error); + + const int status = pgm_recvmsg (sock, &msgv, flags & ~(MSG_ERRQUEUE), &bytes_read, error); + if (PGM_IO_STATUS_NORMAL != status) + return status; + + size_t bytes_copied = 0; + struct pgm_sk_buff_t** skb = msgv.msgv_skb; + struct pgm_sk_buff_t* pskb = *skb; + + if (from) { + from->sa_port = ntohs (sock->dport); + from->sa_addr.sport = ntohs (pskb->tsi.sport); + memcpy (&from->sa_addr.gsi, &pskb->tsi.gsi, sizeof(pgm_gsi_t)); + } + + while (bytes_copied < bytes_read) { + size_t copy_len = pskb->len; + if (bytes_copied + copy_len > buflen) { + pgm_warn (_("APDU truncated, original length %zu bytes."), + bytes_read); + copy_len = buflen - bytes_copied; + bytes_read = buflen; + } + memcpy ((char*)buf + bytes_copied, pskb->data, copy_len); + bytes_copied += copy_len; + pskb = *(++skb); + } + if (_bytes_read) + *_bytes_read = bytes_copied; + return PGM_IO_STATUS_NORMAL; +} + +/* Basic recv operation, copying data from window to application. + * + * on success, returns PGM_IO_STATUS_NORMAL. + */ + +int +pgm_recv ( + pgm_sock_t* const restrict sock, + void* restrict buf, + const size_t buflen, + const int flags, /* MSG_DONTWAIT for non-blocking */ + size_t* const restrict bytes_read, /* may be NULL */ + pgm_error_t** restrict error + ) +{ + pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); + if (PGM_LIKELY(buflen)) pgm_return_val_if_fail (NULL != buf, PGM_IO_STATUS_ERROR); + + pgm_debug ("pgm_recv (sock:%p buf:%p buflen:%zu flags:%d bytes-read:%p error:%p)", + (const void*)sock, buf, buflen, flags, (const void*)bytes_read, (const void*)error); + + return pgm_recvfrom (sock, buf, buflen, flags, bytes_read, NULL, NULL, error); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/recv.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/recv.c.c89.patch new file mode 100644 index 0000000..171c74c --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/recv.c.c89.patch @@ -0,0 +1,404 @@ +--- recv.c 2010-08-04 16:33:15.000000000 +0800 ++++ recv.c89 2010-08-05 11:37:10.000000000 +0800 +@@ -45,12 +45,11 @@ + + #ifdef _WIN32 + # define cmsghdr wsacmsghdr +-# define CMSG_FIRSTHDR(msg) WSA_CMSG_FIRSTHDR(msg) +-# define CMSG_NXTHDR(msg, cmsg) WSA_CMSG_NXTHDR(msg, cmsg) +-# define CMSG_DATA(cmsg) WSA_CMSG_DATA(cmsg) +-# define CMSG_SPACE(len) WSA_CMSG_SPACE(len) +-# define CMSG_LEN(len) WSA_CMSG_LEN(len) +-# endif ++# define PGM_CMSG_FIRSTHDR(msg) WSA_CMSG_FIRSTHDR(msg) ++# define PGM_CMSG_NXTHDR(msg, cmsg) WSA_CMSG_NXTHDR(msg, cmsg) ++# define PGM_CMSG_DATA(cmsg) WSA_CMSG_DATA(cmsg) ++# define PGM_CMSG_SPACE(len) WSA_CMSG_SPACE(len) ++# define PGM_CMSG_LEN(len) WSA_CMSG_LEN(len) + #endif + + +@@ -91,11 +90,11 @@ + if (len <= 0) + return len; + #else +- struct pgm_iovec iov = { +- .iov_base = skb->head, +- .iov_len = sock->max_tpdu +- }; ++ { ++ struct pgm_iovec iov; + char aux[ 1024 ]; ++ iov.iov_base = skb->head; ++ iov.iov_len = sock->max_tpdu; + # ifndef _WIN32 + struct msghdr msg = { + .msg_name = src_addr, +@@ -111,15 +110,16 @@ + if (len <= 0) + return len; + # else /* !_WIN32 */ +- WSAMSG msg = { +- .name = (LPSOCKADDR)src_addr, +- .namelen = src_addrlen, +- .lpBuffers = (LPWSABUF)&iov, +- .dwBufferCount = 1, +- .dwFlags = 0 +- }; ++ { ++ WSAMSG msg; ++ msg.name = (LPSOCKADDR)src_addr; ++ msg.namelen = src_addrlen; ++ msg.lpBuffers = (LPWSABUF)&iov; ++ msg.dwBufferCount = 1; ++ msg.dwFlags = 0; + msg.Control.buf = aux; + msg.Control.len = sizeof(aux); ++ { + DWORD len; + if (SOCKET_ERROR == pgm_WSARecvMsg (sock->recv_sock, &msg, &len, NULL, NULL)) { + return -1; +@@ -145,7 +145,7 @@ + skb->sock = sock; + skb->tstamp = pgm_time_update_now(); + skb->data = skb->head; +- skb->len = len; ++ skb->len = (uint16_t)len; + skb->zero_padded = 0; + skb->tail = (char*)skb->data + len; + +@@ -161,9 +161,9 @@ + #else + struct cmsghdr* cmsg; + #endif +- for (cmsg = CMSG_FIRSTHDR(&msg); ++ for (cmsg = PGM_CMSG_FIRSTHDR(&msg); + cmsg != NULL; +- cmsg = CMSG_NXTHDR(&msg, cmsg)) ++ cmsg = PGM_CMSG_NXTHDR(&msg, cmsg)) + { + /* both IP_PKTINFO and IP_RECVDSTADDR exist on OpenSolaris, so capture + * each type if defined. +@@ -172,12 +172,13 @@ + if (IPPROTO_IP == cmsg->cmsg_level && + IP_PKTINFO == cmsg->cmsg_type) + { +- const void* pktinfo = CMSG_DATA(cmsg); ++ const void* pktinfo = PGM_CMSG_DATA(cmsg); + /* discard on invalid address */ + if (PGM_UNLIKELY(NULL == pktinfo)) { + pgm_debug ("in_pktinfo is NULL"); + return -1; + } ++ { + const struct in_pktinfo* in = pktinfo; + struct sockaddr_in s4; + memset (&s4, 0, sizeof(s4)); +@@ -185,18 +186,20 @@ + s4.sin_addr.s_addr = in->ipi_addr.s_addr; + memcpy (dst_addr, &s4, sizeof(s4)); + break; ++ } + } + #endif + #ifdef IP_RECVDSTADDR + if (IPPROTO_IP == cmsg->cmsg_level && + IP_RECVDSTADDR == cmsg->cmsg_type) + { +- const void* recvdstaddr = CMSG_DATA(cmsg); ++ const void* recvdstaddr = PGM_CMSG_DATA(cmsg); + /* discard on invalid address */ + if (PGM_UNLIKELY(NULL == recvdstaddr)) { + pgm_debug ("in_recvdstaddr is NULL"); + return -1; + } ++ { + const struct in_addr* in = recvdstaddr; + struct sockaddr_in s4; + memset (&s4, 0, sizeof(s4)); +@@ -204,6 +207,7 @@ + s4.sin_addr.s_addr = in->s_addr; + memcpy (dst_addr, &s4, sizeof(s4)); + break; ++ } + } + #endif + #if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR) +@@ -213,12 +217,13 @@ + if (IPPROTO_IPV6 == cmsg->cmsg_level && + IPV6_PKTINFO == cmsg->cmsg_type) + { +- const void* pktinfo = CMSG_DATA(cmsg); ++ const void* pktinfo = PGM_CMSG_DATA(cmsg); + /* discard on invalid address */ + if (PGM_UNLIKELY(NULL == pktinfo)) { + pgm_debug ("in6_pktinfo is NULL"); + return -1; + } ++ { + const struct in6_pktinfo* in6 = pktinfo; + struct sockaddr_in6 s6; + memset (&s6, 0, sizeof(s6)); +@@ -228,11 +233,15 @@ + memcpy (dst_addr, &s6, sizeof(s6)); + /* does not set flow id */ + break; ++ } + } + } + } + #endif + return len; ++ } ++ } ++ } + } + + /* upstream = receiver to source, peer-to-peer = receive to receiver +@@ -349,6 +358,7 @@ + } + + /* check to see the source this peer-to-peer message is about is in our peer list */ ++ { + pgm_tsi_t upstream_tsi; + memcpy (&upstream_tsi.gsi, &skb->tsi.gsi, sizeof(pgm_gsi_t)); + upstream_tsi.sport = skb->pgm_header->pgm_dport; +@@ -391,6 +401,7 @@ + else if (sock->can_send_data) + sock->cumulative_stats[PGM_PC_SOURCE_PACKETS_DISCARDED]++; + return FALSE; ++ } + } + + /* source to receiver message +@@ -416,11 +427,13 @@ + pgm_assert (NULL != source); + + #ifdef RECV_DEBUG ++ { + char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop (src_addr, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (dst_addr, daddr, sizeof(daddr)); + pgm_debug ("on_downstream (sock:%p skb:%p src-addr:%s dst-addr:%s source:%p)", + (const void*)sock, (const void*)skb, saddr, daddr, (const void*)source); ++ } + #endif + + if (PGM_UNLIKELY(!sock->can_recv_data)) { +@@ -527,11 +540,13 @@ + pgm_assert (NULL != source); + + #ifdef RECV_DEBUG ++ { + char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop (src_addr, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (dst_addr, daddr, sizeof(daddr)); + pgm_debug ("on_pgm (sock:%p skb:%p src-addr:%s dst-addr:%s source:%p)", + (const void*)sock, (const void*)skb, saddr, daddr, (const void*)source); ++ } + #endif + + if (PGM_IS_DOWNSTREAM (skb->pgm_header->pgm_type)) +@@ -585,8 +600,10 @@ + const int status = pgm_poll_info (sock, fds, &n_fds, POLLIN); + pgm_assert (-1 != status); + #else ++ { + fd_set readfds; + FD_ZERO(&readfds); ++ { + const int status = pgm_select_info (sock, &readfds, NULL, &n_fds); + pgm_assert (-1 != status); + #endif /* CONFIG_HAVE_POLL */ +@@ -597,19 +614,21 @@ + sock->is_pending_read = FALSE; + } + ++ { + int timeout; + if (sock->can_send_data && !pgm_txw_retransmit_is_empty (sock->window)) + timeout = 0; + else +- timeout = pgm_timer_expiration (sock); ++ timeout = (int)pgm_timer_expiration (sock); + + #ifdef CONFIG_HAVE_POLL + const int ready = poll (fds, n_fds, timeout /* μs */ / 1000 /* to ms */); + #else +- struct timeval tv_timeout = { +- .tv_sec = timeout > 1000000L ? timeout / 1000000UL : 0, +- .tv_usec = timeout > 1000000L ? timeout % 1000000UL : timeout +- }; ++ { ++ struct timeval tv_timeout; ++ tv_timeout.tv_sec = timeout > 1000000L ? timeout / 1000000UL : 0; ++ tv_timeout.tv_usec = timeout > 1000000L ? timeout % 1000000UL : timeout; ++ { + const int ready = select (n_fds, &readfds, NULL, NULL, &tv_timeout); + #endif + if (PGM_UNLIKELY(-1 == ready)) { +@@ -619,6 +638,11 @@ + pgm_debug ("recv again on empty"); + return EAGAIN; + } ++ } ++ } ++ } ++ } ++ } + } while (pgm_timer_check (sock)); + pgm_debug ("state generated event"); + return EINTR; +@@ -653,7 +677,7 @@ + { + int status = PGM_IO_STATUS_WOULD_BLOCK; + +- pgm_debug ("pgm_recvmsgv (sock:%p msg-start:%p msg-len:%zu flags:%d bytes-read:%p error:%p)", ++ pgm_debug ("pgm_recvmsgv (sock:%p msg-start:%p msg-len:%lu flags:%d bytes-read:%p error:%p)", + (void*)sock, (void*)msg_start, msg_len, flags, (void*)_bytes_read, (void*)error); + + /* parameters */ +@@ -676,7 +700,7 @@ + pgm_assert (sock->max_tpdu > 0); + if (sock->can_recv_data) { + pgm_assert (NULL != sock->peers_hashtable); +- pgm_assert_cmpuint (sock->nak_bo_ivl, >, 1); ++ pgm_assert_cmpuint ((unsigned int)sock->nak_bo_ivl, >, 1); + pgm_assert (pgm_notify_is_valid (&sock->pending_notify)); + } + +@@ -686,6 +710,7 @@ + if (PGM_UNLIKELY(sock->is_reset)) { + pgm_assert (NULL != sock->peers_pending); + pgm_assert (NULL != sock->peers_pending->data); ++ { + pgm_peer_t* peer = sock->peers_pending->data; + if (flags & MSG_ERRQUEUE) + pgm_set_reset_error (sock, peer, msg_start); +@@ -703,6 +728,7 @@ + pgm_mutex_unlock (&sock->receiver_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_RESET; ++ } + } + + /* timer status */ +@@ -724,6 +750,7 @@ + pgm_notify_clear (&sock->rdata_notify); + } + ++ { + size_t bytes_read = 0; + unsigned data_read = 0; + struct pgm_msgv_t* pmsg = msg_start; +@@ -743,6 +770,7 @@ + * + * We cannot actually block here as packets pushed by the timers need to be addressed too. + */ ++ { + struct sockaddr_storage src, dst; + ssize_t len; + size_t bytes_received = 0; +@@ -770,6 +798,7 @@ + _("Transport socket error: %s"), + strerror (save_errno)); + #else ++ { + const int save_wsa_errno = WSAGetLastError (); + if (PGM_LIKELY(WSAEWOULDBLOCK == save_wsa_errno)) { + goto check_for_repeat; +@@ -780,6 +809,7 @@ + pgm_error_from_wsa_errno (save_wsa_errno), + _("Transport socket error: %s"), + pgm_wsastrerror (save_wsa_errno)); ++ } + #endif /* !_WIN32 */ + goto out; + } +@@ -794,6 +824,7 @@ + bytes_received += len; + } + ++ { + pgm_error_t* err = NULL; + const bool is_valid = (sock->udp_encap_ucast_port || AF_INET6 == src.ss_family) ? + pgm_parse_udp_encap (sock->rx_buffer, &err) : +@@ -813,6 +844,7 @@ + goto recv_again; + } + ++ { + pgm_peer_t* source = NULL; + if (PGM_UNLIKELY(!on_pgm (sock, sock->rx_buffer, (struct sockaddr*)&src, (struct sockaddr*)&dst, &source))) + goto recv_again; +@@ -893,6 +925,7 @@ + if (PGM_UNLIKELY(sock->is_reset)) { + pgm_assert (NULL != sock->peers_pending); + pgm_assert (NULL != sock->peers_pending->data); ++ { + pgm_peer_t* peer = sock->peers_pending->data; + if (flags & MSG_ERRQUEUE) + pgm_set_reset_error (sock, peer, msg_start); +@@ -910,6 +943,7 @@ + pgm_mutex_unlock (&sock->receiver_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_RESET; ++ } + } + pgm_mutex_unlock (&sock->receiver_mutex); + pgm_rwlock_reader_unlock (&sock->lock); +@@ -944,6 +978,10 @@ + pgm_mutex_unlock (&sock->receiver_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_NORMAL; ++ } ++ } ++ } ++ } + } + + /* read one contiguous apdu and return as a IO scatter/gather array. msgv is owned by +@@ -999,13 +1037,15 @@ + pgm_return_val_if_fail (sizeof (struct pgm_sockaddr_t) == *fromlen, PGM_IO_STATUS_ERROR); + } + +- pgm_debug ("pgm_recvfrom (sock:%p buf:%p buflen:%zu flags:%d bytes-read:%p from:%p from:%p error:%p)", ++ pgm_debug ("pgm_recvfrom (sock:%p buf:%p buflen:%lu flags:%d bytes-read:%p from:%p from:%p error:%p)", + (const void*)sock, buf, buflen, flags, (const void*)_bytes_read, (const void*)from, (const void*)fromlen, (const void*)error); + ++ { + const int status = pgm_recvmsg (sock, &msgv, flags & ~(MSG_ERRQUEUE), &bytes_read, error); + if (PGM_IO_STATUS_NORMAL != status) + return status; + ++ { + size_t bytes_copied = 0; + struct pgm_sk_buff_t** skb = msgv.msgv_skb; + struct pgm_sk_buff_t* pskb = *skb; +@@ -1019,7 +1059,7 @@ + while (bytes_copied < bytes_read) { + size_t copy_len = pskb->len; + if (bytes_copied + copy_len > buflen) { +- pgm_warn (_("APDU truncated, original length %zu bytes."), ++ pgm_warn (_("APDU truncated, original length %lu bytes."), + bytes_read); + copy_len = buflen - bytes_copied; + bytes_read = buflen; +@@ -1031,6 +1071,8 @@ + if (_bytes_read) + *_bytes_read = bytes_copied; + return PGM_IO_STATUS_NORMAL; ++ } ++ } + } + + /* Basic recv operation, copying data from window to application. +@@ -1051,7 +1093,7 @@ + pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); + if (PGM_LIKELY(buflen)) pgm_return_val_if_fail (NULL != buf, PGM_IO_STATUS_ERROR); + +- pgm_debug ("pgm_recv (sock:%p buf:%p buflen:%zu flags:%d bytes-read:%p error:%p)", ++ pgm_debug ("pgm_recv (sock:%p buf:%p buflen:%lu flags:%d bytes-read:%p error:%p)", + (const void*)sock, buf, buflen, flags, (const void*)bytes_read, (const void*)error); + + return pgm_recvfrom (sock, buf, buflen, flags, bytes_read, NULL, NULL, error); diff --git a/3rdparty/openpgm-svn-r1135/pgm/recv_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/recv_unittest.c new file mode 100644 index 0000000..2719897 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/recv_unittest.c @@ -0,0 +1,1600 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for transport recv api + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include /* _GNU_SOURCE for in6_pktinfo */ +#include +#include +#include + + +/* mock state */ + +#define TEST_NETWORK "" +#define TEST_DPORT 7500 +#define TEST_SPORT 1000 +#define TEST_SRC_ADDR "127.0.0.1" +#define TEST_END_ADDR "127.0.0.2" +#define TEST_GROUP_ADDR "239.192.0.1" +#define TEST_PEER_ADDR "127.0.0.6" +#define TEST_DLR_ADDR "127.0.0.9" +#define TEST_MAX_TPDU 1500 +#define TEST_TXW_SQNS 32 +#define TEST_RXW_SQNS 32 +#define TEST_HOPS 16 +#define TEST_SPM_AMBIENT ( pgm_secs(30) ) +#define TEST_SPM_HEARTBEAT_INIT { pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(1300), pgm_secs(7), pgm_secs(16), pgm_secs(25), pgm_secs(30) } +#define TEST_PEER_EXPIRY ( pgm_secs(300) ) +#define TEST_SPMR_EXPIRY ( pgm_msecs(250) ) +#define TEST_NAK_BO_IVL ( pgm_msecs(50) ) +#define TEST_NAK_RPT_IVL ( pgm_secs(2) ) +#define TEST_NAK_RDATA_IVL ( pgm_secs(2) ) +#define TEST_NAK_DATA_RETRIES 5 +#define TEST_NAK_NCF_RETRIES 2 + +struct mock_recvmsg_t { + struct msghdr* mr_msg; + ssize_t mr_retval; + int mr_errno; +}; + +struct pgm_peer_t; + +GList* mock_recvmsg_list = NULL; +static int mock_pgm_type = -1; +static gboolean mock_reset_on_spmr = FALSE; +static gboolean mock_data_on_spmr = FALSE; +static struct pgm_peer_t* mock_peer = NULL; +GList* mock_data_list = NULL; +unsigned mock_pgm_loss_rate = 0; + + +static ssize_t mock_recvmsg (int, struct msghdr*, int); + +#define pgm_parse_raw mock_pgm_parse_raw +#define pgm_parse_udp_encap mock_pgm_parse_udp_encap +#define pgm_verify_spm mock_pgm_verify_spm +#define pgm_verify_nak mock_pgm_verify_nak +#define pgm_verify_ncf mock_pgm_verify_ncf +#define pgm_poll_info mock_pgm_poll_info +#define pgm_set_reset_error mock_pgm_set_reset_error +#define pgm_flush_peers_pending mock_pgm_flush_peers_pending +#define pgm_peer_has_pending mock_pgm_peer_has_pending +#define pgm_peer_set_pending mock_pgm_peer_set_pending +#define pgm_txw_retransmit_is_empty mock_pgm_txw_retransmit_is_empty +#define pgm_rxw_create mock_pgm_rxw_create +#define pgm_rxw_readv mock_pgm_rxw_readv +#define pgm_new_peer mock_pgm_new_peer +#define pgm_on_data mock_pgm_on_data +#define pgm_on_spm mock_pgm_on_spm +#define pgm_on_ack mock_pgm_on_ack +#define pgm_on_nak mock_pgm_on_nak +#define pgm_on_deferred_nak mock_pgm_on_deferred_nak +#define pgm_on_peer_nak mock_pgm_on_peer_nak +#define pgm_on_nnak mock_pgm_on_nnak +#define pgm_on_ncf mock_pgm_on_ncf +#define pgm_on_spmr mock_pgm_on_spmr +#define pgm_sendto mock_pgm_sendto +#define pgm_timer_prepare mock_pgm_timer_prepare +#define pgm_timer_check mock_pgm_timer_check +#define pgm_timer_expiration mock_pgm_timer_expiration +#define pgm_timer_dispatch mock_pgm_timer_dispatch +#define pgm_time_now mock_pgm_time_now +#define pgm_time_update_now mock_pgm_time_update_now +#define recvmsg mock_recvmsg +#define pgm_loss_rate mock_pgm_loss_rate + +#define RECV_DEBUG +#include "recv.c" + + +pgm_rxw_t* mock_pgm_rxw_create (const pgm_tsi_t*, const uint16_t, const unsigned, const unsigned, const ssize_t, const uint32_t); +static pgm_time_t _mock_pgm_time_update_now (void); +pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; + + +static +void +mock_setup (void) +{ + if (!g_thread_supported ()) g_thread_init (NULL); +} + +static +struct pgm_sock_t* +generate_sock (void) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, g_htons(TEST_SPORT) }; + struct pgm_sock_t* sock = g_new0 (struct pgm_sock_t, 1); + sock->window = g_new0 (pgm_txw_t, 1); + memcpy (&sock->tsi, &tsi, sizeof(pgm_tsi_t)); + sock->is_bound = TRUE; + sock->rx_buffer = pgm_alloc_skb (TEST_MAX_TPDU); + sock->max_tpdu = TEST_MAX_TPDU; + sock->rxw_sqns = TEST_RXW_SQNS; + sock->dport = g_htons(TEST_DPORT); + sock->can_send_data = TRUE; + sock->can_send_nak = TRUE; + sock->can_recv_data = TRUE; + sock->peers_hashtable = pgm_hashtable_new (pgm_tsi_hash, pgm_tsi_equal); + pgm_rand_create (&sock->rand_); + sock->nak_bo_ivl = 100*1000; + pgm_notify_init (&sock->pending_notify); + pgm_notify_init (&sock->rdata_notify); + return sock; +} + +static +struct pgm_sk_buff_t* +generate_packet (void) +{ + struct pgm_sk_buff_t* skb; + + skb = pgm_alloc_skb (TEST_MAX_TPDU); + skb->data = skb->head; + skb->len = sizeof(struct pgm_ip) + sizeof(struct pgm_header); + skb->tail = (guint8*)skb->data + skb->len; + +/* add IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_hl = sizeof(struct pgm_ip) / 4; + iphdr->ip_v = 4; + iphdr->ip_tos = 0; + iphdr->ip_id = 0; + iphdr->ip_off = 0; + iphdr->ip_ttl = 16; + iphdr->ip_p = IPPROTO_PGM; + iphdr->ip_sum = 0; + iphdr->ip_src.s_addr = inet_addr (TEST_SRC_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_GROUP_ADDR); + +/* add PGM header */ + struct pgm_header* pgmhdr = (gpointer)(iphdr + 1); + pgmhdr->pgm_sport = g_htons ((guint16)TEST_SPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_options = 0; + pgmhdr->pgm_gsi[0] = 1; + pgmhdr->pgm_gsi[1] = 2; + pgmhdr->pgm_gsi[2] = 3; + pgmhdr->pgm_gsi[3] = 4; + pgmhdr->pgm_gsi[4] = 5; + pgmhdr->pgm_gsi[5] = 6; + pgmhdr->pgm_tsdu_length = 0; + pgmhdr->pgm_checksum = 0; + + skb->pgm_header = pgmhdr; + return skb; +} + +static +void +generate_odata ( + const char* source, + const guint source_len, + const guint32 data_sqn, + const guint32 data_trail, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_data) + source_len); + +/* add ODATA header */ + struct pgm_data* datahdr = (gpointer)(skb->pgm_header + 1); + datahdr->data_sqn = g_htonl (data_sqn); + datahdr->data_trail = g_htonl (data_trail); + +/* add payload */ + gpointer data = (gpointer)(datahdr + 1); + memcpy (data, source, source_len); + +/* finalize PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_type = PGM_ODATA; + pgmhdr->pgm_tsdu_length = g_htons (source_len); + +/* finalize IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_spm ( + const guint32 spm_sqn, + const guint32 spm_trail, + const guint32 spm_lead, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_spm)); + +/* add SPM header */ + struct pgm_spm* spm = (gpointer)(skb->pgm_header + 1); + spm->spm_sqn = g_htonl (spm_sqn); + spm->spm_trail = g_htonl (spm_trail); + spm->spm_lead = g_htonl (spm_lead); + +/* finalize PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_type = PGM_SPM; + +/* finalize IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_nak ( + const guint32 nak_sqn, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_spm)); + +/* update IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_src.s_addr = inet_addr (TEST_END_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_SRC_ADDR); + +/* update PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); + +/* add NAK header */ + struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); + nak->nak_sqn = g_htonl (nak_sqn); + +/* finalize PGM header */ + pgmhdr->pgm_type = PGM_NAK; + +/* finalize IP header */ + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_peer_nak ( + const guint32 nak_sqn, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_spm)); + +/* update IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_src.s_addr = inet_addr (TEST_PEER_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_GROUP_ADDR); + +/* update PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); + +/* add NAK header */ + struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); + nak->nak_sqn = g_htonl (nak_sqn); + +/* finalize PGM header */ + pgmhdr->pgm_type = PGM_NAK; + +/* finalize IP header */ + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_nnak ( + const guint32 nak_sqn, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_nak)); + +/* update IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_src.s_addr = inet_addr (TEST_DLR_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_SRC_ADDR); + +/* update PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); + +/* add NNAK header */ + struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); + nak->nak_sqn = g_htonl (nak_sqn); + +/* finalize PGM header */ + pgmhdr->pgm_type = PGM_NNAK; + +/* finalize IP header */ + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_ncf ( + const guint32 nak_sqn, + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + pgm_skb_put (skb, sizeof(struct pgm_nak)); + +/* add NAK header */ + struct pgm_nak* nak = (gpointer)(skb->pgm_header + 1); + nak->nak_sqn = g_htonl (nak_sqn); + +/* finalize PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_type = PGM_NCF; + +/* finalize IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_spmr ( + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + +/* update IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_src.s_addr = inet_addr (TEST_END_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_SRC_ADDR); + +/* update PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); + +/* finalize PGM header */ + pgmhdr->pgm_type = PGM_SPMR; + +/* finalize IP header */ + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_peer_spmr ( + gpointer* packet, + gsize* len + ) +{ + struct pgm_sk_buff_t* skb = generate_packet (); + +/* update IP header */ + struct pgm_ip* iphdr = skb->data; + iphdr->ip_src.s_addr = inet_addr (TEST_PEER_ADDR); + iphdr->ip_dst.s_addr = inet_addr (TEST_GROUP_ADDR); + +/* update PGM header */ + struct pgm_header* pgmhdr = skb->pgm_header; + pgmhdr->pgm_sport = g_htons ((guint16)TEST_DPORT); + pgmhdr->pgm_dport = g_htons ((guint16)TEST_SPORT); + +/* finalize PGM header */ + pgmhdr->pgm_type = PGM_SPMR; + +/* finalize IP header */ + iphdr->ip_len = g_htons (skb->len); + + *packet = skb->head; + *len = skb->len; +} + +static +void +generate_msghdr ( + const gpointer packet, + const gsize packet_len + ) +{ + struct pgm_ip* iphdr = packet; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = iphdr->ip_src.s_addr + }; + struct iovec iov = { + .iov_base = packet, + .iov_len = packet_len + }; + struct cmsghdr* packet_cmsg = g_malloc0 (sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)); + packet_cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo); + packet_cmsg->cmsg_level = IPPROTO_IP; + packet_cmsg->cmsg_type = IP_PKTINFO; + struct in_pktinfo packet_info = { + .ipi_ifindex = 2, + .ipi_spec_dst = iphdr->ip_src.s_addr, /* local address */ + .ipi_addr = iphdr->ip_dst.s_addr /* destination address */ + }; + memcpy ((char*)(packet_cmsg + 1), &packet_info, sizeof(struct in_pktinfo)); + struct msghdr packet_msg = { + .msg_name = g_memdup (&addr, sizeof(addr)), /* source address */ + .msg_namelen = sizeof(addr), + .msg_iov = g_memdup (&iov, sizeof(iov)), + .msg_iovlen = 1, + .msg_control = &packet_cmsg, + .msg_controllen = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), + .msg_flags = 0 + }; + + struct mock_recvmsg_t* mr = g_malloc (sizeof(struct mock_recvmsg_t)); + mr->mr_msg = g_memdup (&packet_msg, sizeof(packet_msg)); + mr->mr_errno = 0; + mr->mr_retval = packet_len; + mock_recvmsg_list = g_list_append (mock_recvmsg_list, mr); +} + +static +void +push_block_event (void) +{ +/* block */ + struct mock_recvmsg_t* mr = g_malloc (sizeof(struct mock_recvmsg_t)); + mr->mr_msg = NULL; + mr->mr_errno = EAGAIN; + mr->mr_retval = -1; + mock_recvmsg_list = g_list_append (mock_recvmsg_list, mr); +} + +/** packet module */ +bool +mock_pgm_parse_raw ( + struct pgm_sk_buff_t* const skb, + struct sockaddr* const dst, + pgm_error_t** error + ) +{ + const struct pgm_ip* ip = (struct pgm_ip*)skb->data; + struct sockaddr_in* sin = (struct sockaddr_in*)dst; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = ip->ip_dst.s_addr; + const gsize ip_header_length = ip->ip_hl * 4; + skb->pgm_header = (gpointer)( (guint8*)skb->data + ip_header_length ); + skb->data = skb->pgm_header; + skb->len -= ip_header_length; + memcpy (&skb->tsi.gsi, skb->pgm_header->pgm_gsi, sizeof(pgm_gsi_t)); + skb->tsi.sport = skb->pgm_header->pgm_sport; + return TRUE; +} + +bool +mock_pgm_parse_udp_encap ( + struct pgm_sk_buff_t* const skb, + pgm_error_t** error + ) +{ + skb->pgm_header = skb->data; + memcpy (&skb->tsi.gsi, skb->pgm_header->pgm_gsi, sizeof(pgm_gsi_t)); + skb->tsi.sport = skb->pgm_header->pgm_sport; + return TRUE; +} + +bool +mock_pgm_verify_spm ( + const struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +bool +mock_pgm_verify_nak ( + const struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +bool +mock_pgm_verify_ncf ( + const struct pgm_sk_buff_t* const skb + ) +{ + return TRUE; +} + +/** socket module */ +int +mock_pgm_poll_info ( + pgm_sock_t* const sock, + struct pollfd* fds, + int* n_fds, + int events + ) +{ +} + +pgm_peer_t* +mock__pgm_peer_ref ( + pgm_peer_t* peer + ) +{ + pgm_atomic_inc32 (&peer->ref_count); + return peer; +} + +PGM_GNUC_INTERNAL +pgm_peer_t* +mock_pgm_new_peer ( + pgm_sock_t* const sock, + const pgm_tsi_t* const tsi, + const struct sockaddr* const src_addr, + const socklen_t src_addr_len, + const struct sockaddr* const dst_addr, + const socklen_t dst_addr_len, + const pgm_time_t now + ) +{ + pgm_peer_t* peer = g_malloc0 (sizeof(pgm_peer_t)); + peer->expiry = now + sock->peer_expiry; + peer->sock = sock; + memcpy (&peer->tsi, tsi, sizeof(pgm_tsi_t)); + memcpy (&peer->group_nla, dst_addr, dst_addr_len); + memcpy (&peer->local_nla, src_addr, src_addr_len); + ((struct sockaddr_in*)&peer->local_nla)->sin_port = g_htons (sock->udp_encap_ucast_port); + ((struct sockaddr_in*)&peer->nla)->sin_port = g_htons (sock->udp_encap_ucast_port); + peer->window = mock_pgm_rxw_create (&peer->tsi, + sock->max_tpdu, + sock->rxw_sqns, + sock->rxw_secs, + sock->rxw_max_rte, + sock->ack_c_p); + peer->spmr_expiry = now + sock->spmr_expiry; + gpointer entry = mock__pgm_peer_ref(peer); + pgm_hashtable_insert (sock->peers_hashtable, &peer->tsi, entry); + peer->peers_link.next = sock->peers_list; + peer->peers_link.data = peer; + if (sock->peers_list) + sock->peers_list->prev = &peer->peers_link; + sock->peers_list = &peer->peers_link; + return peer; +} + +PGM_GNUC_INTERNAL +void +mock_pgm_set_reset_error ( + pgm_sock_t* const sock, + pgm_peer_t* const source, + struct pgm_msgv_t* const msgv + ) +{ +} + +PGM_GNUC_INTERNAL +int +mock_pgm_flush_peers_pending ( + pgm_sock_t* const sock, + struct pgm_msgv_t** pmsg, + const struct pgm_msgv_t* const msg_end, + size_t* const bytes_read, + unsigned* const data_read + ) +{ + if (mock_data_list) { + size_t len = 0; + unsigned count = 0; + while (mock_data_list && *pmsg <= msg_end) { + struct pgm_msgv_t* mock_msgv = mock_data_list->data; + (*pmsg)->msgv_len = mock_msgv->msgv_len; + for (unsigned i = 0; i < mock_msgv->msgv_len; i++) { + (*pmsg)->msgv_skb[i] = mock_msgv->msgv_skb[i]; + len += mock_msgv->msgv_skb[i]->len; + } + count++; + (*pmsg)++; + mock_data_list = g_list_delete_link (mock_data_list, mock_data_list); + } + *bytes_read = len; + *data_read = count; + if (*pmsg > msg_end) + return -ENOBUFS; + } + return 0; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_peer_has_pending ( + pgm_peer_t* const peer + ) +{ + return FALSE; +} + +PGM_GNUC_INTERNAL +void +mock_pgm_peer_set_pending ( + pgm_sock_t* const sock, + pgm_peer_t* const peer + ) +{ + g_assert (NULL != sock); + g_assert (NULL != peer); + if (peer->pending_link.data) return; + peer->pending_link.data = peer; + peer->pending_link.next = sock->peers_pending; + sock->peers_pending = &peer->pending_link; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_data ( + pgm_sock_t* const sock, + pgm_peer_t* const sender, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_data (sock:%p sender:%p skb:%p)", + (gpointer)sock, (gpointer)sender, (gpointer)skb); + mock_pgm_type = PGM_ODATA; + ((pgm_rxw_t*)sender->window)->has_event = 1; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_ack ( + pgm_sock_t* const sock, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_ack (sock:%p skb:%p)", + (gpointer)sock, (gpointer)skb); + mock_pgm_type = PGM_ACK; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_deferred_nak ( + pgm_sock_t* const sock + ) +{ + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_nak ( + pgm_sock_t* const sock, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_nak (sock:%p skb:%p)", + (gpointer)sock, (gpointer)skb); + mock_pgm_type = PGM_NAK; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_peer_nak ( + pgm_sock_t* const sock, + pgm_peer_t* const sender, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_peer_nak (sock:%p sender:%p skb:%p)", + (gpointer)sock, (gpointer)sender, (gpointer)skb); + mock_pgm_type = PGM_NAK; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_ncf ( + pgm_sock_t* const sock, + pgm_peer_t* const sender, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_ncf (sock:%p sender:%p skb:%p)", + (gpointer)sock, (gpointer)sender, (gpointer)skb); + mock_pgm_type = PGM_NCF; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_nnak ( + pgm_sock_t* const sock, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_nnak (sock:%p skb:%p)", + (gpointer)sock, (gpointer)skb); + mock_pgm_type = PGM_NNAK; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_spm ( + pgm_sock_t* const sock, + pgm_peer_t* const sender, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_spm (sock:%p sender:%p skb:%p)", + (gpointer)sock, (gpointer)sender, (gpointer)skb); + mock_pgm_type = PGM_SPM; + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_on_spmr ( + pgm_sock_t* const sock, + pgm_peer_t* const peer, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_on_spmr (sock:%p peer:%p skb:%p)", + (gpointer)sock, (gpointer)peer, (gpointer)skb); + mock_pgm_type = PGM_SPMR; + if (mock_reset_on_spmr) { + sock->is_reset = TRUE; + mock_pgm_peer_set_pending (sock, mock_peer); + } + if (mock_data_on_spmr) { + mock_pgm_peer_set_pending (sock, mock_peer); + } + return TRUE; +} + +/** transmit window */ +PGM_GNUC_INTERNAL +bool +mock_pgm_txw_retransmit_is_empty ( + const pgm_txw_t*const window + ) +{ + return TRUE; +} + +/** receive window */ +pgm_rxw_t* +mock_pgm_rxw_create ( + const pgm_tsi_t* tsi, + const uint16_t tpdu_size, + const unsigned sqns, + const unsigned secs, + const ssize_t max_rte, + const uint32_t ack_c_p + ) +{ + return g_new0 (pgm_rxw_t, 1); +} + +ssize_t +mock_pgm_rxw_readv ( + pgm_rxw_t* const window, + struct pgm_msgv_t** pmsg, + const unsigned pmsglen + ) +{ + return -1; +} + +/** net module */ +PGM_GNUC_INTERNAL +ssize_t +mock_pgm_sendto ( + pgm_sock_t* sock, + bool use_rate_limit, + bool use_router_alert, + const void* buf, + size_t len, + const struct sockaddr* to, + socklen_t tolen + ) +{ + return len; +} + +/** timer module */ +PGM_GNUC_INTERNAL +bool +mock_pgm_timer_prepare ( + pgm_sock_t* const sock + ) +{ + return FALSE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_timer_check ( + pgm_sock_t* const sock + ) +{ + return FALSE; +} + +PGM_GNUC_INTERNAL +pgm_time_t +mock_pgm_timer_expiration ( + pgm_sock_t* const sock + ) +{ + return 100L; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_timer_dispatch ( + pgm_sock_t* const sock + ) +{ + return TRUE; +} + +/** time module */ +static pgm_time_t mock_pgm_time_now = 0x1; + +static +pgm_time_t +_mock_pgm_time_update_now (void) +{ + return mock_pgm_time_now; +} + +/** libc */ +static +ssize_t +mock_recvmsg ( + int s, + struct msghdr* msg, + int flags + ) +{ + g_assert (NULL != msg); + g_assert (NULL != mock_recvmsg_list); + + g_debug ("mock_recvmsg (s:%d msg:%p flags:%d)", + s, (gpointer)msg, flags); + + struct mock_recvmsg_t* mr = mock_recvmsg_list->data; + struct msghdr* mock_msg = mr->mr_msg; + ssize_t mock_retval = mr->mr_retval; + int mock_errno = mr->mr_errno; + mock_recvmsg_list = g_list_delete_link (mock_recvmsg_list, mock_recvmsg_list); + if (mock_msg) { + g_assert_cmpuint (mock_msg->msg_namelen, <=, msg->msg_namelen); + g_assert_cmpuint (mock_msg->msg_iovlen, <=, msg->msg_iovlen); + g_assert_cmpuint (mock_msg->msg_controllen, <=, msg->msg_controllen); + if (mock_msg->msg_namelen) + memcpy (msg->msg_name, mock_msg->msg_name, mock_msg->msg_namelen); + if (mock_msg->msg_iovlen) { + for (unsigned i = 0; i < mock_msg->msg_iovlen; i++) { + g_assert (mock_msg->msg_iov[i].iov_len <= msg->msg_iov[i].iov_len); + memcpy (msg->msg_iov[i].iov_base, mock_msg->msg_iov[i].iov_base, mock_msg->msg_iov[i].iov_len); + } + } + if (mock_msg->msg_controllen) + memcpy (msg->msg_control, mock_msg->msg_control, mock_msg->msg_controllen); + msg->msg_flags = mock_msg->msg_flags; + } + errno = mock_errno; + return mock_retval; +} + + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + + +/* target: + * int + * pgm_recv ( + * pgm_sock_t* sock, + * void* data, + * size_t len, + * int flags, + * size_t* bytes_read, + * pgm_error_t** error + * ) + * + * Most tests default to PGM_IO_STATUS_TIMER_PENDING, PGM_IO_STATUS_WOULD_BLOCK is not expected due + * to peer state engine and SPM broadcasts. + */ + +START_TEST (test_block_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* recv -> on_data */ +START_TEST (test_data_pass_001) +{ + const char source[] = "i am not a string"; + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_odata (source, sizeof(source), 0 /* sqn */, -1 /* trail */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_ODATA == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_spm */ +START_TEST (test_spm_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_spm (200 /* spm-sqn */, -1 /* trail */, 0 /* lead */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_SPM == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_nak */ +START_TEST (test_nak_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_nak (0 /* sqn */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_NAK == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_peer_nak */ +START_TEST (test_peer_nak_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_peer_nak (0 /* sqn */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_NAK == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_nnak */ +START_TEST (test_nnak_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_nnak (0 /* sqn */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_NNAK == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_ncf */ +START_TEST (test_ncf_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_ncf (0 /* sqn */, &packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_NCF == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on_spmr */ +START_TEST (test_spmr_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_SPMR == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> on (peer) spmr */ +START_TEST (test_peer_spmr_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gpointer packet; gsize packet_len; + generate_peer_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + push_block_event (); + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (PGM_SPMR == mock_pgm_type, "unexpected PGM packet"); +} +END_TEST + +/* recv -> lost data */ +START_TEST (test_lost_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_reset = TRUE; + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + pgm_peer_t* peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == peer, "new_peer failed"); + mock_pgm_peer_set_pending (sock, peer); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + if (err) { + g_message ("%s", err->message); + pgm_error_free (err); + err = NULL; + } + push_block_event (); + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* recv -> lost data and abort transport */ +START_TEST (test_abort_on_lost_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_reset = TRUE; + sock->is_abort_on_reset = TRUE; + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + pgm_peer_t* peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == peer, "new_peer failed"); + mock_pgm_peer_set_pending (sock, peer); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + if (err) { + g_message ("%s", err->message); + pgm_error_free (err); + err = NULL; + } + push_block_event (); + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* recv -> (spmr) & loss */ +START_TEST (test_then_lost_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + mock_reset_on_spmr = TRUE; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == mock_peer, "new_peer failed"); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + if (err) { + g_message ("%s", err->message); + pgm_error_free (err); + err = NULL; + } + push_block_event (); + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* recv -> data & loss & abort transport */ +START_TEST (test_then_abort_on_lost_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + mock_reset_on_spmr = TRUE; + sock->is_abort_on_reset = TRUE; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == mock_peer, "new_peer failed"); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + if (err) { + g_message ("%s", err->message); + pgm_error_free (err); + err = NULL; + } + push_block_event (); + fail_unless (PGM_IO_STATUS_RESET == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* new waiting peer -> return data */ +START_TEST (test_on_data_pass_001) +{ + const char source[] = "i am not a string"; + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + mock_data_on_spmr = TRUE; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == mock_peer, "new_peer failed"); + struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); + pgm_skb_put (skb, sizeof(source)); + memcpy (skb->data, source, sizeof(source)); + struct pgm_msgv_t* msgv = g_new0 (struct pgm_msgv_t, 1); + msgv->msgv_len = 1; + msgv->msgv_skb[0] = skb; + mock_data_list = g_list_append (mock_data_list, msgv); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (NULL == err, "error raised"); + fail_unless ((gsize)sizeof(source) == bytes_read, "unexpected data length"); + push_block_event (); + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* zero length data waiting */ +START_TEST (test_on_zero_pass_001) +{ + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + mock_data_on_spmr = TRUE; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == mock_peer, "new_peer failed"); + struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); + struct pgm_msgv_t* msgv = g_new0 (struct pgm_msgv_t, 1); + msgv->msgv_len = 1; + msgv->msgv_skb[0] = skb; + mock_data_list = g_list_append (mock_data_list, msgv); + push_block_event (); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (NULL == err, "error raised"); + fail_unless ((gsize)0 == bytes_read, "unexpected data length"); + push_block_event (); + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +/* more than vector length data waiting */ +START_TEST (test_on_many_data_pass_001) +{ + const char* source[] = { + "i am not a string", + "i am not an iguana", + "i am not a peach" + }; + pgm_sock_t* sock = generate_sock(); + fail_if (NULL == sock, "generate_sock failed"); + mock_data_on_spmr = TRUE; + gpointer packet; gsize packet_len; + generate_spmr (&packet, &packet_len); + generate_msghdr (packet, packet_len); + const pgm_tsi_t peer_tsi = { { 9, 8, 7, 6, 5, 4 }, g_htons(9000) }; + struct sockaddr_in grp_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_GROUP_ADDR) + }, peer_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr(TEST_END_ADDR) + }; + mock_peer = mock_pgm_new_peer (sock, &peer_tsi, (struct sockaddr*)&grp_addr, sizeof(grp_addr), (struct sockaddr*)&peer_addr, sizeof(peer_addr), mock_pgm_time_now); + fail_if (NULL == mock_peer, "new_peer failed"); + struct pgm_sk_buff_t* skb; + struct pgm_msgv_t* msgv; +/* #1 */ + msgv = g_new0 (struct pgm_msgv_t, 1); + skb = pgm_alloc_skb (TEST_MAX_TPDU); + pgm_skb_put (skb, strlen(source[0]) + 1); + memcpy (skb->data, source[0], strlen(source[0])); + msgv->msgv_len = 1; + msgv->msgv_skb[0] = skb; + mock_data_list = g_list_append (mock_data_list, msgv); +/* #2 */ + msgv = g_new0 (struct pgm_msgv_t, 1); + skb = pgm_alloc_skb (TEST_MAX_TPDU); + pgm_skb_put (skb, strlen(source[1]) + 1); + memcpy (skb->data, source[1], strlen(source[1])); + msgv->msgv_len = 1; + msgv->msgv_skb[0] = skb; + mock_data_list = g_list_append (mock_data_list, msgv); +/* #3 */ + msgv = g_new0 (struct pgm_msgv_t, 1); + skb = pgm_alloc_skb (TEST_MAX_TPDU); + pgm_skb_put (skb, strlen(source[2]) + 1); + memcpy (skb->data, source[2], strlen(source[2])); + msgv->msgv_len = 1; + msgv->msgv_skb[0] = skb; + mock_data_list = g_list_append (mock_data_list, msgv); + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + gsize bytes_read; + pgm_error_t* err = NULL; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (NULL == err, "error raised"); + fail_unless ((gsize)(strlen(source[0]) + 1) == bytes_read, "unexpected data length"); + g_message ("#1 = \"%s\"", buffer); + fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (NULL == err, "error raised"); + fail_unless ((gsize)(strlen(source[1]) + 1) == bytes_read, "unexpected data length"); + g_message ("#2 = \"%s\"", buffer); + fail_unless (PGM_IO_STATUS_NORMAL == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); + fail_unless (NULL == err, "error raised"); + fail_unless ((gsize)(strlen(source[2]) + 1) == bytes_read, "unexpected data length"); + g_message ("#3 = \"%s\"", buffer); + push_block_event (); + fail_unless (PGM_IO_STATUS_TIMER_PENDING == pgm_recv (sock, buffer, sizeof(buffer), MSG_DONTWAIT, &bytes_read, &err), "recv faied"); +} +END_TEST + +START_TEST (test_recv_fail_001) +{ + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + fail_unless (PGM_IO_STATUS_ERROR == pgm_recv (NULL, buffer, sizeof(buffer), 0, NULL, NULL), "recv faied"); +} +END_TEST + +/* target: + * int + * pgm_recvfrom ( + * pgm_sock_t* sock, + * void* data, + * size_t len, + * int flags, + * size_t* bytes_read, + * struct pgm_sockaddr_t* from, + * socklen_t* fromlen, + * pgm_error_t** error + * ) + */ + +START_TEST (test_recvfrom_fail_001) +{ + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + struct pgm_sockaddr_t from; + socklen_t fromlen = sizeof(from); + fail_unless (PGM_IO_STATUS_ERROR == pgm_recvfrom (NULL, buffer, sizeof(buffer), 0, NULL, &from, &fromlen, NULL), "recvfrom failed"); +} +END_TEST + +/* target: + * int + * pgm_recvmsg ( + * pgm_sock_t* sock, + * pgm_msgv_t* msgv, + * int flags, + * size_t* bytes_read, + * pgm_error_t** error + * ) + */ + +START_TEST (test_recvmsg_fail_001) +{ + struct pgm_msgv_t msgv; + fail_unless (PGM_IO_STATUS_ERROR == pgm_recvmsg (NULL, &msgv, 0, NULL, NULL), "recvmsg failed"); +} +END_TEST + +/* target: + * int + * pgm_recvmsgv ( + * pgm_sock_t* sock, + * pgm_msgv_t* msgv, + * unsigned msgv_length, + * int flags, + * size_t* bytes_read, + * pgm_error_t** error + * ) + */ + +START_TEST (test_recvmsgv_fail_001) +{ + struct pgm_msgv_t msgv[1]; + fail_unless (PGM_IO_STATUS_ERROR == pgm_recvmsgv (NULL, msgv, G_N_ELEMENTS(msgv), 0, NULL, NULL), "recvmsgv failed"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_block = tcase_create ("block"); + suite_add_tcase (s, tc_block); + tcase_add_checked_fixture (tc_block, mock_setup, NULL); + tcase_add_test (tc_block, test_block_pass_001); + + TCase* tc_data = tcase_create ("data"); + suite_add_tcase (s, tc_data); + tcase_add_checked_fixture (tc_data, mock_setup, NULL); + tcase_add_test (tc_data, test_data_pass_001); + + TCase* tc_spm = tcase_create ("spm"); + suite_add_tcase (s, tc_spm); + tcase_add_checked_fixture (tc_spm, mock_setup, NULL); + tcase_add_test (tc_spm, test_spm_pass_001); + + TCase* tc_nak = tcase_create ("nak"); + suite_add_tcase (s, tc_nak); + tcase_add_checked_fixture (tc_nak, mock_setup, NULL); + tcase_add_test (tc_nak, test_nak_pass_001); + + TCase* tc_peer_nak = tcase_create ("peer-nak"); + suite_add_tcase (s, tc_peer_nak); + tcase_add_checked_fixture (tc_peer_nak, mock_setup, NULL); + tcase_add_test (tc_peer_nak, test_peer_nak_pass_001); + + TCase* tc_nnak = tcase_create ("nnak"); + suite_add_tcase (s, tc_nnak); + tcase_add_checked_fixture (tc_nnak, mock_setup, NULL); + tcase_add_test (tc_nnak, test_nnak_pass_001); + + TCase* tc_ncf = tcase_create ("ncf"); + suite_add_tcase (s, tc_ncf); + tcase_add_checked_fixture (tc_ncf, mock_setup, NULL); + tcase_add_test (tc_ncf, test_ncf_pass_001); + + TCase* tc_spmr = tcase_create ("spmr"); + suite_add_tcase (s, tc_spmr); + tcase_add_checked_fixture (tc_spmr, mock_setup, NULL); + tcase_add_test (tc_spmr, test_spmr_pass_001); + + TCase* tc_peer_spmr = tcase_create ("peer-spmr"); + suite_add_tcase (s, tc_peer_spmr); + tcase_add_checked_fixture (tc_peer_spmr, mock_setup, NULL); + tcase_add_test (tc_peer_spmr, test_peer_spmr_pass_001); + + TCase* tc_lost = tcase_create ("lost"); + suite_add_tcase (s, tc_lost); + tcase_add_checked_fixture (tc_lost, mock_setup, NULL); + tcase_add_test (tc_lost, test_lost_pass_001); + + TCase* tc_abort_on_lost = tcase_create ("abort-on-lost"); + suite_add_tcase (s, tc_abort_on_lost); + tcase_add_checked_fixture (tc_abort_on_lost, mock_setup, NULL); + tcase_add_test (tc_abort_on_lost, test_abort_on_lost_pass_001); + + TCase* tc_then_lost = tcase_create ("then-lost"); + suite_add_tcase (s, tc_then_lost); + tcase_add_checked_fixture (tc_then_lost, mock_setup, NULL); + tcase_add_test (tc_then_lost, test_then_lost_pass_001); + + TCase* tc_then_abort_on_lost = tcase_create ("then-abort-on-lost"); + suite_add_tcase (s, tc_then_abort_on_lost); + tcase_add_checked_fixture (tc_then_abort_on_lost, mock_setup, NULL); + tcase_add_test (tc_then_abort_on_lost, test_then_abort_on_lost_pass_001); + + TCase* tc_on_data = tcase_create ("on-data"); + suite_add_tcase (s, tc_on_data); + tcase_add_checked_fixture (tc_on_data, mock_setup, NULL); + tcase_add_test (tc_on_data, test_on_data_pass_001); + + TCase* tc_on_zero = tcase_create ("on-zero"); + suite_add_tcase (s, tc_on_zero); + tcase_add_checked_fixture (tc_on_zero, mock_setup, NULL); + tcase_add_test (tc_on_zero, test_on_zero_pass_001); + + TCase* tc_on_many_data = tcase_create ("on-many-data"); + suite_add_tcase (s, tc_on_many_data); + tcase_add_checked_fixture (tc_on_many_data, mock_setup, NULL); + tcase_add_test (tc_on_many_data, test_on_many_data_pass_001); + + TCase* tc_recv = tcase_create ("recv"); + suite_add_tcase (s, tc_recv); + tcase_add_checked_fixture (tc_recv, mock_setup, NULL); + tcase_add_test (tc_recv, test_recv_fail_001); + + TCase* tc_recvfrom = tcase_create ("recvfrom"); + suite_add_tcase (s, tc_recvfrom); + tcase_add_checked_fixture (tc_recvfrom, mock_setup, NULL); + tcase_add_test (tc_recvfrom, test_recvfrom_fail_001); + + TCase* tc_recvmsg = tcase_create ("recvmsg"); + suite_add_tcase (s, tc_recvmsg); + tcase_add_checked_fixture (tc_recvmsg, mock_setup, NULL); + tcase_add_test (tc_recvmsg, test_recvmsg_fail_001); + + TCase* tc_recvmsgv = tcase_create ("recvmsgv"); + suite_add_tcase (s, tc_recvmsgv); + tcase_add_checked_fixture (tc_recvmsgv, mock_setup, NULL); + tcase_add_test (tc_recvmsgv, test_recvmsgv_fail_001); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/reed_solomon.c b/3rdparty/openpgm-svn-r1135/pgm/reed_solomon.c new file mode 100644 index 0000000..a9a292c --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/reed_solomon.c @@ -0,0 +1,576 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Reed-Solomon forward error correction based on Vandermonde matrices. + * + * Output is incompatible with BCH style Reed-Solomon encoding. + * + * draft-ietf-rmt-bb-fec-rs-05.txt + * + rfc5052 + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + + +/* Vector GF(2⁸) plus-equals multiplication. + * + * d[] += b • s[] + */ + +static +void +_pgm_gf_vec_addmul ( + pgm_gf8_t* restrict d, + const pgm_gf8_t b, + const pgm_gf8_t* restrict s, + uint16_t len /* length of vectors */ + ) +{ + uint_fast16_t i; + uint_fast16_t count8; + + if (PGM_UNLIKELY(b == 0)) + return; + +#ifdef CONFIG_GALOIS_MUL_LUT + const pgm_gf8_t* gfmul_b = &pgm_gftable[ (uint16_t)b << 8 ]; +#endif + + i = 0; + count8 = len >> 3; /* 8-way unrolls */ + if (count8) + { + while (count8--) { +#ifdef CONFIG_GALOIS_MUL_LUT + d[i ] ^= gfmul_b[ s[i ] ]; + d[i+1] ^= gfmul_b[ s[i+1] ]; + d[i+2] ^= gfmul_b[ s[i+2] ]; + d[i+3] ^= gfmul_b[ s[i+3] ]; + d[i+4] ^= gfmul_b[ s[i+4] ]; + d[i+5] ^= gfmul_b[ s[i+5] ]; + d[i+6] ^= gfmul_b[ s[i+6] ]; + d[i+7] ^= gfmul_b[ s[i+7] ]; +#else + d[i ] ^= gfmul( b, s[i ] ); + d[i+1] ^= gfmul( b, s[i+1] ); + d[i+2] ^= gfmul( b, s[i+2] ); + d[i+3] ^= gfmul( b, s[i+3] ); + d[i+4] ^= gfmul( b, s[i+4] ); + d[i+5] ^= gfmul( b, s[i+5] ); + d[i+6] ^= gfmul( b, s[i+6] ); + d[i+7] ^= gfmul( b, s[i+7] ); +#endif + i += 8; + } + +/* remaining */ + len %= 8; + } + + while (len--) { +#ifdef CONFIG_GALOIS_MUL_LUT + d[i] ^= gfmul_b[ s[i] ]; +#else + d[i] ^= gfmul( b, s[i] ); +#endif + i++; + } +} + +/* Basic matrix multiplication. + * + * C = AB + * n + * c_i,j = ∑ a_i,j × b_r,j = a_i,1 × b_1,j + a_i,2 × b_2,j + ⋯ + a_i,n × b_n,j + * r=1 + */ + +static +void +_pgm_matmul ( + const pgm_gf8_t* restrict a, /* m-by-n */ + const pgm_gf8_t* restrict b, /* n-by-p */ + pgm_gf8_t* restrict c, /* ∴ m-by-p */ + const uint16_t m, + const uint16_t n, + const uint16_t p + ) +{ + for (uint_fast16_t j = 0; j < m; j++) + { + for (uint_fast16_t i = 0; i < p; i++) + { + pgm_gf8_t sum = 0; + + for (uint_fast16_t k = 0; k < n; k++) + { + sum ^= pgm_gfmul ( a[ (j * n) + k ], b[ (k * p) + i ] ); + } + + c[ (j * p) + i ] = sum; + } + } +} + +/* Generic square matrix inversion + */ + +#ifdef CONFIG_XOR_SWAP +/* whilst cute the xor swap is quite slow */ +#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) +#else +#define SWAP(a, b) do { const pgm_gf8_t _t = (b); (b) = (a); (a) = _t; } while (0) +#endif + +static +void +_pgm_matinv ( + pgm_gf8_t* M, /* is n-by-n */ + const uint8_t n + ) +{ + uint8_t pivot_rows[ n ]; + uint8_t pivot_cols[ n ]; + bool pivots[ n ]; + memset (pivots, 0, sizeof(pivots)); + + pgm_gf8_t identity[ n ]; + memset (identity, 0, sizeof(identity)); + + for (uint_fast8_t i = 0; i < n; i++) + { + uint_fast8_t row = 0, col = 0; + +/* check diagonal for new pivot */ + if (!pivots[ i ] && M[ (i * n) + i ]) + { + row = col = i; + } + else + { + for (uint_fast8_t j = 0; j < n; j++) + { + if (pivots[ j ]) continue; + + for (uint_fast8_t x = 0; x < n; x++) + { + if (!pivots[ x ] && M[ (j * n) + x ]) + { + row = j; + col = x; + goto found; + } + } + } + } + +found: + pivots[ col ] = TRUE; + +/* pivot */ + if (row != col) + { + for (uint_fast8_t x = 0; x < n; x++) + { + pgm_gf8_t *pivot_row = &M[ (row * n) + x ], + *pivot_col = &M[ (col * n) + x ]; + SWAP( *pivot_row, *pivot_col ); + } + } + +/* save location */ + pivot_rows[ i ] = row; + pivot_cols[ i ] = col; + +/* divide row by pivot element */ + if (M[ (col * n) + col ] != 1) + { + const pgm_gf8_t c = M[ (col * n) + col ]; + M[ (col * n) + col ] = 1; + + for (uint_fast8_t x = 0; x < n; x++) + { + M[ (col * n) + x ] = pgm_gfdiv( M[ (col * n) + x ], c ); + } + } + +/* reduce if not an identity row */ + identity[ col ] = 1; + if (memcmp (&M[ (col * n) ], identity, n * sizeof(pgm_gf8_t))) + { + for ( uint_fast8_t x = 0; + x < n; + x++ ) + { + if (x == col) continue; + + const pgm_gf8_t c = M[ (x * n) + col ]; + M[ (x * n) + col ] = 0; + + _pgm_gf_vec_addmul (&M[ x * n ], c, &M[ col * n ], n); + } + } + identity[ col ] = 0; + } + +/* revert all pivots */ + for (int_fast16_t i = n - 1; i >= 0; i--) + { + if (pivot_rows[ i ] != pivot_cols[ i ]) + { + for (uint_fast8_t j = 0; j < n; j++) + { + pgm_gf8_t *pivot_row = &M[ (j * n) + pivot_rows[ i ] ], + *pivot_col = &M[ (j * n) + pivot_cols[ i ] ]; + SWAP( *pivot_row, *pivot_col ); + } + } + } +} + +/* Gauss–Jordan elimination optimised for Vandermonde matrices + * + * matrix = matrix⁻¹ + * + * A Vandermonde matrix exhibits geometric progression in each row: + * + * ⎡ 1 α₁ α₁² ⋯ α₁^^(n-1) ⎤ + * V = ⎢ 1 α₂ α₂² ⋯ α₂^^(n-1) ⎥ + * ⎣ 1 α₃ α₃² ⋯ α₃^^(n-1) ⎦ + * + * First column is actually α_m⁰, second column is α_m¹. + * + * As only the second column is actually unique so optimise from that. + */ + +static +void +_pgm_matinv_vandermonde ( + pgm_gf8_t* V, /* is n-by-n */ + const uint8_t n + ) +{ +/* trivial cases */ + if (n == 1) return; + +/* P_j(α) is polynomial of degree n - 1 defined by + * + * n + * P_j(α) = ∏ (α - α_m) + * m=1 + * + * 1: Work out coefficients. + */ + + pgm_gf8_t P[ n ]; + memset (P, 0, sizeof(P)); + +/* copy across second row, i.e. j = 2 */ + for (uint_fast8_t i = 0; i < n; i++) + { + P[ i ] = V[ (i * n) + 1 ]; + } + + pgm_gf8_t alpha[ n ]; + memset (alpha, 0, sizeof(alpha)); + + alpha[ n - 1 ] = P[ 0 ]; + for (uint_fast8_t i = 1; i < n; i++) + { + for (uint_fast8_t j = (n - i); j < (n - 1); j++) + { + alpha[ j ] ^= pgm_gfmul( P[ i ], alpha[ j + 1 ] ); + } + alpha[ n - 1 ] ^= P[ i ]; + } + +/* 2: Obtain numberators and denominators by synthetic division. + */ + + pgm_gf8_t b[ n ]; + b[ n - 1 ] = 1; + for (uint_fast8_t j = 0; j < n; j++) + { + const pgm_gf8_t xx = P[ j ]; + pgm_gf8_t t = 1; + +/* skip first iteration */ + for (int_fast16_t i = n - 2; i >= 0; i--) + { + b[ i ] = alpha[ i + 1 ] ^ pgm_gfmul( xx, b[ i + 1 ] ); + t = pgm_gfmul( xx, t ) ^ b[ i ]; + } + + for (uint_fast8_t i = 0; i < n; i++) + { + V[ (i * n) + j ] = pgm_gfdiv ( b[ i ], t ); + } + } +} + +/* create the generator matrix of a reed-solomon code. + * + * s GM e + * ⎧ ⎡ s₀ ⎤ ⎡ 1 0 0 ⎤ ⎡ e₀ ⎤ ⎫ + * ⎪ ⎢ ⋮ ⎥ ⎢ 0 1 ⎥ = ⎢ ⋮ ⎥ ⎬ n + * k ⎨ ⎢ ⋮ ⎥ × ⎢ ⋱ ⎥ ⎣e_{n-1}⎦ ⎭ + * ⎪ ⎢ ⋮ ⎥ ⎢ ⋱ ⎥ + * ⎩ ⎣s_{k-1}⎦ ⎣ 0 0 1 ⎦ + * + * e = s × GM + */ + +void +pgm_rs_create ( + pgm_rs_t* rs, + const uint8_t n, + const uint8_t k + ) +{ + pgm_assert (NULL != rs); + pgm_assert (n > 0); + pgm_assert (k > 0); + + rs->n = n; + rs->k = k; + rs->GM = pgm_new0 (pgm_gf8_t, n * k); + rs->RM = pgm_new0 (pgm_gf8_t, k * k); + +/* alpha = root of primitive polynomial of degree m + * ( 1 + x² + x³ + x⁴ + x⁸ ) + * + * V = Vandermonde matrix of k rows and n columns. + * + * Be careful, Harry! + */ +#ifdef CONFIG_PREFER_MALLOC + pgm_gf8_t* V = pgm_new0 (pgm_gf8_t, n * k); +#else + pgm_gf8_t* V = pgm_newa (pgm_gf8_t, n * k); + memset (V, 0, n * k); +#endif + pgm_gf8_t* p = V + k; + V[0] = 1; + for (uint_fast8_t j = 0; j < (n - 1); j++) + { + for (uint_fast8_t i = 0; i < k; i++) + { +/* the {i, j} entry of V_{k,n} is v_{i,j} = α^^(i×j), + * where 0 <= i <= k - 1 and 0 <= j <= n - 1. + */ + *p++ = pgm_gfantilog[ ( i * j ) % PGM_GF_MAX ]; + } + } + +/* This generator matrix would create a Maximum Distance Separable (MDS) + * matrix, a systematic result is required, i.e. original data is left + * unchanged. + * + * GM = V_{k,k}⁻¹ × V_{k,n} + * + * 1: matrix V_{k,k} formed by the first k columns of V_{k,n} + */ + pgm_gf8_t* V_kk = V; + pgm_gf8_t* V_kn = V + (k * k); + +/* 2: invert it + */ + _pgm_matinv_vandermonde (V_kk, k); + +/* 3: multiply by V_{k,n} + */ + _pgm_matmul (V_kn, V_kk, rs->GM + (k * k), n - k, k, k); + +#ifdef CONFIG_PREFER_MALLOC + pgm_free (V); +#endif + +/* 4: set identity matrix for original data + */ + for (uint_fast8_t i = 0; i < k; i++) + { + rs->GM[ (i * k) + i ] = 1; + } +} + +void +pgm_rs_destroy ( + pgm_rs_t* rs + ) +{ + pgm_assert (NULL != rs); + + if (rs->RM) { + pgm_free (rs->RM); + rs->RM = NULL; + } + + if (rs->GM) { + pgm_free (rs->GM); + rs->GM = NULL; + } +} + +/* create a parity packet from a vector of original data packets and + * FEC block packet offset. + */ + +void +pgm_rs_encode ( + pgm_rs_t* restrict rs, + const pgm_gf8_t** restrict src, /* length rs_t::k */ + const uint8_t offset, + pgm_gf8_t* restrict dst, + const uint16_t len + ) +{ + pgm_assert (NULL != rs); + pgm_assert (NULL != src); + pgm_assert (offset >= rs->k && offset < rs->n); /* parity packet */ + pgm_assert (NULL != dst); + pgm_assert (len > 0); + + memset (dst, 0, len); + for (uint_fast8_t i = 0; i < rs->k; i++) + { + const pgm_gf8_t c = rs->GM[ (offset * rs->k) + i ]; + _pgm_gf_vec_addmul (dst, c, src[i], len); + } +} + +/* original data block of packets with missing packet entries replaced + * with on-demand parity packets. + */ + +void +pgm_rs_decode_parity_inline ( + pgm_rs_t* restrict rs, + pgm_gf8_t** restrict block, /* length rs_t::k */ + const uint8_t* restrict offsets, /* offsets within FEC block, 0 < offset < n */ + const uint16_t len /* packet length */ + ) +{ + pgm_assert (NULL != rs); + pgm_assert (NULL != block); + pgm_assert (NULL != offsets); + pgm_assert (len > 0); + +/* create new recovery matrix from generator + */ + for (uint_fast8_t i = 0; i < rs->k; i++) + { + if (offsets[i] < rs->k) { + memset (&rs->RM[ i * rs->k ], 0, rs->k * sizeof(pgm_gf8_t)); + rs->RM[ (i * rs->k) + i ] = 1; + continue; + } + memcpy (&rs->RM[ i * rs->k ], &rs->GM[ offsets[ i ] * rs->k ], rs->k * sizeof(pgm_gf8_t)); + } + +/* invert */ + _pgm_matinv (rs->RM, rs->k); + + pgm_gf8_t* repairs[ rs->k ]; + +/* multiply out, through the length of erasures[] */ + for (uint_fast8_t j = 0; j < rs->k; j++) + { + if (offsets[ j ] < rs->k) + continue; + +#ifdef CONFIG_PREFER_MALLOC + pgm_gf8_t* erasure = repairs[ j ] = pgm_malloc0 (len); +#else + pgm_gf8_t* erasure = repairs[ j ] = pgm_alloca (len); + memset (erasure, 0, len); +#endif + for (uint_fast8_t i = 0; i < rs->k; i++) + { + pgm_gf8_t* src = block[ i ]; + pgm_gf8_t c = rs->RM[ (j * rs->k) + i ]; + _pgm_gf_vec_addmul (erasure, c, src, len); + } + } + +/* move repaired over parity packets */ + for (uint_fast8_t j = 0; j < rs->k; j++) + { + if (offsets[ j ] < rs->k) + continue; + + memcpy (block[ j ], repairs[ j ], len * sizeof(pgm_gf8_t)); +#ifdef CONFIG_PREFER_MALLOC + pgm_free (repairs[ j ]); +#endif + } +} + +/* entire FEC block of original data and parity packets. + * + * erased packet buffers must be zeroed. + */ +void +pgm_rs_decode_parity_appended ( + pgm_rs_t* restrict rs, + pgm_gf8_t** restrict block, /* length rs_t::n, the FEC block */ + const uint8_t* restrict offsets, /* ordered index of packets */ + const uint16_t len /* packet length */ + ) +{ + pgm_assert (NULL != rs); + pgm_assert (NULL != block); + pgm_assert (NULL != offsets); + pgm_assert (len > 0); + +/* create new recovery matrix from generator + */ + for (uint_fast8_t i = 0; i < rs->k; i++) + { + if (offsets[i] < rs->k) { + memset (&rs->RM[ i * rs->k ], 0, rs->k * sizeof(pgm_gf8_t)); + rs->RM[ (i * rs->k) + i ] = 1; + continue; + } + memcpy (&rs->RM[ i * rs->k ], &rs->GM[ offsets[ i ] * rs->k ], rs->k * sizeof(pgm_gf8_t)); + } + +/* invert */ + _pgm_matinv (rs->RM, rs->k); + +/* multiply out, through the length of erasures[] */ + for (uint_fast8_t j = 0; j < rs->k; j++) + { + if (offsets[ j ] < rs->k) + continue; + + uint_fast8_t p = rs->k; + pgm_gf8_t* erasure = block[ j ]; + for (uint_fast8_t i = 0; i < rs->k; i++) + { + pgm_gf8_t* src; + if (offsets[ i ] < rs->k) + src = block[ i ]; + else + src = block[ p++ ]; + const pgm_gf8_t c = rs->RM[ (j * rs->k) + i ]; + _pgm_gf_vec_addmul (erasure, c, src, len); + } + } +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/reed_solomon.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/reed_solomon.c.c89.patch new file mode 100644 index 0000000..93b2ee2 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/reed_solomon.c.c89.patch @@ -0,0 +1,467 @@ +--- reed_solomon.c 2010-05-21 11:35:32.000000000 +0800 ++++ reed_solomon.c89 2010-08-04 16:46:52.000000000 +0800 +@@ -48,6 +48,7 @@ + return; + + #ifdef CONFIG_GALOIS_MUL_LUT ++ { + const pgm_gf8_t* gfmul_b = &pgm_gftable[ (uint16_t)b << 8 ]; + #endif + +@@ -90,6 +91,10 @@ + #endif + i++; + } ++ ++#ifdef CONFIG_GALOIS_MUL_LUT ++ } ++#endif + } + + /* Basic matrix multiplication. +@@ -111,19 +116,28 @@ + const uint16_t p + ) + { +- for (uint_fast16_t j = 0; j < m; j++) + { +- for (uint_fast16_t i = 0; i < p; i++) ++ uint_fast16_t j; ++ for (j = 0; j < m; j++) ++ { ++ { ++ uint_fast16_t i; ++ for (i = 0; i < p; i++) + { + pgm_gf8_t sum = 0; + +- for (uint_fast16_t k = 0; k < n; k++) ++ { ++ uint_fast16_t k; ++ for (k = 0; k < n; k++) + { + sum ^= pgm_gfmul ( a[ (j * n) + k ], b[ (k * p) + i ] ); + } ++ } + + c[ (j * p) + i ] = sum; + } ++ } ++ } + } + } + +@@ -144,15 +158,16 @@ + const uint8_t n + ) + { +- uint8_t pivot_rows[ n ]; +- uint8_t pivot_cols[ n ]; +- bool pivots[ n ]; ++ uint8_t* pivot_rows = pgm_newa (uint8_t, n); ++ uint8_t* pivot_cols = pgm_newa (uint8_t, n); ++ bool* pivots = pgm_newa (bool, n); ++ pgm_gf8_t* identity = pgm_newa (pgm_gf8_t, n); + memset (pivots, 0, sizeof(pivots)); +- +- pgm_gf8_t identity[ n ]; + memset (identity, 0, sizeof(identity)); + +- for (uint_fast8_t i = 0; i < n; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < n; i++) + { + uint_fast8_t row = 0, col = 0; + +@@ -163,11 +178,15 @@ + } + else + { +- for (uint_fast8_t j = 0; j < n; j++) ++ { ++ uint_fast8_t j; ++ for (j = 0; j < n; j++) + { + if (pivots[ j ]) continue; + +- for (uint_fast8_t x = 0; x < n; x++) ++ { ++ uint_fast8_t x; ++ for (x = 0; x < n; x++) + { + if (!pivots[ x ] && M[ (j * n) + x ]) + { +@@ -176,6 +195,8 @@ + goto found; + } + } ++ } ++ } + } + } + +@@ -185,12 +206,15 @@ + /* pivot */ + if (row != col) + { +- for (uint_fast8_t x = 0; x < n; x++) ++ { ++ uint_fast8_t x; ++ for (x = 0; x < n; x++) + { + pgm_gf8_t *pivot_row = &M[ (row * n) + x ], + *pivot_col = &M[ (col * n) + x ]; + SWAP( *pivot_row, *pivot_col ); + } ++ } + } + + /* save location */ +@@ -203,44 +227,59 @@ + const pgm_gf8_t c = M[ (col * n) + col ]; + M[ (col * n) + col ] = 1; + +- for (uint_fast8_t x = 0; x < n; x++) ++ { ++ uint_fast8_t x; ++ for (x = 0; x < n; x++) + { + M[ (col * n) + x ] = pgm_gfdiv( M[ (col * n) + x ], c ); + } ++ } + } + + /* reduce if not an identity row */ + identity[ col ] = 1; + if (memcmp (&M[ (col * n) ], identity, n * sizeof(pgm_gf8_t))) + { +- for ( uint_fast8_t x = 0; ++ { ++ uint_fast8_t x; ++ for ( x = 0; + x < n; + x++ ) + { + if (x == col) continue; + ++ { + const pgm_gf8_t c = M[ (x * n) + col ]; + M[ (x * n) + col ] = 0; + + _pgm_gf_vec_addmul (&M[ x * n ], c, &M[ col * n ], n); ++ } ++ } + } + } + identity[ col ] = 0; + } ++ } + + /* revert all pivots */ +- for (int_fast16_t i = n - 1; i >= 0; i--) ++ { ++ int_fast16_t i; ++ for (i = n - 1; i >= 0; i--) + { + if (pivot_rows[ i ] != pivot_cols[ i ]) + { +- for (uint_fast8_t j = 0; j < n; j++) ++ { ++ uint_fast8_t j; ++ for (j = 0; j < n; j++) + { + pgm_gf8_t *pivot_row = &M[ (j * n) + pivot_rows[ i ] ], + *pivot_col = &M[ (j * n) + pivot_cols[ i ] ]; + SWAP( *pivot_row, *pivot_col ); + } ++ } + } + } ++ } + } + + /* Gauss–Jordan elimination optimised for Vandermonde matrices +@@ -277,49 +316,73 @@ + * 1: Work out coefficients. + */ + +- pgm_gf8_t P[ n ]; ++ { ++ pgm_gf8_t* P = pgm_newa (pgm_gf8_t, n); + memset (P, 0, sizeof(P)); + + /* copy across second row, i.e. j = 2 */ +- for (uint_fast8_t i = 0; i < n; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < n; i++) + { + P[ i ] = V[ (i * n) + 1 ]; + } ++ } + +- pgm_gf8_t alpha[ n ]; ++ { ++ pgm_gf8_t* alpha = pgm_newa (pgm_gf8_t, n); + memset (alpha, 0, sizeof(alpha)); + + alpha[ n - 1 ] = P[ 0 ]; +- for (uint_fast8_t i = 1; i < n; i++) + { +- for (uint_fast8_t j = (n - i); j < (n - 1); j++) ++ uint_fast8_t i; ++ for (i = 1; i < n; i++) ++ { ++ { ++ uint_fast8_t j; ++ for (j = (n - i); j < (n - 1); j++) + { + alpha[ j ] ^= pgm_gfmul( P[ i ], alpha[ j + 1 ] ); + } ++ } + alpha[ n - 1 ] ^= P[ i ]; + } ++ } + + /* 2: Obtain numberators and denominators by synthetic division. + */ + +- pgm_gf8_t b[ n ]; ++ { ++ pgm_gf8_t* b = pgm_newa (pgm_gf8_t, n); + b[ n - 1 ] = 1; +- for (uint_fast8_t j = 0; j < n; j++) ++ { ++ uint_fast8_t j; ++ for (j = 0; j < n; j++) + { + const pgm_gf8_t xx = P[ j ]; + pgm_gf8_t t = 1; + + /* skip first iteration */ +- for (int_fast16_t i = n - 2; i >= 0; i--) ++ { ++ int_fast16_t i; ++ for (i = n - 2; i >= 0; i--) + { + b[ i ] = alpha[ i + 1 ] ^ pgm_gfmul( xx, b[ i + 1 ] ); + t = pgm_gfmul( xx, t ) ^ b[ i ]; + } ++ } + +- for (uint_fast8_t i = 0; i < n; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < n; i++) + { + V[ (i * n) + j ] = pgm_gfdiv ( b[ i ], t ); + } ++ } ++ } ++ } ++ } ++ } + } + } + +@@ -358,23 +421,31 @@ + * + * Be careful, Harry! + */ ++ { + #ifdef CONFIG_PREFER_MALLOC + pgm_gf8_t* V = pgm_new0 (pgm_gf8_t, n * k); + #else + pgm_gf8_t* V = pgm_newa (pgm_gf8_t, n * k); + memset (V, 0, n * k); + #endif ++ { + pgm_gf8_t* p = V + k; + V[0] = 1; +- for (uint_fast8_t j = 0; j < (n - 1); j++) + { +- for (uint_fast8_t i = 0; i < k; i++) ++ uint_fast8_t j; ++ for (j = 0; j < (n - 1); j++) ++ { ++ { ++ uint_fast8_t i; ++ for (i = 0; i < k; i++) + { + /* the {i, j} entry of V_{k,n} is v_{i,j} = α^^(i×j), + * where 0 <= i <= k - 1 and 0 <= j <= n - 1. + */ + *p++ = pgm_gfantilog[ ( i * j ) % PGM_GF_MAX ]; + } ++ } ++ } + } + + /* This generator matrix would create a Maximum Distance Separable (MDS) +@@ -385,6 +456,7 @@ + * + * 1: matrix V_{k,k} formed by the first k columns of V_{k,n} + */ ++ { + pgm_gf8_t* V_kk = V; + pgm_gf8_t* V_kn = V + (k * k); + +@@ -402,10 +474,16 @@ + + /* 4: set identity matrix for original data + */ +- for (uint_fast8_t i = 0; i < k; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < k; i++) + { + rs->GM[ (i * k) + i ] = 1; + } ++ } ++ } ++ } ++ } + } + + void +@@ -446,11 +524,14 @@ + pgm_assert (len > 0); + + memset (dst, 0, len); +- for (uint_fast8_t i = 0; i < rs->k; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < rs->k; i++) + { + const pgm_gf8_t c = rs->GM[ (offset * rs->k) + i ]; + _pgm_gf_vec_addmul (dst, c, src[i], len); + } ++ } + } + + /* original data block of packets with missing packet entries replaced +@@ -472,7 +553,9 @@ + + /* create new recovery matrix from generator + */ +- for (uint_fast8_t i = 0; i < rs->k; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < rs->k; i++) + { + if (offsets[i] < rs->k) { + memset (&rs->RM[ i * rs->k ], 0, rs->k * sizeof(pgm_gf8_t)); +@@ -481,34 +564,46 @@ + } + memcpy (&rs->RM[ i * rs->k ], &rs->GM[ offsets[ i ] * rs->k ], rs->k * sizeof(pgm_gf8_t)); + } ++ } + + /* invert */ + _pgm_matinv (rs->RM, rs->k); + +- pgm_gf8_t* repairs[ rs->k ]; ++ { ++ pgm_gf8_t** repairs = pgm_newa (pgm_gf8_t*, rs->k); + + /* multiply out, through the length of erasures[] */ +- for (uint_fast8_t j = 0; j < rs->k; j++) ++ { ++ uint_fast8_t j; ++ for (j = 0; j < rs->k; j++) + { + if (offsets[ j ] < rs->k) + continue; + ++ { + #ifdef CONFIG_PREFER_MALLOC + pgm_gf8_t* erasure = repairs[ j ] = pgm_malloc0 (len); + #else + pgm_gf8_t* erasure = repairs[ j ] = pgm_alloca (len); + memset (erasure, 0, len); + #endif +- for (uint_fast8_t i = 0; i < rs->k; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < rs->k; i++) + { + pgm_gf8_t* src = block[ i ]; + pgm_gf8_t c = rs->RM[ (j * rs->k) + i ]; + _pgm_gf_vec_addmul (erasure, c, src, len); + } ++ } ++ } ++ } + } + + /* move repaired over parity packets */ +- for (uint_fast8_t j = 0; j < rs->k; j++) ++ { ++ uint_fast8_t j; ++ for (j = 0; j < rs->k; j++) + { + if (offsets[ j ] < rs->k) + continue; +@@ -518,6 +613,8 @@ + pgm_free (repairs[ j ]); + #endif + } ++ } ++ } + } + + /* entire FEC block of original data and parity packets. +@@ -539,7 +636,9 @@ + + /* create new recovery matrix from generator + */ +- for (uint_fast8_t i = 0; i < rs->k; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < rs->k; i++) + { + if (offsets[i] < rs->k) { + memset (&rs->RM[ i * rs->k ], 0, rs->k * sizeof(pgm_gf8_t)); +@@ -548,28 +647,39 @@ + } + memcpy (&rs->RM[ i * rs->k ], &rs->GM[ offsets[ i ] * rs->k ], rs->k * sizeof(pgm_gf8_t)); + } ++ } + + /* invert */ + _pgm_matinv (rs->RM, rs->k); + + /* multiply out, through the length of erasures[] */ +- for (uint_fast8_t j = 0; j < rs->k; j++) ++ { ++ uint_fast8_t j; ++ for (j = 0; j < rs->k; j++) + { + if (offsets[ j ] < rs->k) + continue; + ++ { + uint_fast8_t p = rs->k; + pgm_gf8_t* erasure = block[ j ]; +- for (uint_fast8_t i = 0; i < rs->k; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < rs->k; i++) + { + pgm_gf8_t* src; + if (offsets[ i ] < rs->k) + src = block[ i ]; + else + src = block[ p++ ]; ++ { + const pgm_gf8_t c = rs->RM[ (j * rs->k) + i ]; + _pgm_gf_vec_addmul (erasure, c, src, len); ++ } ++ } + } ++ } ++ } + } + } + diff --git a/3rdparty/openpgm-svn-r1135/pgm/reed_solomon_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/reed_solomon_unittest.c new file mode 100644 index 0000000..5e0e75e --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/reed_solomon_unittest.c @@ -0,0 +1,305 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for Reed-Solomon forward error correction based on Vandermonde matrices. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include + + +/* mock state */ + + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + + +#define REED_SOLOMON_DEBUG +#include "reed_solomon.c" + + +/* target: + * void + * pgm_rs_create ( + * pgm_rs_t* rs, + * const uint8_t n, + * const uint8_t k + * ) + */ + +START_TEST (test_create_pass_001) +{ + pgm_rs_t rs; + pgm_rs_create (&rs, 255, 16); +} +END_TEST + +START_TEST (test_create_fail_001) +{ + pgm_rs_create (NULL, 255, 16); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_rs_destroy ( + * pgm_rs_t* rs, + * ) + */ + +START_TEST (test_destroy_pass_001) +{ + pgm_rs_t rs; + pgm_rs_create (&rs, 255, 16); + pgm_rs_destroy (&rs); +} +END_TEST + +START_TEST (test_destroy_fail_001) +{ + pgm_rs_destroy (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_rs_encode ( + * pgm_rs_t* rs, + * const pgm_gf8_t** src, + * const uint8_t offset, + * pgm_gf8_t* dst, + * const uint16_t len + * ) + */ + +START_TEST (test_encode_pass_001) +{ + const gchar source[] = "i am not a string"; + const guint16 source_len = strlen (source); + pgm_rs_t rs; + const guint8 k = source_len; + const guint8 parity_index = k; + const guint16 packet_len = 100; + pgm_gf8_t* source_packets[k]; + pgm_gf8_t* parity_packet = g_malloc0 (packet_len); + pgm_rs_create (&rs, 255, k); + for (unsigned i = 0; i < k; i++) { + source_packets[i] = g_malloc0 (packet_len); + source_packets[i][0] = source[i]; + g_message ("packet#%2.2d: 0x%02.2x '%c'", i, source[i], source[i]); + } + pgm_rs_encode (&rs, (const pgm_gf8_t**)source_packets, parity_index, parity_packet, packet_len); + g_message ("parity-packet: %02.2x", parity_packet[0]); + pgm_rs_destroy (&rs); +} +END_TEST + +START_TEST (test_encode_fail_001) +{ + pgm_rs_encode (NULL, NULL, 0, NULL, 0); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_rs_decode_parity_inline ( + * pgm_rs_t* rs, + * pgm_gf8_t** block, + * const uint8_t* offsets, + * const uint16_t len + * ) + */ + +START_TEST (test_decode_parity_inline_pass_001) +{ + const gchar source[] = "i am not a string"; + const guint16 source_len = strlen (source); + pgm_rs_t rs; + const guint8 k = source_len; + const guint8 parity_index = k; + const guint16 packet_len = 100; + pgm_gf8_t* source_packets[k]; + pgm_gf8_t* parity_packet = g_malloc0 (packet_len); + pgm_rs_create (&rs, 255, k); + for (unsigned i = 0; i < k; i++) { + source_packets[i] = g_malloc0 (packet_len); + source_packets[i][0] = source[i]; + } + pgm_rs_encode (&rs, (const pgm_gf8_t**)source_packets, parity_index, parity_packet, packet_len); +/* simulate error occuring at index #3 */ + const guint erased_index = 3; + source_packets[erased_index][0] = 'X'; + for (unsigned i = 0; i < k; i++) { + g_message ("damaged-packet#%2.2d: 0x%02.2x '%c'", + i, source_packets[i][0], source_packets[i][0]); + } + guint8 offsets[k]; + for (unsigned i = 0; i < k; i++) + offsets[i] = i; +/* erased offset now points to parity packet at k */ + offsets[erased_index] = parity_index; +/* move parity inline */ + g_free (source_packets[erased_index]); + source_packets[erased_index] = parity_packet; + pgm_rs_decode_parity_inline (&rs, source_packets, offsets, packet_len); + pgm_rs_destroy (&rs); + for (unsigned i = 0; i < k; i++) { + g_message ("repaired-packet#%2.2d: 0x%02.2x '%c'", + i, source_packets[i][0], source_packets[i][0]); + } +} +END_TEST + +START_TEST (test_decode_parity_inline_fail_001) +{ + pgm_rs_decode_parity_inline (NULL, NULL, NULL, 0); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_rs_decode_parity_appended ( + * pgm_rs_t* rs, + * pgm_gf8_t* block, + * const uint8_t* offsets, + * const uint16_t len + * ) + */ + +START_TEST (test_decode_parity_appended_pass_001) +{ + const gchar source[] = "i am not a string"; + const guint16 source_len = strlen (source); + pgm_rs_t rs; + const guint8 k = source_len; + const guint8 parity_index = k; + const guint16 packet_len = 100; + pgm_gf8_t* source_packets[k+1]; /* include 1 appended parity packet */ + pgm_gf8_t* parity_packet = g_malloc0 (packet_len); + pgm_rs_create (&rs, 255, k); + for (unsigned i = 0; i < k; i++) { + source_packets[i] = g_malloc0 (packet_len); + source_packets[i][0] = source[i]; + } + pgm_rs_encode (&rs, (const pgm_gf8_t**)source_packets, parity_index, parity_packet, packet_len); +/* simulate error occuring at index #3 */ + const guint erased_index = 3; + source_packets[erased_index][0] = 'X'; + for (unsigned i = 0; i < k; i++) { + g_message ("damaged-packet#%2.2d: 0x%02.2x '%c'", + i, source_packets[i][0], source_packets[i][0]); + } + guint8 offsets[k]; + for (unsigned i = 0; i < k; i++) + offsets[i] = i; +/* erased offset now points to parity packet at k */ + offsets[erased_index] = parity_index; +/* erase damaged packet */ + memset (source_packets[erased_index], 0, packet_len); +/* append parity to source packet block */ + source_packets[parity_index] = parity_packet; + pgm_rs_decode_parity_appended (&rs, source_packets, offsets, packet_len); + pgm_rs_destroy (&rs); + for (unsigned i = 0; i < k; i++) { + g_message ("repaired-packet#%2.2d: 0x%02.2x '%c'", + i, source_packets[i][0], source_packets[i][0]); + } +} +END_TEST + +START_TEST (test_decode_parity_appended_fail_001) +{ + pgm_rs_decode_parity_appended (NULL, NULL, NULL, 0); + fail ("reached"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_create = tcase_create ("create"); + suite_add_tcase (s, tc_create); + tcase_add_test (tc_create, test_create_pass_001); + tcase_add_test_raise_signal (tc_create, test_create_fail_001, SIGABRT); + + TCase* tc_destroy = tcase_create ("destroy"); + suite_add_tcase (s, tc_destroy); + tcase_add_test (tc_destroy, test_destroy_pass_001); + tcase_add_test_raise_signal (tc_destroy, test_destroy_fail_001, SIGABRT); + + TCase* tc_encode = tcase_create ("encode"); + suite_add_tcase (s, tc_encode); + tcase_add_test (tc_encode, test_encode_pass_001); + tcase_add_test_raise_signal (tc_encode, test_encode_fail_001, SIGABRT); + + TCase* tc_decode_parity_inline = tcase_create ("decode-parity-inline"); + suite_add_tcase (s, tc_decode_parity_inline); + tcase_add_test (tc_decode_parity_inline, test_decode_parity_inline_pass_001); + tcase_add_test_raise_signal (tc_decode_parity_inline, test_decode_parity_inline_fail_001, SIGABRT); + + TCase* tc_decode_parity_appended = tcase_create ("decode-parity-appended"); + suite_add_tcase (s, tc_decode_parity_appended); + tcase_add_test (tc_decode_parity_appended, test_decode_parity_appended_pass_001); + tcase_add_test_raise_signal (tc_decode_parity_appended, test_decode_parity_appended_fail_001, SIGABRT); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/rxw.c b/3rdparty/openpgm-svn-r1135/pgm/rxw.c new file mode 100644 index 0000000..a6891d9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/rxw.c @@ -0,0 +1,2233 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * A basic receive window: pointer array implementation. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __STDC_FORMAT_MACROS +#ifdef _MSC_VER +# include +#else +# include +#endif +#include +#include +#include + + +//#define RXW_DEBUG + +#ifndef RXW_DEBUG +# define PGM_DISABLE_ASSERT +#endif + + +/* testing function: is TSI null + * + * returns TRUE if null, returns FALSE if not null. + */ + +static inline +bool +_pgm_tsi_is_null ( + const void*const tsi + ) +{ + const union { + pgm_tsi_t tsi; + uint32_t l[2]; + } *u = tsi; + +/* pre-conditions */ + pgm_assert (NULL != tsi); + + return (0 == u->l[0] && 0 == u->l[1]); +} + +/* sequence state must be smaller than PGM skbuff control buffer */ +PGM_STATIC_ASSERT(sizeof(struct pgm_rxw_state_t) <= sizeof(((struct pgm_sk_buff_t*)0)->cb)); + +static void _pgm_rxw_define (pgm_rxw_t*const, const uint32_t); +static void _pgm_rxw_update_trail (pgm_rxw_t*const, const uint32_t); +static inline uint32_t _pgm_rxw_update_lead (pgm_rxw_t*const, const uint32_t, const pgm_time_t, const pgm_time_t); +static inline uint32_t _pgm_rxw_tg_sqn (pgm_rxw_t*const, const uint32_t); +static inline uint32_t _pgm_rxw_pkt_sqn (pgm_rxw_t*const, const uint32_t); +static inline bool _pgm_rxw_is_first_of_tg_sqn (pgm_rxw_t*const, const uint32_t); +static inline bool _pgm_rxw_is_last_of_tg_sqn (pgm_rxw_t*const, const uint32_t); +static int _pgm_rxw_insert (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict); +static int _pgm_rxw_append (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict, const pgm_time_t); +static int _pgm_rxw_add_placeholder_range (pgm_rxw_t*const, const uint32_t, const pgm_time_t, const pgm_time_t); +static void _pgm_rxw_unlink (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict); +static uint32_t _pgm_rxw_remove_trail (pgm_rxw_t*const); +static void _pgm_rxw_state (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict, const int); +static inline void _pgm_rxw_shuffle_parity (pgm_rxw_t*const restrict, struct pgm_sk_buff_t*const restrict); +static inline ssize_t _pgm_rxw_incoming_read (pgm_rxw_t*const restrict, struct pgm_msgv_t**restrict, uint32_t); +static bool _pgm_rxw_is_apdu_complete (pgm_rxw_t*const restrict, const uint32_t); +static inline ssize_t _pgm_rxw_incoming_read_apdu (pgm_rxw_t*const restrict, struct pgm_msgv_t**restrict); +static inline int _pgm_rxw_recovery_update (pgm_rxw_t*const, const uint32_t, const pgm_time_t); +static inline int _pgm_rxw_recovery_append (pgm_rxw_t*const, const pgm_time_t, const pgm_time_t); + + +/* returns the pointer at the given index of the window. + */ + +static +struct pgm_sk_buff_t* +_pgm_rxw_peek ( + const pgm_rxw_t* const window, + const uint32_t sequence + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + + if (pgm_rxw_is_empty (window)) + return NULL; + + if (pgm_uint32_gte (sequence, window->trail) && pgm_uint32_lte (sequence, window->lead)) + { + const uint_fast32_t index_ = sequence % pgm_rxw_max_length (window); + struct pgm_sk_buff_t* skb = window->pdata[index_]; +/* availability only guaranteed inside commit window */ + if (pgm_uint32_lt (sequence, window->commit_lead)) { + pgm_assert (NULL != skb); + pgm_assert (pgm_skb_is_valid (skb)); + pgm_assert (!_pgm_tsi_is_null (&skb->tsi)); + } + return skb; + } + + return NULL; +} + +/* sections of the receive window: + * + * | Commit | Incoming | + * |<---------------->|<------------>| + * | | | + * trail commit-lead lead + * + * commit buffers are currently held by the application, the window trail + * cannot be advanced if packets remain in the commit buffer. + * + * incoming buffers are waiting to be passed to the application. + */ + +static inline +uint32_t +_pgm_rxw_commit_length ( + const pgm_rxw_t* const window + ) +{ + pgm_assert (NULL != window); + return window->commit_lead - window->trail; +} + +static inline +bool +_pgm_rxw_commit_is_empty ( + const pgm_rxw_t* const window + ) +{ + pgm_assert (NULL != window); + return (_pgm_rxw_commit_length (window) == 0); +} + +static inline +uint32_t +_pgm_rxw_incoming_length ( + const pgm_rxw_t* const window + ) +{ + pgm_assert (NULL != window); + return ( 1 + window->lead ) - window->commit_lead; +} + +static inline +bool +_pgm_rxw_incoming_is_empty ( + const pgm_rxw_t* const window + ) +{ + pgm_assert (NULL != window); + return (_pgm_rxw_incoming_length (window) == 0); +} + +/* constructor for receive window. zero-length windows are not permitted. + * + * returns pointer to window. + */ + +pgm_rxw_t* +pgm_rxw_create ( + const pgm_tsi_t*const tsi, + const uint16_t tpdu_size, + const unsigned sqns, /* transmit window size in sequence numbers */ + const unsigned secs, /* size in seconds */ + const ssize_t max_rte, /* max bandwidth */ + const uint32_t ack_c_p + ) +{ + pgm_rxw_t* window; + +/* pre-conditions */ + pgm_assert (NULL != tsi); + pgm_assert_cmpuint (tpdu_size, >, 0); + if (sqns) { + pgm_assert_cmpuint (sqns, >, 0); + pgm_assert_cmpuint (sqns & PGM_UINT32_SIGN_BIT, ==, 0); + pgm_assert_cmpuint (secs, ==, 0); + pgm_assert_cmpuint (max_rte, ==, 0); + } else { + pgm_assert_cmpuint (secs, >, 0); + pgm_assert_cmpuint (max_rte, >, 0); + } + + pgm_debug ("create (tsi:%s max-tpdu:%" PRIu16 " sqns:%" PRIu32 " secs %u max-rte %zd ack-c_p %" PRIu32 ")", + pgm_tsi_print (tsi), tpdu_size, sqns, secs, max_rte, ack_c_p); + +/* calculate receive window parameters */ + pgm_assert (sqns || (secs && max_rte)); + const unsigned alloc_sqns = sqns ? sqns : ( (secs * max_rte) / tpdu_size ); + window = pgm_malloc0 (sizeof(pgm_rxw_t) + ( alloc_sqns * sizeof(struct pgm_sk_buff_t*) )); + + window->tsi = tsi; + window->max_tpdu = tpdu_size; + +/* empty state: + * + * trail = 0, lead = -1 + * commit_trail = commit_lead = rxw_trail = rxw_trail_init = 0 + */ + window->lead = -1; + window->trail = window->lead + 1; + +/* limit retransmit requests on late session joining */ + window->is_constrained = TRUE; + +/* minimum value of RS::k = 1 */ + window->tg_size = 1; + +/* PGMCC filter weight */ + window->ack_c_p = pgm_fp16 (ack_c_p); + window->bitmap = 0xffffffff; + +/* pointer array */ + window->alloc = alloc_sqns; + +/* post-conditions */ + pgm_assert_cmpuint (pgm_rxw_max_length (window), ==, alloc_sqns); + pgm_assert_cmpuint (pgm_rxw_length (window), ==, 0); + pgm_assert_cmpuint (pgm_rxw_size (window), ==, 0); + pgm_assert (pgm_rxw_is_empty (window)); + pgm_assert (!pgm_rxw_is_full (window)); + + return window; +} + +/* destructor for receive window. must not be called more than once for same window. + */ + +void +pgm_rxw_destroy ( + pgm_rxw_t* const window + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert_cmpuint (window->alloc, >, 0); + + pgm_debug ("destroy (window:%p)", (const void*)window); + +/* contents of window */ + while (!pgm_rxw_is_empty (window)) { + _pgm_rxw_remove_trail (window); + } + +/* window must now be empty */ + pgm_assert_cmpuint (pgm_rxw_length (window), ==, 0); + pgm_assert_cmpuint (pgm_rxw_size (window), ==, 0); + pgm_assert (pgm_rxw_is_empty (window)); + pgm_assert (!pgm_rxw_is_full (window)); + +/* window */ + pgm_free (window); +} + +/* add skb to receive window. window has fixed size and will not grow. + * PGM skbuff data/tail pointers must point to the PGM payload, and hence skb->len + * is allowed to be zero. + * + * if the skb sequence number indicates lost packets placeholders will be defined + * for each missing entry in the window. + * + * side effects: + * + * 1) sequence number is set in skb from PGM header value. + * 2) window may be updated with new skb. + * 3) placeholders may be created for detected lost packets. + * 4) parity skbs may be shuffled to accomodate original data. + * + * returns: + * PGM_RXW_INSERTED - packet filled a waiting placeholder, skb consumed. + * PGM_RXW_APPENDED - packet advanced window lead, skb consumed. + * PGM_RXW_MISSING - missing packets detected whilst window lead was adanced, skb consumed. + * PGM_RXW_DUPLICATE - re-transmission of previously seen packet. + * PGM_RXW_MALFORMED - corrupted or invalid packet. + * PGM_RXW_BOUNDS - packet out of window. + * + * it is an error to try to free the skb after adding to the window. + */ + +int +pgm_rxw_add ( + pgm_rxw_t* const restrict window, + struct pgm_sk_buff_t* const restrict skb, + const pgm_time_t now, + const pgm_time_t nak_rb_expiry /* calculated expiry time for this skb */ + ) +{ + pgm_rxw_state_t* const state = (pgm_rxw_state_t*)&skb->cb; + int status; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != skb); + pgm_assert_cmpuint (nak_rb_expiry, >, 0); + pgm_assert_cmpuint (pgm_rxw_max_length (window), >, 0); + pgm_assert (pgm_skb_is_valid (skb)); + pgm_assert (((const pgm_list_t*)skb)->next == NULL); + pgm_assert (((const pgm_list_t*)skb)->prev == NULL); + pgm_assert (!_pgm_tsi_is_null (&skb->tsi)); + pgm_assert ((char*)skb->data > (char*)skb->head); + pgm_assert (sizeof(struct pgm_header) + sizeof(struct pgm_data) <= (size_t)((char*)skb->data - (char*)skb->head)); + pgm_assert (skb->len == ((char*)skb->tail - (char*)skb->data)); + + pgm_debug ("add (window:%p skb:%p nak_rb_expiry:%" PGM_TIME_FORMAT ")", + (const void*)window, (const void*)skb, nak_rb_expiry); + + skb->sequence = ntohl (skb->pgm_data->data_sqn); + +/* protocol sanity check: tsdu size */ + if (PGM_UNLIKELY(skb->len != ntohs (skb->pgm_header->pgm_tsdu_length))) + return PGM_RXW_MALFORMED; + +/* protocol sanity check: valid trail pointer wrt. sequence */ + if (PGM_UNLIKELY(skb->sequence - ntohl (skb->pgm_data->data_trail) >= ((UINT32_MAX/2)-1))) + return PGM_RXW_MALFORMED; + +/* verify fragment header for original data, parity packets include a + * parity fragment header + */ + if (!(skb->pgm_header->pgm_options & PGM_OPT_PARITY) && + skb->pgm_opt_fragment) + { +/* protocol sanity check: single fragment APDU */ + if (PGM_UNLIKELY(ntohl (skb->of_apdu_len) == skb->len)) + skb->pgm_opt_fragment = NULL; + +/* protocol sanity check: minimum APDU length */ + if (PGM_UNLIKELY(ntohl (skb->of_apdu_len) < skb->len)) + return PGM_RXW_MALFORMED; + +/* protocol sanity check: sequential ordering */ + if (PGM_UNLIKELY(pgm_uint32_gt (ntohl (skb->of_apdu_first_sqn), skb->sequence))) + return PGM_RXW_MALFORMED; + +/* protocol sanity check: maximum APDU length */ + if (PGM_UNLIKELY(ntohl (skb->of_apdu_len) > PGM_MAX_APDU)) + return PGM_RXW_MALFORMED; + } + +/* first packet of a session defines the window */ + if (PGM_UNLIKELY(!window->is_defined)) + _pgm_rxw_define (window, skb->sequence - 1); /* previous_lead needed for append to occur */ + else + _pgm_rxw_update_trail (window, ntohl (skb->pgm_data->data_trail)); + +/* bounds checking for parity data occurs at the transmission group sequence number */ + if (skb->pgm_header->pgm_options & PGM_OPT_PARITY) + { + if (pgm_uint32_lt (_pgm_rxw_tg_sqn (window, skb->sequence), _pgm_rxw_tg_sqn (window, window->commit_lead))) + return PGM_RXW_DUPLICATE; + + if (pgm_uint32_lt (_pgm_rxw_tg_sqn (window, skb->sequence), _pgm_rxw_tg_sqn (window, window->lead))) { + window->has_event = 1; + return _pgm_rxw_insert (window, skb); + } + + const struct pgm_sk_buff_t* const first_skb = _pgm_rxw_peek (window, _pgm_rxw_tg_sqn (window, skb->sequence)); + const pgm_rxw_state_t* const first_state = (pgm_rxw_state_t*)&first_skb->cb; + + if (_pgm_rxw_tg_sqn (window, skb->sequence) == _pgm_rxw_tg_sqn (window, window->lead)) { + window->has_event = 1; + if (NULL == first_state || first_state->is_contiguous) { + state->is_contiguous = 1; + return _pgm_rxw_append (window, skb, now); + } else + return _pgm_rxw_insert (window, skb); + } + + pgm_assert (NULL != first_state); + status = _pgm_rxw_add_placeholder_range (window, _pgm_rxw_tg_sqn (window, skb->sequence), now, nak_rb_expiry); + } + else + { + if (pgm_uint32_lt (skb->sequence, window->commit_lead)) { + if (pgm_uint32_gte (skb->sequence, window->trail)) + return PGM_RXW_DUPLICATE; + else + return PGM_RXW_BOUNDS; + } + + if (pgm_uint32_lte (skb->sequence, window->lead)) { + window->has_event = 1; + return _pgm_rxw_insert (window, skb); + } + + if (skb->sequence == pgm_rxw_next_lead (window)) { + window->has_event = 1; + if (_pgm_rxw_is_first_of_tg_sqn (window, skb->sequence)) + state->is_contiguous = 1; + return _pgm_rxw_append (window, skb, now); + } + + status = _pgm_rxw_add_placeholder_range (window, skb->sequence, now, nak_rb_expiry); + } + + if (PGM_RXW_APPENDED == status) { + status = _pgm_rxw_append (window, skb, now); + if (PGM_RXW_APPENDED == status) + status = PGM_RXW_MISSING; + } + return status; +} + +/* trail is the next packet to commit upstream, lead is the leading edge + * of the receive window with possible gaps inside, rxw_trail is the transmit + * window trail for retransmit requests. + */ + +/* define window by parameters of first data packet. + */ + +static +void +_pgm_rxw_define ( + pgm_rxw_t* const window, + const uint32_t lead + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (pgm_rxw_is_empty (window)); + pgm_assert (_pgm_rxw_commit_is_empty (window)); + pgm_assert (_pgm_rxw_incoming_is_empty (window)); + pgm_assert (!window->is_defined); + + window->lead = lead; + window->commit_lead = window->rxw_trail = window->rxw_trail_init = window->trail = window->lead + 1; + window->is_constrained = window->is_defined = TRUE; + +/* post-conditions */ + pgm_assert (pgm_rxw_is_empty (window)); + pgm_assert (_pgm_rxw_commit_is_empty (window)); + pgm_assert (_pgm_rxw_incoming_is_empty (window)); + pgm_assert (window->is_defined); + pgm_assert (window->is_constrained); +} + +/* update window with latest transmitted parameters. + * + * returns count of placeholders added into window, used to start sending naks. + */ + +unsigned +pgm_rxw_update ( + pgm_rxw_t* const window, + const uint32_t txw_lead, + const uint32_t txw_trail, + const pgm_time_t now, + const pgm_time_t nak_rb_expiry /* packet expiration time */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert_cmpuint (nak_rb_expiry, >, 0); + + pgm_debug ("pgm_rxw_update (window:%p txw-lead:%" PRIu32 " txw-trail:%" PRIu32 " nak-rb-expiry:%" PGM_TIME_FORMAT ")", + (void*)window, txw_lead, txw_trail, nak_rb_expiry); + + if (PGM_UNLIKELY(!window->is_defined)) { + _pgm_rxw_define (window, txw_lead); + return 0; + } + + _pgm_rxw_update_trail (window, txw_trail); + return _pgm_rxw_update_lead (window, txw_lead, now, nak_rb_expiry); +} + +/* update trailing edge of receive window + */ + +static +void +_pgm_rxw_update_trail ( + pgm_rxw_t* const window, + const uint32_t txw_trail + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + +/* advertised trail is less than the current value */ + if (PGM_UNLIKELY(pgm_uint32_lte (txw_trail, window->rxw_trail))) + return; + +/* protocol sanity check: advertised trail jumps too far ahead */ + if (PGM_UNLIKELY(txw_trail - window->rxw_trail > ((UINT32_MAX/2)-1))) + return; + +/* retransmissions requests are constrained on startup until the advertised trail advances + * beyond the first data sequence number. + */ + if (PGM_UNLIKELY(window->is_constrained)) + { + if (pgm_uint32_gt (txw_trail, window->rxw_trail_init)) + window->is_constrained = FALSE; + else + return; + } + + window->rxw_trail = txw_trail; + +/* new value doesn't affect window */ + if (PGM_UNLIKELY(pgm_uint32_lte (window->rxw_trail, window->trail))) + return; + +/* jump remaining sequence numbers if window is empty */ + if (pgm_rxw_is_empty (window)) + { + const uint32_t distance = (int32_t)(window->rxw_trail) - (int32_t)(window->trail); + window->commit_lead = window->trail += distance; + window->lead += distance; + +/* add loss to bitmap */ + if (distance > 32) window->bitmap = 0; + else window->bitmap <<= distance; + +/* update the Exponential Moving Average (EMA) data loss with long jump: + * s_t = α × (p₁ + (1 - α) × p₂ + (1 - α)² × p₃ + ⋯) + * omitting the weight by stopping after k terms, + * = α × ((1 - α)^^k + (1 - α)^^{k+1} +(1 - α)^^{k+1} + ⋯) + * = α × (1 - α)^^k × (1 + (1 - α) + (1 - α)² + ⋯) + * = (1 - α)^^k + */ + window->data_loss = pgm_fp16mul (window->data_loss, pgm_fp16pow (pgm_fp16 (1) - window->ack_c_p, distance)); + + window->cumulative_losses += distance; + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Data loss due to trailing edge update, fragment count %" PRIu32 "."),window->fragment_count); + pgm_assert (pgm_rxw_is_empty (window)); + pgm_assert (_pgm_rxw_commit_is_empty (window)); + pgm_assert (_pgm_rxw_incoming_is_empty (window)); + return; + } + +/* remove all buffers between commit lead and advertised rxw_trail */ + for (uint32_t sequence = window->commit_lead; + pgm_uint32_gt (window->rxw_trail, sequence) && pgm_uint32_gte (window->lead, sequence); + sequence++) + { + struct pgm_sk_buff_t* skb; + pgm_rxw_state_t* state; + + skb = _pgm_rxw_peek (window, sequence); + pgm_assert (NULL != skb); + state = (pgm_rxw_state_t*)&skb->cb; + + switch (state->pkt_state) { + case PGM_PKT_STATE_HAVE_DATA: + case PGM_PKT_STATE_HAVE_PARITY: + case PGM_PKT_STATE_LOST_DATA: + break; + + case PGM_PKT_STATE_ERROR: + pgm_assert_not_reached(); + + default: + pgm_rxw_lost (window, sequence); + break; + } + } + +/* post-conditions: only after flush */ +// pgm_assert (!pgm_rxw_is_full (window)); +} + +/* update FEC parameters + */ + +void +pgm_rxw_update_fec ( + pgm_rxw_t* const window, + const uint8_t rs_k + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert_cmpuint (rs_k, >, 1); + + pgm_debug ("pgm_rxw_update_fec (window:%p rs(k):%u)", + (void*)window, rs_k); + + if (window->is_fec_available) { + if (rs_k == window->rs.k) return; + pgm_rs_destroy (&window->rs); + } else + window->is_fec_available = 1; + pgm_rs_create (&window->rs, PGM_RS_DEFAULT_N, rs_k); + window->tg_sqn_shift = pgm_power2_log2 (rs_k); + window->tg_size = window->rs.k; +} + +/* add one placeholder to leading edge due to detected lost packet. + */ + +static +void +_pgm_rxw_add_placeholder ( + pgm_rxw_t* const window, + const pgm_time_t now, + const pgm_time_t nak_rb_expiry + ) +{ + struct pgm_sk_buff_t* skb; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (!pgm_rxw_is_full (window)); + +/* advance lead */ + window->lead++; + +/* add loss to bitmap */ + window->bitmap <<= 1; + +/* update the Exponential Moving Average (EMA) data loss with loss: + * s_t = α × x_{t-1} + (1 - α) × s_{t-1} + * x_{t-1} = 1 + * ∴ s_t = α + (1 - α) × s_{t-1} + */ + window->data_loss = window->ack_c_p + pgm_fp16mul ((pgm_fp16 (1) - window->ack_c_p), window->data_loss); + + skb = pgm_alloc_skb (window->max_tpdu); + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + skb->tstamp = now; + skb->sequence = window->lead; + state->timer_expiry = nak_rb_expiry; + + if (!_pgm_rxw_is_first_of_tg_sqn (window, skb->sequence)) + { + struct pgm_sk_buff_t* first_skb = _pgm_rxw_peek (window, _pgm_rxw_tg_sqn (window, skb->sequence)); + if (first_skb) { + pgm_rxw_state_t* first_state = (pgm_rxw_state_t*)&first_skb->cb; + first_state->is_contiguous = 0; + } + } + +/* add skb to window */ + const uint_fast32_t index_ = skb->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = skb; + + pgm_rxw_state (window, skb, PGM_PKT_STATE_BACK_OFF); + +/* post-conditions */ + pgm_assert_cmpuint (pgm_rxw_length (window), >, 0); + pgm_assert_cmpuint (pgm_rxw_length (window), <=, pgm_rxw_max_length (window)); + pgm_assert_cmpuint (_pgm_rxw_incoming_length (window), >, 0); +} + +/* add a range of placeholders to the window. + */ + +static +int +_pgm_rxw_add_placeholder_range ( + pgm_rxw_t* const window, + const uint32_t sequence, + const pgm_time_t now, + const pgm_time_t nak_rb_expiry + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (pgm_uint32_gt (sequence, pgm_rxw_lead (window))); + +/* check bounds of commit window */ + const uint32_t new_commit_sqns = ( 1 + sequence ) - window->trail; + if ( !_pgm_rxw_commit_is_empty (window) && + (new_commit_sqns >= pgm_rxw_max_length (window)) ) + { + _pgm_rxw_update_lead (window, sequence, now, nak_rb_expiry); + return PGM_RXW_BOUNDS; /* effectively a slow consumer */ + } + + if (pgm_rxw_is_full (window)) { + pgm_assert (_pgm_rxw_commit_is_empty (window)); + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Receive window full on placeholder sequence.")); + _pgm_rxw_remove_trail (window); + } + +/* if packet is non-contiguous to current leading edge add place holders + * TODO: can be rather inefficient on packet loss looping through dropped sequence numbers + */ + while (pgm_rxw_next_lead (window) != sequence) + { + _pgm_rxw_add_placeholder (window, now, nak_rb_expiry); + if (pgm_rxw_is_full (window)) { + pgm_assert (_pgm_rxw_commit_is_empty (window)); + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Receive window full on placeholder sequence.")); + _pgm_rxw_remove_trail (window); + } + } + +/* post-conditions */ + pgm_assert (!pgm_rxw_is_full (window)); + + return PGM_RXW_APPENDED; +} + +/* update leading edge of receive window. + * + * returns number of place holders added. + */ + +static +unsigned +_pgm_rxw_update_lead ( + pgm_rxw_t* const window, + const uint32_t txw_lead, + const pgm_time_t now, + const pgm_time_t nak_rb_expiry + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + +/* advertised lead is less than the current value */ + if (PGM_UNLIKELY(pgm_uint32_lte (txw_lead, window->lead))) + return 0; + + uint32_t lead; + +/* committed packets limit constrain the lead until they are released */ + if (!_pgm_rxw_commit_is_empty (window) && + (txw_lead - window->trail) >= pgm_rxw_max_length (window)) + { + lead = window->trail + pgm_rxw_max_length (window) - 1; + if (lead == window->lead) + return 0; + } + else + lead = txw_lead; + + unsigned lost = 0; + + while (window->lead != lead) + { +/* slow consumer or fast producer */ + if (pgm_rxw_is_full (window)) { + pgm_assert (_pgm_rxw_commit_is_empty (window)); + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Receive window full on window lead advancement.")); + _pgm_rxw_remove_trail (window); + } + _pgm_rxw_add_placeholder (window, now, nak_rb_expiry); + lost++; + } + + return lost; +} + +/* checks whether an APDU is unrecoverable due to lost TPDUs. + */ +static inline +bool +_pgm_rxw_is_apdu_lost ( + pgm_rxw_t* const restrict window, + struct pgm_sk_buff_t* const restrict skb + ) +{ + const pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != skb); + +/* lost is lost */ + if (PGM_PKT_STATE_LOST_DATA == state->pkt_state) + return TRUE; + +/* by definition, a single-TPDU APDU is complete */ + if (!skb->pgm_opt_fragment) + return FALSE; + + const uint32_t apdu_first_sqn = ntohl (skb->of_apdu_first_sqn); + +/* by definition, first fragment indicates APDU is available */ + if (apdu_first_sqn == skb->sequence) + return FALSE; + + const struct pgm_sk_buff_t* const first_skb = _pgm_rxw_peek (window, apdu_first_sqn); +/* first fragment out-of-bounds */ + if (NULL == first_skb) + return TRUE; + + const pgm_rxw_state_t* first_state = (pgm_rxw_state_t*)&first_skb->cb; + if (PGM_PKT_STATE_LOST_DATA == first_state->pkt_state) + return TRUE; + + return FALSE; +} + +/* return the first missing packet sequence in the specified transmission + * group or NULL if not required. + */ + +static inline +struct pgm_sk_buff_t* +_pgm_rxw_find_missing ( + pgm_rxw_t* const window, + const uint32_t tg_sqn /* tg_sqn | pkt_sqn */ + ) +{ + struct pgm_sk_buff_t* skb; + pgm_rxw_state_t* state; + +/* pre-conditions */ + pgm_assert (NULL != window); + + for (uint32_t i = tg_sqn, j = 0; j < window->tg_size; i++, j++) + { + skb = _pgm_rxw_peek (window, i); + pgm_assert (NULL != skb); + state = (pgm_rxw_state_t*)&skb->cb; + switch (state->pkt_state) { + case PGM_PKT_STATE_BACK_OFF: + case PGM_PKT_STATE_WAIT_NCF: + case PGM_PKT_STATE_WAIT_DATA: + case PGM_PKT_STATE_LOST_DATA: + return skb; + + case PGM_PKT_STATE_HAVE_DATA: + case PGM_PKT_STATE_HAVE_PARITY: + break; + + default: pgm_assert_not_reached(); break; + } + } + + return NULL; +} + +/* returns TRUE if skb is a parity packet with packet length not + * matching the transmission group length without the variable-packet-length + * flag set. + */ + +static inline +bool +_pgm_rxw_is_invalid_var_pktlen ( + pgm_rxw_t* const restrict window, + const struct pgm_sk_buff_t* const restrict skb + ) +{ + const struct pgm_sk_buff_t* first_skb; + +/* pre-conditions */ + pgm_assert (NULL != window); + + if (!window->is_fec_available) + return FALSE; + + if (skb->pgm_header->pgm_options & PGM_OPT_VAR_PKTLEN) + return FALSE; + + const uint32_t tg_sqn = _pgm_rxw_tg_sqn (window, skb->sequence); + if (tg_sqn == skb->sequence) + return FALSE; + + first_skb = _pgm_rxw_peek (window, tg_sqn); + if (NULL == first_skb) + return TRUE; /* transmission group unrecoverable */ + + if (first_skb->len == skb->len) + return FALSE; + + return TRUE; +} + +static inline +bool +_pgm_rxw_has_payload_op ( + const struct pgm_sk_buff_t* const skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != skb); + pgm_assert (NULL != skb->pgm_header); + + return skb->pgm_opt_fragment || skb->pgm_header->pgm_options & PGM_OP_ENCODED; +} + +/* returns TRUE is skb options are invalid when compared to the transmission group + */ + +static inline +bool +_pgm_rxw_is_invalid_payload_op ( + pgm_rxw_t* const restrict window, + const struct pgm_sk_buff_t* const restrict skb + ) +{ + const struct pgm_sk_buff_t* first_skb; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != skb); + + if (!window->is_fec_available) + return FALSE; + + const uint32_t tg_sqn = _pgm_rxw_tg_sqn (window, skb->sequence); + if (tg_sqn == skb->sequence) + return FALSE; + + first_skb = _pgm_rxw_peek (window, tg_sqn); + if (NULL == first_skb) + return TRUE; /* transmission group unrecoverable */ + + if (_pgm_rxw_has_payload_op (first_skb) == _pgm_rxw_has_payload_op (skb)) + return FALSE; + + return TRUE; +} + +/* insert skb into window range, discard if duplicate. window will have placeholder, + * parity, or data packet already matching sequence. + * + * returns: + * PGM_RXW_INSERTED - packet filled a waiting placeholder, skb consumed. + * PGM_RXW_DUPLICATE - re-transmission of previously seen packet. + * PGM_RXW_MALFORMED - corrupted or invalid packet. + * PGM_RXW_BOUNDS - packet out of window. + */ + +static +int +_pgm_rxw_insert ( + pgm_rxw_t* const restrict window, + struct pgm_sk_buff_t* const restrict new_skb + ) +{ + struct pgm_sk_buff_t* skb; + pgm_rxw_state_t* state; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != new_skb); + pgm_assert (!_pgm_rxw_incoming_is_empty (window)); + + if (PGM_UNLIKELY(_pgm_rxw_is_invalid_var_pktlen (window, new_skb) || + _pgm_rxw_is_invalid_payload_op (window, new_skb))) + return PGM_RXW_MALFORMED; + + if (new_skb->pgm_header->pgm_options & PGM_OPT_PARITY) + { + skb = _pgm_rxw_find_missing (window, new_skb->sequence); + if (NULL == skb) + return PGM_RXW_DUPLICATE; + state = (pgm_rxw_state_t*)&skb->cb; + } + else + { + skb = _pgm_rxw_peek (window, new_skb->sequence); + pgm_assert (NULL != skb); + state = (pgm_rxw_state_t*)&skb->cb; + + if (state->pkt_state == PGM_PKT_STATE_HAVE_DATA) + return PGM_RXW_DUPLICATE; + } + +/* APDU fragments are already declared lost */ + if (new_skb->pgm_opt_fragment && + _pgm_rxw_is_apdu_lost (window, new_skb)) + { + pgm_rxw_lost (window, skb->sequence); + return PGM_RXW_BOUNDS; + } + +/* verify placeholder state */ + switch (state->pkt_state) { + case PGM_PKT_STATE_BACK_OFF: + case PGM_PKT_STATE_WAIT_NCF: + case PGM_PKT_STATE_WAIT_DATA: + case PGM_PKT_STATE_LOST_DATA: + break; + + case PGM_PKT_STATE_HAVE_PARITY: + _pgm_rxw_shuffle_parity (window, skb); + break; + + default: pgm_assert_not_reached(); break; + } + +/* statistics */ + const pgm_time_t fill_time = new_skb->tstamp - skb->tstamp; + PGM_HISTOGRAM_TIMES("Rx.RepairTime", fill_time); + PGM_HISTOGRAM_COUNTS("Rx.NakTransmits", state->nak_transmit_count); + PGM_HISTOGRAM_COUNTS("Rx.NcfRetries", state->ncf_retry_count); + PGM_HISTOGRAM_COUNTS("Rx.DataRetries", state->data_retry_count); + if (!window->max_fill_time) { + window->max_fill_time = window->min_fill_time = fill_time; + } + else + { + if (fill_time > window->max_fill_time) + window->max_fill_time = fill_time; + else if (fill_time < window->min_fill_time) + window->min_fill_time = fill_time; + + if (!window->max_nak_transmit_count) { + window->max_nak_transmit_count = window->min_nak_transmit_count = state->nak_transmit_count; + } else { + if (state->nak_transmit_count > window->max_nak_transmit_count) + window->max_nak_transmit_count = state->nak_transmit_count; + else if (state->nak_transmit_count < window->min_nak_transmit_count) + window->min_nak_transmit_count = state->nak_transmit_count; + } + } + +/* add packet to bitmap */ + const uint_fast32_t pos = window->lead - new_skb->sequence; + if (pos < 32) { + window->bitmap |= 1 << pos; + } + +/* update the Exponential Moving Average (EMA) data loss with repair data. + * s_t = α × x_{t-1} + (1 - α) × s_{t-1} + * x_{t-1} = 0 + * ∴ s_t = (1 - α) × s_{t-1} + */ + const uint_fast32_t s = pgm_fp16pow (pgm_fp16 (1) - window->ack_c_p, pos); + if (s > window->data_loss) window->data_loss = 0; + else window->data_loss -= s; + +/* replace place holder skb with incoming skb */ + memcpy (new_skb->cb, skb->cb, sizeof(skb->cb)); + pgm_rxw_state_t* rxw_state = (void*)new_skb->cb; + rxw_state->pkt_state = PGM_PKT_STATE_ERROR; + _pgm_rxw_unlink (window, skb); + pgm_free_skb (skb); + const uint_fast32_t index_ = new_skb->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = new_skb; + if (new_skb->pgm_header->pgm_options & PGM_OPT_PARITY) + _pgm_rxw_state (window, new_skb, PGM_PKT_STATE_HAVE_PARITY); + else + _pgm_rxw_state (window, new_skb, PGM_PKT_STATE_HAVE_DATA); + window->size += new_skb->len; + + return PGM_RXW_INSERTED; +} + +/* shuffle parity packet at skb->sequence to any other needed spot. + */ + +static inline +void +_pgm_rxw_shuffle_parity ( + pgm_rxw_t* const restrict window, + struct pgm_sk_buff_t* const restrict skb + ) +{ + uint_fast32_t index_; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != skb); + + struct pgm_sk_buff_t* restrict missing = _pgm_rxw_find_missing (window, skb->sequence); + if (NULL == missing) + return; + +/* replace place holder skb with parity skb */ + char cb[48]; + _pgm_rxw_unlink (window, missing); + memcpy (cb, skb->cb, sizeof(skb->cb)); + memcpy (skb->cb, missing->cb, sizeof(skb->cb)); + memcpy (missing->cb, cb, sizeof(skb->cb)); + index_ = skb->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = skb; + index_ = missing->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = missing; +} + +/* skb advances the window lead. + * + * returns: + * PGM_RXW_APPENDED - packet advanced window lead, skb consumed. + * PGM_RXW_MALFORMED - corrupted or invalid packet. + * PGM_RXW_BOUNDS - packet out of window. + */ + +static +int +_pgm_rxw_append ( + pgm_rxw_t* const restrict window, + struct pgm_sk_buff_t* const restrict skb, + const pgm_time_t now + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != skb); + if (skb->pgm_header->pgm_options & PGM_OPT_PARITY) { + pgm_assert (_pgm_rxw_tg_sqn (window, skb->sequence) == _pgm_rxw_tg_sqn (window, pgm_rxw_lead (window))); + } else { + pgm_assert (skb->sequence == pgm_rxw_next_lead (window)); + } + + if (PGM_UNLIKELY(_pgm_rxw_is_invalid_var_pktlen (window, skb) || + _pgm_rxw_is_invalid_payload_op (window, skb))) + return PGM_RXW_MALFORMED; + + if (pgm_rxw_is_full (window)) { + if (_pgm_rxw_commit_is_empty (window)) { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Receive window full on new data.")); + _pgm_rxw_remove_trail (window); + } else { + return PGM_RXW_BOUNDS; /* constrained by commit window */ + } + } + +/* advance leading edge */ + window->lead++; + +/* add packet to bitmap */ + window->bitmap = (window->bitmap << 1) | 1; + +/* update the Exponential Moving Average (EMA) data loss with data: + * s_t = α × x_{t-1} + (1 - α) × s_{t-1} + * x_{t-1} = 0 + * ∴ s_t = (1 - α) × s_{t-1} + */ + window->data_loss = pgm_fp16mul (window->data_loss, pgm_fp16 (1) - window->ack_c_p); + +/* APDU fragments are already declared lost */ + if (PGM_UNLIKELY(skb->pgm_opt_fragment && + _pgm_rxw_is_apdu_lost (window, skb))) + { + struct pgm_sk_buff_t* lost_skb = pgm_alloc_skb (window->max_tpdu); + lost_skb->tstamp = now; + lost_skb->sequence = skb->sequence; + +/* add lost-placeholder skb to window */ + const uint_fast32_t index_ = lost_skb->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = lost_skb; + + _pgm_rxw_state (window, lost_skb, PGM_PKT_STATE_LOST_DATA); + return PGM_RXW_BOUNDS; + } + +/* add skb to window */ + if (skb->pgm_header->pgm_options & PGM_OPT_PARITY) + { + const uint_fast32_t index_ = skb->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = skb; + _pgm_rxw_state (window, skb, PGM_PKT_STATE_HAVE_PARITY); + } + else + { + const uint_fast32_t index_ = skb->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = skb; + _pgm_rxw_state (window, skb, PGM_PKT_STATE_HAVE_DATA); + } + +/* statistics */ + window->size += skb->len; + + return PGM_RXW_APPENDED; +} + +/* remove references to all commit packets not in the same transmission group + * as the commit-lead + */ + +void +pgm_rxw_remove_commit ( + pgm_rxw_t* const window + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + + const uint32_t tg_sqn_of_commit_lead = _pgm_rxw_tg_sqn (window, window->commit_lead); + + while (!_pgm_rxw_commit_is_empty (window) && + tg_sqn_of_commit_lead != _pgm_rxw_tg_sqn (window, window->trail)) + { + _pgm_rxw_remove_trail (window); + } +} + +/* flush packets but instead of calling on_data append the contiguous data packets + * to the provided scatter/gather vector. + * + * when transmission groups are enabled, packets remain in the windows tagged committed + * until the transmission group has been completely committed. this allows the packet + * data to be used in parity calculations to recover the missing packets. + * + * returns -1 on nothing read, returns length of bytes read, 0 is a valid read length. + * + * PGM skbuffs will have an increased reference count and must be unreferenced by the + * calling application. + */ + +ssize_t +pgm_rxw_readv ( + pgm_rxw_t* const restrict window, + struct pgm_msgv_t** restrict pmsg, /* message array, updated as messages appended */ + const unsigned pmsglen /* number of items in pmsg */ + ) +{ + const struct pgm_msgv_t* msg_end; + struct pgm_sk_buff_t* skb; + pgm_rxw_state_t* state; + ssize_t bytes_read; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != pmsg); + pgm_assert_cmpuint (pmsglen, >, 0); + + pgm_debug ("readv (window:%p pmsg:%p pmsglen:%u)", + (void*)window, (void*)pmsg, pmsglen); + + msg_end = *pmsg + pmsglen - 1; + + if (_pgm_rxw_incoming_is_empty (window)) + return -1; + + skb = _pgm_rxw_peek (window, window->commit_lead); + pgm_assert (NULL != skb); + + state = (pgm_rxw_state_t*)&skb->cb; + switch (state->pkt_state) { + case PGM_PKT_STATE_HAVE_DATA: + bytes_read = _pgm_rxw_incoming_read (window, pmsg, msg_end - *pmsg + 1); + break; + + case PGM_PKT_STATE_LOST_DATA: +/* do not purge in situ sequence */ + if (_pgm_rxw_commit_is_empty (window)) { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Removing lost trail from window")); + _pgm_rxw_remove_trail (window); + } else { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Locking trail at commit window")); + } +/* fall through */ + case PGM_PKT_STATE_BACK_OFF: + case PGM_PKT_STATE_WAIT_NCF: + case PGM_PKT_STATE_WAIT_DATA: + case PGM_PKT_STATE_HAVE_PARITY: + bytes_read = -1; + break; + + case PGM_PKT_STATE_COMMIT_DATA: + case PGM_PKT_STATE_ERROR: + default: + pgm_assert_not_reached(); + break; + } + + return bytes_read; +} + +/* remove lost sequences from the trailing edge of the window. lost sequence + * at lead of commit window invalidates all parity-data packets as any + * transmission group is now unrecoverable. + * + * returns number of sequences purged. + */ + +static +unsigned +_pgm_rxw_remove_trail ( + pgm_rxw_t* const window + ) +{ + struct pgm_sk_buff_t* skb; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (!pgm_rxw_is_empty (window)); + + skb = _pgm_rxw_peek (window, window->trail); + pgm_assert (NULL != skb); + _pgm_rxw_unlink (window, skb); + window->size -= skb->len; +/* remove reference to skb */ + if (PGM_UNLIKELY(pgm_mem_gc_friendly)) { + const uint_fast32_t index_ = skb->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = NULL; + } + pgm_free_skb (skb); + if (window->trail++ == window->commit_lead) { +/* data-loss */ + window->commit_lead++; + window->cumulative_losses++; + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Data loss due to pulled trailing edge, fragment count %" PRIu32 "."),window->fragment_count); + return 1; + } + return 0; +} + +unsigned +pgm_rxw_remove_trail ( + pgm_rxw_t* const window + ) +{ + pgm_debug ("remove_trail (window:%p)", (const void*)window); + return _pgm_rxw_remove_trail (window); +} + +/* read contiguous APDU-grouped sequences from the incoming window. + * + * side effects: + * + * 1) increments statics for window messages and bytes read. + * + * returns count of bytes read. + */ + +static inline +ssize_t +_pgm_rxw_incoming_read ( + pgm_rxw_t* const restrict window, + struct pgm_msgv_t** restrict pmsg, /* message array, updated as messages appended */ + unsigned pmsglen /* number of items in pmsg */ + ) +{ + const struct pgm_msgv_t* msg_end; + struct pgm_sk_buff_t* skb; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != pmsg); + pgm_assert_cmpuint (pmsglen, >, 0); + pgm_assert (!_pgm_rxw_incoming_is_empty (window)); + + pgm_debug ("_pgm_rxw_incoming_read (window:%p pmsg:%p pmsglen:%u)", + (void*)window, (void*)pmsg, pmsglen); + + msg_end = *pmsg + pmsglen - 1; + ssize_t bytes_read = 0; + size_t data_read = 0; + + do { + skb = _pgm_rxw_peek (window, window->commit_lead); + pgm_assert (NULL != skb); + if (_pgm_rxw_is_apdu_complete (window, + skb->pgm_opt_fragment ? ntohl (skb->of_apdu_first_sqn) : skb->sequence)) + { + bytes_read += _pgm_rxw_incoming_read_apdu (window, pmsg); + data_read ++; + } + else break; + } while (*pmsg <= msg_end && !_pgm_rxw_incoming_is_empty (window)); + + window->bytes_delivered += bytes_read; + window->msgs_delivered += data_read; + return data_read > 0 ? bytes_read : -1; +} + +/* returns TRUE if transmission group is lost. + * + * checking is lightly limited to bounds. + */ + +static inline +bool +_pgm_rxw_is_tg_sqn_lost ( + pgm_rxw_t* const window, + const uint32_t tg_sqn /* transmission group sequence */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert_cmpuint (_pgm_rxw_pkt_sqn (window, tg_sqn), ==, 0); + + if (pgm_rxw_is_empty (window)) + return TRUE; + + if (pgm_uint32_lt (tg_sqn, window->trail)) + return TRUE; + + return FALSE; +} + +/* reconstruct missing sequences in a transmission group using embedded parity data. + */ + +static +void +_pgm_rxw_reconstruct ( + pgm_rxw_t* const window, + const uint32_t tg_sqn /* transmission group sequence */ + ) +{ + struct pgm_sk_buff_t* skb; + pgm_rxw_state_t* state; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (1 == window->is_fec_available); + pgm_assert_cmpuint (_pgm_rxw_pkt_sqn (window, tg_sqn), ==, 0); + + skb = _pgm_rxw_peek (window, tg_sqn); + pgm_assert (NULL != skb); + + const bool is_var_pktlen = skb->pgm_header->pgm_options & PGM_OPT_VAR_PKTLEN; + const bool is_op_encoded = skb->pgm_header->pgm_options & PGM_OPT_PRESENT; + const uint16_t parity_length = ntohs (skb->pgm_header->pgm_tsdu_length); + struct pgm_sk_buff_t* tg_skbs[ window->rs.n ]; + pgm_gf8_t* tg_data[ window->rs.n ]; + pgm_gf8_t* tg_opts[ window->rs.n ]; + uint8_t offsets[ window->rs.k ]; + uint8_t rs_h = 0; + + for (uint32_t i = tg_sqn, j = 0; i != (tg_sqn + window->rs.k); i++, j++) + { + skb = _pgm_rxw_peek (window, i); + pgm_assert (NULL != skb); + state = (pgm_rxw_state_t*)&skb->cb; + switch (state->pkt_state) { + case PGM_PKT_STATE_HAVE_DATA: + tg_skbs[ j ] = skb; + tg_data[ j ] = skb->data; + tg_opts[ j ] = (pgm_gf8_t*)skb->pgm_opt_fragment; + offsets[ j ] = j; + break; + + case PGM_PKT_STATE_HAVE_PARITY: + tg_skbs[ window->rs.k + rs_h ] = skb; + tg_data[ window->rs.k + rs_h ] = skb->data; + tg_opts[ window->rs.k + rs_h ] = (pgm_gf8_t*)skb->pgm_opt_fragment; + offsets[ j ] = window->rs.k + rs_h; + ++rs_h; +/* fall through and alloc new skb for reconstructed data */ + case PGM_PKT_STATE_BACK_OFF: + case PGM_PKT_STATE_WAIT_NCF: + case PGM_PKT_STATE_WAIT_DATA: + case PGM_PKT_STATE_LOST_DATA: + skb = pgm_alloc_skb (window->max_tpdu); + pgm_skb_reserve (skb, sizeof(struct pgm_header) + sizeof(struct pgm_data)); + skb->pgm_header = skb->head; + skb->pgm_data = (void*)( skb->pgm_header + 1 ); + if (is_op_encoded) { + const uint16_t opt_total_length = sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment); + pgm_skb_reserve (skb, opt_total_length); + skb->pgm_opt_fragment = (void*)( skb->pgm_data + 1 ); + pgm_skb_put (skb, parity_length); + memset (skb->pgm_opt_fragment, 0, opt_total_length + parity_length); + } else { + pgm_skb_put (skb, parity_length); + memset (skb->data, 0, parity_length); + } + tg_skbs[ j ] = skb; + tg_data[ j ] = skb->data; + tg_opts[ j ] = (void*)skb->pgm_opt_fragment; + break; + + default: pgm_assert_not_reached(); break; + } + + if (!skb->zero_padded) { + memset (skb->tail, 0, parity_length - skb->len); + skb->zero_padded = 1; + } + + } + +/* reconstruct payload */ + pgm_rs_decode_parity_appended (&window->rs, + tg_data, + offsets, + parity_length); + +/* reconstruct opt_fragment option */ + if (is_op_encoded) + pgm_rs_decode_parity_appended (&window->rs, + tg_opts, + offsets, + sizeof(struct pgm_opt_fragment)); + +/* swap parity skbs with reconstructed skbs */ + for (uint_fast8_t i = 0; i < window->rs.k; i++) + { + if (offsets[i] < window->rs.k) + continue; + + struct pgm_sk_buff_t* repair_skb = tg_skbs[i]; + + if (is_var_pktlen) + { + const uint16_t pktlen = *(uint16_t*)( (char*)repair_skb->tail - sizeof(uint16_t)); + if (pktlen > parity_length) { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Invalid encoded variable packet length in reconstructed packet, dropping entire transmission group.")); + pgm_free_skb (repair_skb); + for (uint_fast8_t j = i; j < window->rs.k; j++) + { + if (offsets[j] < window->rs.k) + continue; + pgm_rxw_lost (window, tg_skbs[offsets[j]]->sequence); + } + break; + } + const uint16_t padding = parity_length - pktlen; + repair_skb->len -= padding; + repair_skb->tail = (char*)repair_skb->tail - padding; + } + +#ifdef PGM_DISABLE_ASSERT + _pgm_rxw_insert (window, repair_skb); +#else + pgm_assert_cmpint (_pgm_rxw_insert (window, repair_skb), ==, PGM_RXW_INSERTED); +#endif + } +} + +/* check every TPDU in an APDU and verify that the data has arrived + * and is available to commit to the application. + * + * if APDU sits in a transmission group that can be reconstructed use parity + * data then the entire group will be decoded and any missing data packets + * replaced by the recovery calculation. + * + * packets with single fragment fragment headers must be normalised as regular + * packets before calling. + * + * APDUs exceeding PGM_MAX_FRAGMENTS or PGM_MAX_APDU length will be discarded. + * + * returns FALSE if APDU is incomplete or longer than max_len sequences. + */ + +static +bool +_pgm_rxw_is_apdu_complete ( + pgm_rxw_t* const window, + const uint32_t first_sequence + ) +{ + struct pgm_sk_buff_t* skb; + pgm_rxw_state_t* state; + +/* pre-conditions */ + pgm_assert (NULL != window); + + pgm_debug ("_pgm_rxw_is_apdu_complete (window:%p first-sequence:%" PRIu32 ")", + (const void*)window, first_sequence); + + skb = _pgm_rxw_peek (window, first_sequence); + if (PGM_UNLIKELY(NULL == skb)) { + return FALSE; + } + + const size_t apdu_size = skb->pgm_opt_fragment ? ntohl (skb->of_apdu_len) : skb->len; + const uint32_t tg_sqn = _pgm_rxw_tg_sqn (window, first_sequence); + uint32_t sequence = first_sequence; + unsigned contiguous_tpdus = 0; + size_t contiguous_size = 0; + bool check_parity = FALSE; + + pgm_assert_cmpuint (apdu_size, >=, skb->len); + +/* protocol sanity check: maximum length */ + if (PGM_UNLIKELY(apdu_size > PGM_MAX_APDU)) { + pgm_rxw_lost (window, first_sequence); + return FALSE; + } + + do { + state = (pgm_rxw_state_t*)&skb->cb; + + if (!check_parity && + PGM_PKT_STATE_HAVE_DATA != state->pkt_state) + { + if (window->is_fec_available && + !_pgm_rxw_is_tg_sqn_lost (window, tg_sqn) ) + { + check_parity = TRUE; +/* pre-seed committed sequence count */ + if (pgm_uint32_lte (tg_sqn, window->commit_lead)) + contiguous_tpdus += window->commit_lead - tg_sqn; + } + else + return FALSE; + } + + if (check_parity) + { + if (PGM_PKT_STATE_HAVE_DATA == state->pkt_state || + PGM_PKT_STATE_HAVE_PARITY == state->pkt_state) + ++contiguous_tpdus; + +/* have sufficient been received for reconstruction */ + if (contiguous_tpdus >= window->tg_size) { + _pgm_rxw_reconstruct (window, tg_sqn); + return _pgm_rxw_is_apdu_complete (window, first_sequence); + } + } + else + { +/* single packet APDU, already complete */ + if (PGM_PKT_STATE_HAVE_DATA == state->pkt_state && + !skb->pgm_opt_fragment) + return TRUE; + +/* protocol sanity check: matching first sequence reference */ + if (PGM_UNLIKELY(ntohl (skb->of_apdu_first_sqn) != first_sequence)) { + pgm_rxw_lost (window, first_sequence); + return FALSE; + } + +/* protocol sanity check: matching apdu length */ + if (PGM_UNLIKELY(ntohl (skb->of_apdu_len) != apdu_size)) { + pgm_rxw_lost (window, first_sequence); + return FALSE; + } + +/* protocol sanity check: maximum number of fragments per apdu */ + if (PGM_UNLIKELY(++contiguous_tpdus > PGM_MAX_FRAGMENTS)) { + pgm_rxw_lost (window, first_sequence); + return FALSE; + } + + contiguous_size += skb->len; + if (apdu_size == contiguous_size) + return TRUE; + else if (PGM_UNLIKELY(apdu_size < contiguous_size)) { + pgm_rxw_lost (window, first_sequence); + return FALSE; + } + } + + skb = _pgm_rxw_peek (window, ++sequence); + } while (skb); + +/* pending */ + return FALSE; +} + +/* read one APDU consisting of one or more TPDUs. target array is guaranteed + * to be big enough to store complete APDU. + */ + +static inline +ssize_t +_pgm_rxw_incoming_read_apdu ( + pgm_rxw_t* const restrict window, + struct pgm_msgv_t** restrict pmsg /* message array, updated as messages appended */ + ) +{ + struct pgm_sk_buff_t *skb; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != pmsg); + + pgm_debug ("_pgm_rxw_incoming_read_apdu (window:%p pmsg:%p)", + (const void*)window, (const void*)pmsg); + + skb = _pgm_rxw_peek (window, window->commit_lead); + size_t contiguous_len = 0; + const size_t apdu_len = skb->pgm_opt_fragment ? ntohl (skb->of_apdu_len) : skb->len; + unsigned i = 0; + pgm_assert_cmpuint (apdu_len, >=, skb->len); + (*pmsg)->msgv_len = 0; + do { + _pgm_rxw_state (window, skb, PGM_PKT_STATE_COMMIT_DATA); + (*pmsg)->msgv_skb[i++] = skb; + (*pmsg)->msgv_len++; + contiguous_len += skb->len; + window->commit_lead++; + if (apdu_len == contiguous_len) + break; + skb = _pgm_rxw_peek (window, window->commit_lead); + } while (apdu_len > contiguous_len); + + (*pmsg)++; + +/* post-conditions */ + pgm_assert (!_pgm_rxw_commit_is_empty (window)); + +return contiguous_len; +} + +/* returns transmission group sequence (TG_SQN) from sequence (SQN). + */ + +static inline +uint32_t +_pgm_rxw_tg_sqn ( + pgm_rxw_t* const window, + const uint32_t sequence + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + + const uint32_t tg_sqn_mask = 0xffffffff << window->tg_sqn_shift; + return sequence & tg_sqn_mask; +} + +/* returns packet number (PKT_SQN) from sequence (SQN). + */ + +static inline +uint32_t +_pgm_rxw_pkt_sqn ( + pgm_rxw_t* const window, + const uint32_t sequence + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + + const uint32_t tg_sqn_mask = 0xffffffff << window->tg_sqn_shift; + return sequence & ~tg_sqn_mask; +} + +/* returns TRUE when the sequence is the first of a transmission group. + */ + +static inline +bool +_pgm_rxw_is_first_of_tg_sqn ( + pgm_rxw_t* const window, + const uint32_t sequence + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + + return _pgm_rxw_pkt_sqn (window, sequence) == 0; +} + +/* returns TRUE when the sequence is the last of a transmission group + */ + +static inline +bool +_pgm_rxw_is_last_of_tg_sqn ( + pgm_rxw_t* const window, + const uint32_t sequence + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + + return _pgm_rxw_pkt_sqn (window, sequence) == window->tg_size - 1; +} + +/* set PGM skbuff to new FSM state. + */ + +static +void +_pgm_rxw_state ( + pgm_rxw_t* const restrict window, + struct pgm_sk_buff_t* const restrict skb, + const int new_pkt_state + ) +{ + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != skb); + +/* remove current state */ + if (PGM_PKT_STATE_ERROR != state->pkt_state) + _pgm_rxw_unlink (window, skb); + + switch (new_pkt_state) { + case PGM_PKT_STATE_BACK_OFF: + pgm_queue_push_head_link (&window->nak_backoff_queue, (pgm_list_t*)skb); + break; + + case PGM_PKT_STATE_WAIT_NCF: + pgm_queue_push_head_link (&window->wait_ncf_queue, (pgm_list_t*)skb); + break; + + case PGM_PKT_STATE_WAIT_DATA: + pgm_queue_push_head_link (&window->wait_data_queue, (pgm_list_t*)skb); + break; + + case PGM_PKT_STATE_HAVE_DATA: + window->fragment_count++; + pgm_assert_cmpuint (window->fragment_count, <=, pgm_rxw_length (window)); + break; + + case PGM_PKT_STATE_HAVE_PARITY: + window->parity_count++; + pgm_assert_cmpuint (window->parity_count, <=, pgm_rxw_length (window)); + break; + + case PGM_PKT_STATE_COMMIT_DATA: + window->committed_count++; + pgm_assert_cmpuint (window->committed_count, <=, pgm_rxw_length (window)); + break; + + case PGM_PKT_STATE_LOST_DATA: + window->lost_count++; + window->cumulative_losses++; + window->has_event = 1; + pgm_assert_cmpuint (window->lost_count, <=, pgm_rxw_length (window)); + break; + + case PGM_PKT_STATE_ERROR: + break; + + default: pgm_assert_not_reached(); break; + } + + state->pkt_state = new_pkt_state; +} + +void +pgm_rxw_state ( + pgm_rxw_t* const restrict window, + struct pgm_sk_buff_t* const restrict skb, + const int new_pkt_state + ) +{ + pgm_debug ("state (window:%p skb:%p new_pkt_state:%s)", + (const void*)window, (const void*)skb, pgm_pkt_state_string (new_pkt_state)); + _pgm_rxw_state (window, skb, new_pkt_state); +} + +/* remove current state from sequence. + */ + +static +void +_pgm_rxw_unlink ( + pgm_rxw_t* const restrict window, + struct pgm_sk_buff_t* const restrict skb + ) +{ + pgm_queue_t* queue; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != skb); + + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + + switch (state->pkt_state) { + case PGM_PKT_STATE_BACK_OFF: + pgm_assert (!pgm_queue_is_empty (&window->nak_backoff_queue)); + queue = &window->nak_backoff_queue; + goto unlink_queue; + + case PGM_PKT_STATE_WAIT_NCF: + pgm_assert (!pgm_queue_is_empty (&window->wait_ncf_queue)); + queue = &window->wait_ncf_queue; + goto unlink_queue; + + case PGM_PKT_STATE_WAIT_DATA: + pgm_assert (!pgm_queue_is_empty (&window->wait_data_queue)); + queue = &window->wait_data_queue; +unlink_queue: + pgm_queue_unlink (queue, (pgm_list_t*)skb); + break; + + case PGM_PKT_STATE_HAVE_DATA: + pgm_assert_cmpuint (window->fragment_count, >, 0); + window->fragment_count--; + break; + + case PGM_PKT_STATE_HAVE_PARITY: + pgm_assert_cmpuint (window->parity_count, >, 0); + window->parity_count--; + break; + + case PGM_PKT_STATE_COMMIT_DATA: + pgm_assert_cmpuint (window->committed_count, >, 0); + window->committed_count--; + break; + + case PGM_PKT_STATE_LOST_DATA: + pgm_assert_cmpuint (window->lost_count, >, 0); + window->lost_count--; + break; + + case PGM_PKT_STATE_ERROR: + break; + + default: pgm_assert_not_reached(); break; + } + + state->pkt_state = PGM_PKT_STATE_ERROR; + pgm_assert (((pgm_list_t*)skb)->next == NULL); + pgm_assert (((pgm_list_t*)skb)->prev == NULL); +} + +/* returns the pointer at the given index of the window. + */ + +struct pgm_sk_buff_t* +pgm_rxw_peek ( + pgm_rxw_t* const window, + const uint32_t sequence + ) +{ + pgm_debug ("peek (window:%p sequence:%" PRIu32 ")", (void*)window, sequence); + return _pgm_rxw_peek (window, sequence); +} + +/* mark an existing sequence lost due to failed recovery. + */ + +void +pgm_rxw_lost ( + pgm_rxw_t* const window, + const uint32_t sequence + ) +{ + struct pgm_sk_buff_t* skb; + pgm_rxw_state_t* state; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (!pgm_rxw_is_empty (window)); + + pgm_debug ("lost (window:%p sequence:%" PRIu32 ")", + (const void*)window, sequence); + + skb = _pgm_rxw_peek (window, sequence); + pgm_assert (NULL != skb); + + state = (pgm_rxw_state_t*)&skb->cb; + + if (PGM_UNLIKELY(!(state->pkt_state == PGM_PKT_STATE_BACK_OFF || + state->pkt_state == PGM_PKT_STATE_WAIT_NCF || + state->pkt_state == PGM_PKT_STATE_WAIT_DATA || + state->pkt_state == PGM_PKT_STATE_HAVE_DATA || /* fragments */ + state->pkt_state == PGM_PKT_STATE_HAVE_PARITY))) + { + pgm_fatal (_("Unexpected state %s(%u)"), pgm_pkt_state_string (state->pkt_state), state->pkt_state); + pgm_assert_not_reached(); + } + + _pgm_rxw_state (window, skb, PGM_PKT_STATE_LOST_DATA); +} + +/* received a uni/multicast ncf, search for a matching nak & tag or extend window if + * beyond lead + * + * returns: + * PGM_RXW_BOUNDS - sequence is outside of window, or window is undefined. + * PGM_RXW_UPDATED - receiver state updated, waiting for data. + * PGM_RXW_DUPLICATE - data already exists at sequence. + * PGM_RXW_APPENDED - lead is extended with state set waiting for data. + */ + +int +pgm_rxw_confirm ( + pgm_rxw_t* const window, + const uint32_t sequence, + const pgm_time_t now, + const pgm_time_t nak_rdata_expiry, /* pre-calculated expiry times */ + const pgm_time_t nak_rb_expiry + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + + pgm_debug ("confirm (window:%p sequence:%" PRIu32 " nak_rdata_expiry:%" PGM_TIME_FORMAT " nak_rb_expiry:%" PGM_TIME_FORMAT ")", + (void*)window, sequence, nak_rdata_expiry, nak_rb_expiry); + +/* NCFs do not define the transmit window */ + if (PGM_UNLIKELY(!window->is_defined)) + return PGM_RXW_BOUNDS; + +/* sequence already committed */ + if (pgm_uint32_lt (sequence, window->commit_lead)) { + if (pgm_uint32_gte (sequence, window->trail)) + return PGM_RXW_DUPLICATE; + else + return PGM_RXW_BOUNDS; + } + + if (pgm_uint32_lte (sequence, window->lead)) + return _pgm_rxw_recovery_update (window, sequence, nak_rdata_expiry); + + if (sequence == window->lead) + return _pgm_rxw_recovery_append (window, now, nak_rdata_expiry); + else { + _pgm_rxw_add_placeholder_range (window, sequence, now, nak_rb_expiry); + return _pgm_rxw_recovery_append (window, now, nak_rdata_expiry); + } +} + +/* update an incoming sequence with state transition to WAIT-DATA. + * + * returns: + * PGM_RXW_UPDATED - receiver state updated, waiting for data. + * PGM_RXW_DUPLICATE - data already exists at sequence. + */ + +static inline +int +_pgm_rxw_recovery_update ( + pgm_rxw_t* const window, + const uint32_t sequence, + const pgm_time_t nak_rdata_expiry /* pre-calculated expiry times */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + +/* fetch skb from window and bump expiration times */ + struct pgm_sk_buff_t* skb = _pgm_rxw_peek (window, sequence); + pgm_assert (NULL != skb); + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + switch (state->pkt_state) { + case PGM_PKT_STATE_BACK_OFF: + case PGM_PKT_STATE_WAIT_NCF: + pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_DATA); + +/* fall through */ + case PGM_PKT_STATE_WAIT_DATA: + state->timer_expiry = nak_rdata_expiry; + return PGM_RXW_UPDATED; + + case PGM_PKT_STATE_HAVE_DATA: + case PGM_PKT_STATE_HAVE_PARITY: + case PGM_PKT_STATE_COMMIT_DATA: + case PGM_PKT_STATE_LOST_DATA: + break; + + default: pgm_assert_not_reached(); break; + } + + return PGM_RXW_DUPLICATE; +} + +/* append an skb to the incoming window with WAIT-DATA state. + * + * returns: + * PGM_RXW_APPENDED - lead is extended with state set waiting for data. + * PGM_RXW_BOUNDS - constrained by commit window + */ + +static inline +int +_pgm_rxw_recovery_append ( + pgm_rxw_t* const window, + const pgm_time_t now, + const pgm_time_t nak_rdata_expiry /* pre-calculated expiry times */ + ) +{ + struct pgm_sk_buff_t* skb; + +/* pre-conditions */ + pgm_assert (NULL != window); + + if (pgm_rxw_is_full (window)) { + if (_pgm_rxw_commit_is_empty (window)) { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Receive window full on confirmed sequence.")); + _pgm_rxw_remove_trail (window); + } else { + return PGM_RXW_BOUNDS; /* constrained by commit window */ + } + } + +/* advance leading edge */ + window->lead++; + +/* add loss to bitmap */ + window->bitmap <<= 1; + +/* update the Exponential Moving Average (EMA) data loss with loss: + * s_t = α × x_{t-1} + (1 - α) × s_{t-1} + * x_{t-1} = 1 + * ∴ s_t = α + (1 - α) × s_{t-1} + */ + window->data_loss = window->ack_c_p + pgm_fp16mul (pgm_fp16 (1) - window->ack_c_p, window->data_loss); + + skb = pgm_alloc_skb (window->max_tpdu); + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + skb->tstamp = now; + skb->sequence = window->lead; + state->timer_expiry = nak_rdata_expiry; + + const uint_fast32_t index_ = pgm_rxw_lead (window) % pgm_rxw_max_length (window); + window->pdata[index_] = skb; + _pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_DATA); + + return PGM_RXW_APPENDED; +} + +/* dumps window state to stdout + */ + +void +pgm_rxw_dump ( + const pgm_rxw_t* const window + ) +{ + pgm_info ("window = {" + "tsi = {gsi = {identifier = %i.%i.%i.%i.%i.%i}, sport = %" PRIu16 "}, " + "nak_backoff_queue = {head = %p, tail = %p, length = %u}, " + "wait_ncf_queue = {head = %p, tail = %p, length = %u}, " + "wait_data_queue = {head = %p, tail = %p, length = %u}, " + "lost_count = %" PRIu32 ", " + "fragment_count = %" PRIu32 ", " + "parity_count = %" PRIu32 ", " + "committed_count = %" PRIu32 ", " + "max_tpdu = %" PRIu16 ", " + "tg_size = %" PRIu32 ", " + "tg_sqn_shift = %u, " + "lead = %" PRIu32 ", " + "trail = %" PRIu32 ", " + "rxw_trail = %" PRIu32 ", " + "rxw_trail_init = %" PRIu32 ", " + "commit_lead = %" PRIu32 ", " + "is_constrained = %u, " + "is_defined = %u, " + "has_event = %u, " + "is_fec_available = %u, " + "min_fill_time = %" PRIu32 ", " + "max_fill_time = %" PRIu32 ", " + "min_nak_transmit_count = %" PRIu32 ", " + "max_nak_transmit_count = %" PRIu32 ", " + "cumulative_losses = %" PRIu32 ", " + "bytes_delivered = %" PRIu32 ", " + "msgs_delivered = %" PRIu32 ", " + "size = %zu, " + "alloc = %" PRIu32 ", " + "pdata = []" + "}", + window->tsi->gsi.identifier[0], + window->tsi->gsi.identifier[1], + window->tsi->gsi.identifier[2], + window->tsi->gsi.identifier[3], + window->tsi->gsi.identifier[4], + window->tsi->gsi.identifier[5], + ntohs (window->tsi->sport), + (void*)window->nak_backoff_queue.head, + (void*)window->nak_backoff_queue.tail, + window->nak_backoff_queue.length, + (void*)window->wait_ncf_queue.head, + (void*)window->wait_ncf_queue.tail, + window->wait_ncf_queue.length, + (void*)window->wait_data_queue.head, + (void*)window->wait_data_queue.tail, + window->wait_data_queue.length, + window->lost_count, + window->fragment_count, + window->parity_count, + window->committed_count, + window->max_tpdu, + window->tg_size, + window->tg_sqn_shift, + window->lead, + window->trail, + window->rxw_trail, + window->rxw_trail_init, + window->commit_lead, + window->is_constrained, + window->is_defined, + window->has_event, + window->is_fec_available, + window->min_fill_time, + window->max_fill_time, + window->min_nak_transmit_count, + window->max_nak_transmit_count, + window->cumulative_losses, + window->bytes_delivered, + window->msgs_delivered, + window->size, + window->alloc + ); +} + +/* state string helper + */ + +const char* +pgm_pkt_state_string ( + const int pkt_state + ) +{ + const char* c; + + switch (pkt_state) { + case PGM_PKT_STATE_BACK_OFF: c = "PGM_PKT_STATE_BACK_OFF"; break; + case PGM_PKT_STATE_WAIT_NCF: c = "PGM_PKT_STATE_WAIT_NCF"; break; + case PGM_PKT_STATE_WAIT_DATA: c = "PGM_PKT_STATE_WAIT_DATA"; break; + case PGM_PKT_STATE_HAVE_DATA: c = "PGM_PKT_STATE_HAVE_DATA"; break; + case PGM_PKT_STATE_HAVE_PARITY: c = "PGM_PKT_STATE_HAVE_PARITY"; break; + case PGM_PKT_STATE_COMMIT_DATA: c = "PGM_PKT_STATE_COMMIT_DATA"; break; + case PGM_PKT_STATE_LOST_DATA: c = "PGM_PKT_STATE_LOST_DATA"; break; + case PGM_PKT_STATE_ERROR: c = "PGM_PKT_STATE_ERROR"; break; + default: c = "(unknown)"; break; + } + + return c; +} + +const char* +pgm_rxw_returns_string ( + const int rxw_returns + ) +{ + const char* c; + + switch (rxw_returns) { + case PGM_RXW_OK: c = "PGM_RXW_OK"; break; + case PGM_RXW_INSERTED: c = "PGM_RXW_INSERTED"; break; + case PGM_RXW_APPENDED: c = "PGM_RXW_APPENDED"; break; + case PGM_RXW_UPDATED: c = "PGM_RXW_UPDATED"; break; + case PGM_RXW_MISSING: c = "PGM_RXW_MISSING"; break; + case PGM_RXW_DUPLICATE: c = "PGM_RXW_DUPLICATE"; break; + case PGM_RXW_MALFORMED: c = "PGM_RXW_MALFORMED"; break; + case PGM_RXW_BOUNDS: c = "PGM_RXW_BOUNDS"; break; + case PGM_RXW_SLOW_CONSUMER: c = "PGM_RXW_SLOW_CONSUMER"; break; + case PGM_RXW_UNKNOWN: c = "PGM_RXW_UNKNOWN"; break; + default: c = "(unknown)"; break; + } + + return c; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/rxw.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/rxw.c.c89.patch new file mode 100644 index 0000000..1eef6b2 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/rxw.c.c89.patch @@ -0,0 +1,565 @@ +--- rxw.c 2010-08-04 17:06:11.000000000 +0800 ++++ rxw.c89 2010-08-05 11:36:04.000000000 +0800 +@@ -198,11 +198,12 @@ + pgm_assert_cmpuint (max_rte, >, 0); + } + +- pgm_debug ("create (tsi:%s max-tpdu:%" PRIu16 " sqns:%" PRIu32 " secs %u max-rte %zd ack-c_p %" PRIu32 ")", ++ pgm_debug ("create (tsi:%s max-tpdu:%" PRIu16 " sqns:%" PRIu32 " secs %u max-rte %ld ack-c_p %" PRIu32 ")", + pgm_tsi_print (tsi), tpdu_size, sqns, secs, max_rte, ack_c_p); + + /* calculate receive window parameters */ + pgm_assert (sqns || (secs && max_rte)); ++ { + const unsigned alloc_sqns = sqns ? sqns : ( (secs * max_rte) / tpdu_size ); + window = pgm_malloc0 (sizeof(pgm_rxw_t) + ( alloc_sqns * sizeof(struct pgm_sk_buff_t*) )); + +@@ -238,6 +239,7 @@ + pgm_assert (!pgm_rxw_is_full (window)); + + return window; ++ } + } + + /* destructor for receive window. must not be called more than once for same window. +@@ -308,7 +310,7 @@ + /* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != skb); +- pgm_assert_cmpuint (nak_rb_expiry, >, 0); ++ pgm_assert_cmpuint ((unsigned int)nak_rb_expiry, >, 0); + pgm_assert_cmpuint (pgm_rxw_max_length (window), >, 0); + pgm_assert (pgm_skb_is_valid (skb)); + pgm_assert (((const pgm_list_t*)skb)->next == NULL); +@@ -371,6 +373,7 @@ + return _pgm_rxw_insert (window, skb); + } + ++ { + const struct pgm_sk_buff_t* const first_skb = _pgm_rxw_peek (window, _pgm_rxw_tg_sqn (window, skb->sequence)); + const pgm_rxw_state_t* const first_state = (pgm_rxw_state_t*)&first_skb->cb; + +@@ -385,6 +388,7 @@ + + pgm_assert (NULL != first_state); + status = _pgm_rxw_add_placeholder_range (window, _pgm_rxw_tg_sqn (window, skb->sequence), now, nak_rb_expiry); ++ } + } + else + { +@@ -468,7 +472,7 @@ + { + /* pre-conditions */ + pgm_assert (NULL != window); +- pgm_assert_cmpuint (nak_rb_expiry, >, 0); ++ pgm_assert_cmpuint ((unsigned int)nak_rb_expiry, >, 0); + + pgm_debug ("pgm_rxw_update (window:%p txw-lead:%" PRIu32 " txw-trail:%" PRIu32 " nak-rb-expiry:%" PGM_TIME_FORMAT ")", + (void*)window, txw_lead, txw_trail, nak_rb_expiry); +@@ -549,7 +553,9 @@ + } + + /* remove all buffers between commit lead and advertised rxw_trail */ +- for (uint32_t sequence = window->commit_lead; ++ { ++ uint32_t sequence; ++ for (sequence = window->commit_lead; + pgm_uint32_gt (window->rxw_trail, sequence) && pgm_uint32_gte (window->lead, sequence); + sequence++) + { +@@ -574,6 +580,7 @@ + break; + } + } ++ } + + /* post-conditions: only after flush */ + // pgm_assert (!pgm_rxw_is_full (window)); +@@ -636,6 +643,7 @@ + window->data_loss = window->ack_c_p + pgm_fp16mul ((pgm_fp16 (1) - window->ack_c_p), window->data_loss); + + skb = pgm_alloc_skb (window->max_tpdu); ++ { + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + skb->tstamp = now; + skb->sequence = window->lead; +@@ -651,6 +659,7 @@ + } + + /* add skb to window */ ++ { + const uint_fast32_t index_ = skb->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = skb; + +@@ -660,6 +669,8 @@ + pgm_assert_cmpuint (pgm_rxw_length (window), >, 0); + pgm_assert_cmpuint (pgm_rxw_length (window), <=, pgm_rxw_max_length (window)); + pgm_assert_cmpuint (_pgm_rxw_incoming_length (window), >, 0); ++ } ++ } + } + + /* add a range of placeholders to the window. +@@ -679,6 +690,7 @@ + pgm_assert (pgm_uint32_gt (sequence, pgm_rxw_lead (window))); + + /* check bounds of commit window */ ++ { + const uint32_t new_commit_sqns = ( 1 + sequence ) - window->trail; + if ( !_pgm_rxw_commit_is_empty (window) && + (new_commit_sqns >= pgm_rxw_max_length (window)) ) +@@ -710,6 +722,7 @@ + pgm_assert (!pgm_rxw_is_full (window)); + + return PGM_RXW_APPENDED; ++ } + } + + /* update leading edge of receive window. +@@ -733,6 +746,7 @@ + if (PGM_UNLIKELY(pgm_uint32_lte (txw_lead, window->lead))) + return 0; + ++ { + uint32_t lead; + + /* committed packets limit constrain the lead until they are released */ +@@ -746,6 +760,7 @@ + else + lead = txw_lead; + ++ { + unsigned lost = 0; + + while (window->lead != lead) +@@ -761,6 +776,8 @@ + } + + return lost; ++ } ++ } + } + + /* checks whether an APDU is unrecoverable due to lost TPDUs. +@@ -786,22 +803,28 @@ + if (!skb->pgm_opt_fragment) + return FALSE; + ++ { + const uint32_t apdu_first_sqn = ntohl (skb->of_apdu_first_sqn); + + /* by definition, first fragment indicates APDU is available */ + if (apdu_first_sqn == skb->sequence) + return FALSE; + ++ { + const struct pgm_sk_buff_t* const first_skb = _pgm_rxw_peek (window, apdu_first_sqn); + /* first fragment out-of-bounds */ + if (NULL == first_skb) + return TRUE; + ++ { + const pgm_rxw_state_t* first_state = (pgm_rxw_state_t*)&first_skb->cb; + if (PGM_PKT_STATE_LOST_DATA == first_state->pkt_state) + return TRUE; + + return FALSE; ++ } ++ } ++ } + } + + /* return the first missing packet sequence in the specified transmission +@@ -821,7 +844,9 @@ + /* pre-conditions */ + pgm_assert (NULL != window); + +- for (uint32_t i = tg_sqn, j = 0; j < window->tg_size; i++, j++) ++ { ++ uint32_t i, j; ++ for (i = tg_sqn, j = 0; j < window->tg_size; i++, j++) + { + skb = _pgm_rxw_peek (window, i); + pgm_assert (NULL != skb); +@@ -840,6 +865,7 @@ + default: pgm_assert_not_reached(); break; + } + } ++ } + + return NULL; + } +@@ -867,6 +893,7 @@ + if (skb->pgm_header->pgm_options & PGM_OPT_VAR_PKTLEN) + return FALSE; + ++ { + const uint32_t tg_sqn = _pgm_rxw_tg_sqn (window, skb->sequence); + if (tg_sqn == skb->sequence) + return FALSE; +@@ -879,6 +906,7 @@ + return FALSE; + + return TRUE; ++ } + } + + static inline +@@ -913,6 +941,7 @@ + if (!window->is_fec_available) + return FALSE; + ++ { + const uint32_t tg_sqn = _pgm_rxw_tg_sqn (window, skb->sequence); + if (tg_sqn == skb->sequence) + return FALSE; +@@ -925,6 +954,7 @@ + return FALSE; + + return TRUE; ++ } + } + + /* insert skb into window range, discard if duplicate. window will have placeholder, +@@ -997,20 +1027,21 @@ + } + + /* statistics */ ++ { + const pgm_time_t fill_time = new_skb->tstamp - skb->tstamp; + PGM_HISTOGRAM_TIMES("Rx.RepairTime", fill_time); + PGM_HISTOGRAM_COUNTS("Rx.NakTransmits", state->nak_transmit_count); + PGM_HISTOGRAM_COUNTS("Rx.NcfRetries", state->ncf_retry_count); + PGM_HISTOGRAM_COUNTS("Rx.DataRetries", state->data_retry_count); + if (!window->max_fill_time) { +- window->max_fill_time = window->min_fill_time = fill_time; ++ window->max_fill_time = window->min_fill_time = (uint32_t)fill_time; + } + else + { + if (fill_time > window->max_fill_time) +- window->max_fill_time = fill_time; ++ window->max_fill_time = (uint32_t)fill_time; + else if (fill_time < window->min_fill_time) +- window->min_fill_time = fill_time; ++ window->min_fill_time = (uint32_t)fill_time; + + if (!window->max_nak_transmit_count) { + window->max_nak_transmit_count = window->min_nak_transmit_count = state->nak_transmit_count; +@@ -1023,6 +1054,7 @@ + } + + /* add packet to bitmap */ ++ { + const uint_fast32_t pos = window->lead - new_skb->sequence; + if (pos < 32) { + window->bitmap |= 1 << pos; +@@ -1033,16 +1065,19 @@ + * x_{t-1} = 0 + * ∴ s_t = (1 - α) × s_{t-1} + */ ++ { + const uint_fast32_t s = pgm_fp16pow (pgm_fp16 (1) - window->ack_c_p, pos); + if (s > window->data_loss) window->data_loss = 0; + else window->data_loss -= s; + + /* replace place holder skb with incoming skb */ + memcpy (new_skb->cb, skb->cb, sizeof(skb->cb)); ++ { + pgm_rxw_state_t* rxw_state = (void*)new_skb->cb; + rxw_state->pkt_state = PGM_PKT_STATE_ERROR; + _pgm_rxw_unlink (window, skb); + pgm_free_skb (skb); ++ { + const uint_fast32_t index_ = new_skb->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = new_skb; + if (new_skb->pgm_header->pgm_options & PGM_OPT_PARITY) +@@ -1052,6 +1087,11 @@ + window->size += new_skb->len; + + return PGM_RXW_INSERTED; ++ } ++ } ++ } ++ } ++ } + } + + /* shuffle parity packet at skb->sequence to any other needed spot. +@@ -1070,11 +1110,13 @@ + pgm_assert (NULL != window); + pgm_assert (NULL != skb); + ++ { + struct pgm_sk_buff_t* restrict missing = _pgm_rxw_find_missing (window, skb->sequence); + if (NULL == missing) + return; + + /* replace place holder skb with parity skb */ ++ { + char cb[48]; + _pgm_rxw_unlink (window, missing); + memcpy (cb, skb->cb, sizeof(skb->cb)); +@@ -1084,6 +1126,8 @@ + window->pdata[index_] = skb; + index_ = missing->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = missing; ++ } ++ } + } + + /* skb advances the window lead. +@@ -1146,11 +1190,13 @@ + lost_skb->sequence = skb->sequence; + + /* add lost-placeholder skb to window */ ++ { + const uint_fast32_t index_ = lost_skb->sequence % pgm_rxw_max_length (window); + window->pdata[index_] = lost_skb; + + _pgm_rxw_state (window, lost_skb, PGM_PKT_STATE_LOST_DATA); + return PGM_RXW_BOUNDS; ++ } + } + + /* add skb to window */ +@@ -1185,6 +1231,7 @@ + /* pre-conditions */ + pgm_assert (NULL != window); + ++ { + const uint32_t tg_sqn_of_commit_lead = _pgm_rxw_tg_sqn (window, window->commit_lead); + + while (!_pgm_rxw_commit_is_empty (window) && +@@ -1192,6 +1239,7 @@ + { + _pgm_rxw_remove_trail (window); + } ++ } + } + + /* flush packets but instead of calling on_data append the contiguous data packets +@@ -1344,7 +1392,9 @@ + pgm_debug ("_pgm_rxw_incoming_read (window:%p pmsg:%p pmsglen:%u)", + (void*)window, (void*)pmsg, pmsglen); + ++ { + msg_end = *pmsg + pmsglen - 1; ++ { + ssize_t bytes_read = 0; + size_t data_read = 0; + +@@ -1363,6 +1413,8 @@ + window->bytes_delivered += bytes_read; + window->msgs_delivered += data_read; + return data_read > 0 ? bytes_read : -1; ++ } ++ } + } + + /* returns TRUE if transmission group is lost. +@@ -1411,16 +1463,19 @@ + skb = _pgm_rxw_peek (window, tg_sqn); + pgm_assert (NULL != skb); + ++ { + const bool is_var_pktlen = skb->pgm_header->pgm_options & PGM_OPT_VAR_PKTLEN; + const bool is_op_encoded = skb->pgm_header->pgm_options & PGM_OPT_PRESENT; + const uint16_t parity_length = ntohs (skb->pgm_header->pgm_tsdu_length); +- struct pgm_sk_buff_t* tg_skbs[ window->rs.n ]; +- pgm_gf8_t* tg_data[ window->rs.n ]; +- pgm_gf8_t* tg_opts[ window->rs.n ]; +- uint8_t offsets[ window->rs.k ]; ++ struct pgm_sk_buff_t** tg_skbs = pgm_newa (struct pgm_sk_buff_t*, window->rs.n); ++ pgm_gf8_t** tg_data = pgm_newa (pgm_gf8_t*, window->rs.n); ++ pgm_gf8_t** tg_opts = pgm_newa (pgm_gf8_t*, window->rs.n); ++ uint8_t* offsets = pgm_newa (uint8_t, window->rs.k); + uint8_t rs_h = 0; + +- for (uint32_t i = tg_sqn, j = 0; i != (tg_sqn + window->rs.k); i++, j++) ++ { ++ uint32_t i, j; ++ for (i = tg_sqn, j = 0; i != (tg_sqn + window->rs.k); i++, j++) + { + skb = _pgm_rxw_peek (window, i); + pgm_assert (NULL != skb); +@@ -1474,6 +1529,7 @@ + } + + } ++ } + + /* reconstruct payload */ + pgm_rs_decode_parity_appended (&window->rs, +@@ -1489,11 +1545,14 @@ + sizeof(struct pgm_opt_fragment)); + + /* swap parity skbs with reconstructed skbs */ +- for (uint_fast8_t i = 0; i < window->rs.k; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < window->rs.k; i++) + { + if (offsets[i] < window->rs.k) + continue; + ++ { + struct pgm_sk_buff_t* repair_skb = tg_skbs[i]; + + if (is_var_pktlen) +@@ -1502,17 +1561,22 @@ + if (pktlen > parity_length) { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Invalid encoded variable packet length in reconstructed packet, dropping entire transmission group.")); + pgm_free_skb (repair_skb); +- for (uint_fast8_t j = i; j < window->rs.k; j++) ++ { ++ uint_fast8_t j; ++ for (j = i; j < window->rs.k; j++) + { + if (offsets[j] < window->rs.k) + continue; + pgm_rxw_lost (window, tg_skbs[offsets[j]]->sequence); + } ++ } + break; + } ++ { + const uint16_t padding = parity_length - pktlen; + repair_skb->len -= padding; + repair_skb->tail = (char*)repair_skb->tail - padding; ++ } + } + + #ifdef PGM_DISABLE_ASSERT +@@ -1520,6 +1584,9 @@ + #else + pgm_assert_cmpint (_pgm_rxw_insert (window, repair_skb), ==, PGM_RXW_INSERTED); + #endif ++ } ++ } ++ } + } + } + +@@ -1559,6 +1626,7 @@ + return FALSE; + } + ++ { + const size_t apdu_size = skb->pgm_opt_fragment ? ntohl (skb->of_apdu_len) : skb->len; + const uint32_t tg_sqn = _pgm_rxw_tg_sqn (window, first_sequence); + uint32_t sequence = first_sequence; +@@ -1643,6 +1711,7 @@ + + /* pending */ + return FALSE; ++ } + } + + /* read one APDU consisting of one or more TPDUs. target array is guaranteed +@@ -1666,6 +1735,7 @@ + (const void*)window, (const void*)pmsg); + + skb = _pgm_rxw_peek (window, window->commit_lead); ++ { + size_t contiguous_len = 0; + const size_t apdu_len = skb->pgm_opt_fragment ? ntohl (skb->of_apdu_len) : skb->len; + unsigned i = 0; +@@ -1687,7 +1757,8 @@ + /* post-conditions */ + pgm_assert (!_pgm_rxw_commit_is_empty (window)); + +-return contiguous_len; ++ return contiguous_len; ++ } + } + + /* returns transmission group sequence (TG_SQN) from sequence (SQN). +@@ -1703,8 +1774,10 @@ + /* pre-conditions */ + pgm_assert (NULL != window); + ++ { + const uint32_t tg_sqn_mask = 0xffffffff << window->tg_sqn_shift; + return sequence & tg_sqn_mask; ++ } + } + + /* returns packet number (PKT_SQN) from sequence (SQN). +@@ -1720,8 +1793,10 @@ + /* pre-conditions */ + pgm_assert (NULL != window); + ++ { + const uint32_t tg_sqn_mask = 0xffffffff << window->tg_sqn_shift; + return sequence & ~tg_sqn_mask; ++ } + } + + /* returns TRUE when the sequence is the first of a transmission group. +@@ -1849,6 +1924,7 @@ + pgm_assert (NULL != window); + pgm_assert (NULL != skb); + ++ { + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + + switch (state->pkt_state) { +@@ -1898,6 +1974,7 @@ + state->pkt_state = PGM_PKT_STATE_ERROR; + pgm_assert (((pgm_list_t*)skb)->next == NULL); + pgm_assert (((pgm_list_t*)skb)->prev == NULL); ++ } + } + + /* returns the pointer at the given index of the window. +@@ -2017,8 +2094,10 @@ + pgm_assert (NULL != window); + + /* fetch skb from window and bump expiration times */ ++ { + struct pgm_sk_buff_t* skb = _pgm_rxw_peek (window, sequence); + pgm_assert (NULL != skb); ++ { + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + switch (state->pkt_state) { + case PGM_PKT_STATE_BACK_OFF: +@@ -2040,6 +2119,8 @@ + } + + return PGM_RXW_DUPLICATE; ++ } ++ } + } + + /* append an skb to the incoming window with WAIT-DATA state. +@@ -2085,16 +2166,20 @@ + window->data_loss = window->ack_c_p + pgm_fp16mul (pgm_fp16 (1) - window->ack_c_p, window->data_loss); + + skb = pgm_alloc_skb (window->max_tpdu); ++ { + pgm_rxw_state_t* state = (pgm_rxw_state_t*)&skb->cb; + skb->tstamp = now; + skb->sequence = window->lead; + state->timer_expiry = nak_rdata_expiry; + ++ { + const uint_fast32_t index_ = pgm_rxw_lead (window) % pgm_rxw_max_length (window); + window->pdata[index_] = skb; + _pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_DATA); + + return PGM_RXW_APPENDED; ++ } ++ } + } + + /* dumps window state to stdout +@@ -2133,7 +2218,7 @@ + "cumulative_losses = %" PRIu32 ", " + "bytes_delivered = %" PRIu32 ", " + "msgs_delivered = %" PRIu32 ", " +- "size = %zu, " ++ "size = %lu, " + "alloc = %" PRIu32 ", " + "pdata = []" + "}", diff --git a/3rdparty/openpgm-svn-r1135/pgm/rxw_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/rxw_unittest.c new file mode 100644 index 0000000..635c854 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/rxw_unittest.c @@ -0,0 +1,1844 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for receive window. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + + +/* mock global */ + + +#define pgm_histogram_add mock_pgm_histogram_add +#define pgm_time_now mock_pgm_time_now +#define pgm_rs_create mock_pgm_rs_create +#define pgm_rs_destroy mock_pgm_rs_destroy +#define pgm_rs_decode_parity_appended mock_pgm_rs_decode_parity_appended +#define pgm_histogram_init mock_pgm_histogram_init + +#define RXW_DEBUG +#include "rxw.c" + +#ifdef PGM_DISABLE_ASSERT +# error "PGM_DISABLE_ASSERT set" +#endif + +static pgm_time_t mock_pgm_time_now = 0x1; + + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + +/** reed-solomon module */ +void +mock_pgm_rs_create ( + pgm_rs_t* rs, + uint8_t n, + uint8_t k + ) +{ +} + +void +mock_pgm_rs_destroy ( + pgm_rs_t* rs + ) +{ +} + +void +mock_pgm_rs_decode_parity_appended ( + pgm_rs_t* rs, + pgm_gf8_t** block, + const uint8_t* offsets, + uint16_t len + ) +{ +// null +} + +void +mock_pgm_histogram_init ( + pgm_histogram_t* histogram + ) +{ +} + +void +mock_pgm_histogram_add ( + pgm_histogram_t* histogram, + int value + ) +{ +} + + +/* generate valid skb, data pointer pointing to PGM payload + */ +static +struct pgm_sk_buff_t* +generate_valid_skb (void) +{ + const pgm_tsi_t tsi = { { 200, 202, 203, 204, 205, 206 }, 2000 }; + const guint16 tsdu_length = 1000; + const guint16 header_length = sizeof(struct pgm_header) + sizeof(struct pgm_data); + struct pgm_sk_buff_t* skb = pgm_alloc_skb (1500); + memcpy (&skb->tsi, &tsi, sizeof(tsi)); +/* fake but valid socket and timestamp */ + skb->sock = (pgm_sock_t*)0x1; + skb->tstamp = pgm_time_now; +/* header */ + pgm_skb_reserve (skb, header_length); + memset (skb->head, 0, header_length); + skb->pgm_header = (struct pgm_header*)skb->head; + skb->pgm_data = (struct pgm_data*)(skb->pgm_header + 1); + skb->pgm_header->pgm_type = PGM_ODATA; + skb->pgm_header->pgm_tsdu_length = g_htons (tsdu_length); +/* DATA */ + pgm_skb_put (skb, tsdu_length); + return skb; +} + +/* target: + * pgm_rxw_t* + * pgm_rxw_create ( + * const pgm_tsi_t* tsi, + * const uint16_t tpdu_size, + * const unsigned sqns, + * const unsigned secs, + * const ssize_t max_rte, + * const uint32_t ack_c_p + * ) + */ + +/* vanilla sequence count window */ +START_TEST (test_create_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + fail_if (NULL == pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p), "create failed"); +} +END_TEST + +/* vanilla time based window */ +START_TEST (test_create_pass_002) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + fail_if (NULL == pgm_rxw_create (&tsi, 1500, 0, 60, 800000, ack_c_p), "create failed"); +} +END_TEST + +/* jumbo frame */ +START_TEST (test_create_pass_003) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + fail_if (NULL == pgm_rxw_create (&tsi, 9000, 0, 60, 800000, ack_c_p), "create failed"); +} +END_TEST + +/* max frame */ +START_TEST (test_create_pass_004) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + fail_if (NULL == pgm_rxw_create (&tsi, UINT16_MAX, 0, 60, 800000, ack_c_p), "create failed"); +} +END_TEST + +/* invalid tsi pointer */ +START_TEST (test_create_fail_001) +{ + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (NULL, 1500, 100, 0, 0, ack_c_p); + fail ("reached"); +} +END_TEST + +/* invalid tpdu size */ +START_TEST (test_create_fail_002) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + fail_if (NULL == pgm_rxw_create (&tsi, 0, 100, 0, 0, ack_c_p), "create failed"); +} +END_TEST + +START_TEST (test_create_fail_003) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 0, 0, 60, 800000, ack_c_p); + fail ("reached"); +} +END_TEST + +/* no specified sequence count or time value */ +START_TEST (test_create_fail_004) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 0, 0, 0, 800000, ack_c_p); + fail ("reached"); +} +END_TEST + +/* no specified rate */ +START_TEST (test_create_fail_005) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 0, 0, 60, 0, ack_c_p); + fail ("reached"); +} +END_TEST + +/* all invalid */ +START_TEST (test_create_fail_006) +{ + pgm_rxw_t* window = pgm_rxw_create (NULL, 0, 0, 0, 0, 0); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_rxw_destroy ( + * pgm_rxw_t* const window + * ) + */ + +START_TEST (test_destroy_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_destroy_fail_001) +{ + pgm_rxw_destroy (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * int + * pgm_rxw_add ( + * pgm_rxw_t* const window, + * struct pgm_sk_buff_t* const skb, + * const pgm_time_t now, + * const pgm_time_t nak_rb_expiry + * ) + * failures raise assert errors and stop process execution. + */ + +START_TEST (test_add_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + pgm_rxw_destroy (window); +} +END_TEST + +/* missing + inserted */ +START_TEST (test_add_pass_002) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); +/* #1 */ + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); +/* #2 with jump */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (2); + fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not missing"); +/* #3 to fill in gap */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (1); + fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); + pgm_rxw_destroy (window); +} +END_TEST + +/* duplicate + append */ +START_TEST (test_add_pass_003) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); +/* #1 */ + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); +/* #2 repeat sequence */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + fail_unless (PGM_RXW_DUPLICATE == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not duplicate"); +/* #3 append */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (1); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + pgm_rxw_destroy (window); +} +END_TEST + +/* malformed: tpdu too long */ +START_TEST (test_add_pass_004) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_header->pgm_tsdu_length = g_htons (65535); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_MALFORMED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not malformed"); +} +END_TEST + +/* bounds + append */ +START_TEST (test_add_pass_005) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); +/* #1 */ + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + skb->pgm_data->data_trail = g_htonl (-10); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); +/* #2 jump backwards */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (-1); + skb->pgm_data->data_trail = g_htonl (-10); + fail_unless (PGM_RXW_BOUNDS == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not bounds"); +/* #3 append */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (1); + skb->pgm_data->data_trail = g_htonl (-10); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); +/* #4 jump forward */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (100 + (UINT32_MAX / 2)); + skb->pgm_data->data_trail = g_htonl (UINT32_MAX / 2); + fail_unless (PGM_RXW_BOUNDS == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not bounds"); +/* #5 append */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (2); + skb->pgm_data->data_trail = g_htonl (-10); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + pgm_rxw_destroy (window); +} +END_TEST + +/* null skb */ +START_TEST (test_add_fail_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + int retval = pgm_rxw_add (window, NULL, now, nak_rb_expiry); + fail ("reached"); +} +END_TEST + +/* null window */ +START_TEST (test_add_fail_002) +{ + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + int retval = pgm_rxw_add (NULL, skb, now, nak_rb_expiry); + fail ("reached"); +} +END_TEST + +/* null skb content */ +START_TEST (test_add_fail_003) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + char buffer[1500]; + memset (buffer, 0, sizeof(buffer)); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + int retval = pgm_rxw_add (window, (struct pgm_sk_buff_t*)buffer, now, nak_rb_expiry); + fail ("reached"); +} +END_TEST + +/* 0 nak_rb_expiry */ +START_TEST (test_add_fail_004) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + int retval = pgm_rxw_add (window, skb, now, 0); + fail ("reached"); +} +END_TEST + +/* target: + * struct pgm_sk_buff_t* + * pgm_rxw_peek ( + * pgm_rxw_t* const window, + * const uint32_t sequence + * ) + */ + +START_TEST (test_peek_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + fail_unless (NULL == pgm_rxw_peek (window, 0)); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (skb == pgm_rxw_peek (window, 0), "peek failed"); + fail_unless (NULL == pgm_rxw_peek (window, 1), "peek failed"); + fail_unless (NULL == pgm_rxw_peek (window, -1), "peek failed"); + pgm_rxw_destroy (window); +} +END_TEST + +/* null window */ +START_TEST (test_peek_fail_001) +{ + struct pgm_sk_buff_t* skb = pgm_rxw_peek (NULL, 0); + fail ("reached"); +} +END_TEST + +/** inline function tests **/ +/* pgm_rxw_max_length () + */ +START_TEST (test_max_length_pass_001) +{ + const guint window_length = 100; + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, window_length, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + fail_unless (window_length == pgm_rxw_max_length (window), "max_length failed"); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_max_length_fail_001) +{ + const unsigned len = pgm_rxw_max_length (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_rxw_length () + */ +START_TEST (test_length_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + fail_unless (0 == pgm_rxw_length (window), "length failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (1 == pgm_rxw_length (window), "length failed"); +/* #2 */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (1); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (2 == pgm_rxw_length (window), "length failed"); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_length_fail_001) +{ + const uint32_t answer = pgm_rxw_length (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_rxw_size () + */ +START_TEST (test_size_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + fail_unless (0 == pgm_rxw_size (window), "size failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (1000 == pgm_rxw_size (window), "size failed"); +/* #2 */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (1); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (2000 == pgm_rxw_size (window), "size failed"); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_size_fail_001) +{ + const size_t answer = pgm_rxw_size (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_rxw_is_empty + */ +START_TEST (test_is_empty_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + fail_unless (pgm_rxw_is_empty (window), "is_empty failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_if (pgm_rxw_is_empty (window), "is_empty failed"); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_is_empty_fail_001) +{ + const bool answer = pgm_rxw_is_empty (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_rxw_is_full + */ +START_TEST (test_is_full_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 1, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + fail_if (pgm_rxw_is_full (window), "is_full failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (pgm_rxw_is_full (window), "is_full failed"); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_is_full_fail_001) +{ + const bool answer = pgm_rxw_is_full (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_rxw_lead + */ +START_TEST (test_lead_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + guint32 lead = pgm_rxw_lead (window); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (lead + 1 == pgm_rxw_lead (window), "lead failed"); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_lead_fail_001) +{ + const uint32_t answer = pgm_rxw_lead (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_rxw_next_lead + */ +START_TEST (test_next_lead_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + guint32 next_lead = pgm_rxw_next_lead (window); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (next_lead == pgm_rxw_lead (window), "lead failed"); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_next_lead_fail_001) +{ + const uint32_t answer = pgm_rxw_next_lead (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * ssize_t + * pgm_rxw_readv ( + * pgm_rxw_t* const window, + * struct pgm_msgv_t** pmsg, + * const unsigned msg_len + * ) + */ + +START_TEST (test_readv_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_msgv_t msgv[2], *pmsg; +/* #1 empty */ + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); +/* #2 single TPDU-APDU */ + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + pmsg = msgv; + fail_unless (1000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); +/* #3,4 two APDUs */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (1); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (2); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + pmsg = msgv; + fail_unless (2000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); +/* #5,6 skip and repair APDU */ + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (4); + fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not missing"); + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (3); + fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); + pmsg = msgv; + fail_unless (2000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + pgm_rxw_destroy (window); +} +END_TEST + +/* zero-length */ +START_TEST (test_readv_pass_002) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_msgv_t msgv[2], *pmsg; + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + pgm_rxw_destroy (window); +} +END_TEST + +/* full window */ +START_TEST (test_readv_pass_003) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_msgv_t msgv[1], *pmsg; + struct pgm_sk_buff_t* skb; + for (unsigned i = 0; i < 100; i++) + { + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless ((1 + i) == pgm_rxw_length (window), "length failed"); + } + fail_unless (pgm_rxw_is_full (window), "is_full failed"); + fail_unless (_pgm_rxw_commit_is_empty (window), "commit_is_empty failed"); + for (unsigned i = 0; i < 100; i++) + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + fail_unless ((1 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); + } + fail_unless (pgm_rxw_length (window) == _pgm_rxw_commit_length (window), "commit_length failed"); + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + pgm_rxw_destroy (window); +} +END_TEST + +/* full + 1 window */ +START_TEST (test_readv_pass_004) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_msgv_t msgv[1], *pmsg; + struct pgm_sk_buff_t* skb; + for (unsigned i = 0; i < 101; i++) + { + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (MIN(100, 1 + i) == pgm_rxw_length (window), "length failed"); + } + fail_unless (pgm_rxw_is_full (window), "is_full failed"); + fail_unless (_pgm_rxw_commit_is_empty (window), "commit_is_empty failed"); + for (unsigned i = 0; i < 100; i++) + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + fail_unless ((1 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); + } + fail_unless (pgm_rxw_length (window) == _pgm_rxw_commit_length (window), "commit_length failed"); + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + pgm_rxw_destroy (window); +} +END_TEST + +/* full - 2 lost last in window */ +START_TEST (test_readv_pass_005) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_msgv_t msgv[1], *pmsg; + struct pgm_sk_buff_t* skb; + for (unsigned i = 0; i < 98; i++) + { + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless ((1 + i) == pgm_rxw_length (window), "length failed"); + } + fail_if (pgm_rxw_is_full (window), "is_full failed"); + fail_unless (_pgm_rxw_commit_is_empty (window), "commit_is_empty failed"); + { + unsigned i = 99; + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not missing"); + fail_unless ((1 + i) == pgm_rxw_length (window), "length failed"); + } + fail_unless (pgm_rxw_is_full (window)); + fail_unless (_pgm_rxw_commit_is_empty (window)); + for (unsigned i = 0; i < 98; i++) + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + fail_unless ((1 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); + } + fail_unless (pgm_rxw_length (window) == (2 + _pgm_rxw_commit_length (window)), "commit_length failed"); +/* read end-of-window */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + } + pgm_rxw_destroy (window); +} +END_TEST + +/* add full window, readv 1 skb, add 1 more */ +START_TEST (test_readv_pass_006) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_msgv_t msgv[1], *pmsg; + struct pgm_sk_buff_t* skb; + for (unsigned i = 0; i < 100; i++) + { + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (MIN(100, 1 + i) == pgm_rxw_length (window), "length failed"); + } + fail_unless (pgm_rxw_is_full (window)); + fail_unless (_pgm_rxw_commit_is_empty (window)); +/* read one skb */ + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + fail_unless (1 == _pgm_rxw_commit_length (window), "commit_length failed"); + } +/* add one more new skb */ + { + unsigned i = 100; + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_BOUNDS == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not bounds"); + fail_unless (MIN(100, 1 + i) == pgm_rxw_length (window), "length failed"); + } +/* read off 99 more skbs */ + for (unsigned i = 0; i < 99; i++) + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + fail_unless ((2 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); + } +/* read end-of-window */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + } + pgm_rxw_destroy (window); +} +END_TEST + +/* NULL window */ +START_TEST (test_readv_fail_001) +{ + struct pgm_msgv_t msgv[1], *pmsg = msgv; + gssize len = pgm_rxw_readv (NULL, &pmsg, G_N_ELEMENTS(msgv)); + fail ("reached"); +} +END_TEST + +/* NULL pmsg */ +START_TEST (test_readv_fail_002) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + struct pgm_msgv_t msgv[1], *pmsg = msgv; + gssize len = pgm_rxw_readv (window, NULL, G_N_ELEMENTS(msgv)); + fail ("reached"); +} +END_TEST + +/* 0 msg-len */ +START_TEST (test_readv_fail_003) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + struct pgm_msgv_t msgv[1], *pmsg = msgv; + gssize len = pgm_rxw_readv (window, &pmsg, 0); + fail ("reached"); +} +END_TEST + +/* target: + * + * void + * pgm_rxw_remove_commit ( + * pgm_rxw_t* const window + * ) + */ + +/* full - 2 lost last in window */ +START_TEST (test_remove_commit_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_msgv_t msgv[1], *pmsg; + struct pgm_sk_buff_t* skb; + for (unsigned i = 0; i < 98; i++) + { + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless ((1 + i) == pgm_rxw_length (window), "length failed"); + } + fail_if (pgm_rxw_is_full (window)); + fail_unless (_pgm_rxw_commit_is_empty (window)); +/* #98 is missing */ + { + unsigned i = 99; + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless ((1 + i) == pgm_rxw_length (window), "length failed"); + } + fail_unless (pgm_rxw_is_full (window), "is_full failed"); + fail_unless (_pgm_rxw_commit_is_empty (window), "commit_is_empty"); +/* now mark #98 lost */ + pgm_rxw_lost (window, 98); + for (unsigned i = 0; i < 98; i++) + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + fail_unless ((1 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); + } + fail_unless (100 == pgm_rxw_length (window), "length failed"); + fail_unless ( 98 == _pgm_rxw_commit_length (window), "commit_length failed"); +/* read end-of-window */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + } + fail_unless (100 == pgm_rxw_length (window), "length failed"); + fail_unless ( 98 == _pgm_rxw_commit_length (window), "commit_length failed"); + pgm_rxw_remove_commit (window); +/* read lost skb #98 */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + } + pgm_rxw_remove_commit (window); +/* read valid skb #99 */ + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + } +/* read end-of-window */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + } + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_remove_commit_fail_001) +{ + pgm_rxw_remove_commit (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * unsigned + * pgm_rxw_remove_trail ( + * pgm_rxw_t* const window + * ) + */ + +START_TEST (test_remove_trail_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_msgv_t msgv[2], *pmsg; + fail_unless (0 == pgm_rxw_remove_trail (window), "remove_trail failed"); +/* #1,2 two APDUs */ + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (1); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry)); + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (2); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry)); + fail_unless (1 == pgm_rxw_remove_trail (window), "remove_trail failed"); + fail_unless (1 == pgm_rxw_length (window), "length failed"); + fail_unless (1000 == pgm_rxw_size (window), "size failed"); + pmsg = msgv; + fail_unless (1000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + fail_unless (0 == pgm_rxw_remove_trail (window), "remove_trail failed"); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_remove_trail_fail_001) +{ + guint count = pgm_rxw_remove_trail (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * unsigned + * pgm_rxw_update ( + * pgm_rxw_t* const window, + * const uint32_t txw_trail, + * const uint32_t txw_lead, + * const pgm_time_t now, + * const pgm_time_t nak_rb_expiry + * ) + */ + +START_TEST (test_update_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (0 == pgm_rxw_update (window, 100, 99, now, nak_rb_expiry), "update failed"); +/* dupe */ + fail_unless (0 == pgm_rxw_update (window, 100, 99, now, nak_rb_expiry), "update failed"); +/* #1 at 100 */ + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (100); + fail_unless (PGM_RXW_BOUNDS == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not bounds"); +/* #2 at 101 */ + skb->pgm_data->data_sqn = g_htonl (101); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + struct pgm_msgv_t msgv[1], *pmsg = msgv; + fail_unless (1000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); +/* #3 at 102 */ + fail_unless (1 == pgm_rxw_update (window, 102, 99, now, nak_rb_expiry), "update failed"); + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (102); + fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_update_fail_001) +{ + guint count = pgm_rxw_update (NULL, 0, 0, 0, 0); + fail ("reached"); +} +END_TEST + +/* target: + * int + * pgm_rxw_confirm ( + * pgm_rxw_t* const window, + * const uint32_t sequence, + * const pgm_time_t now, + * const pgm_time_t nak_rdata_expiry, + * const pgm_time_t nak_rb_expiry + * ) + */ + +START_TEST (test_confirm_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + const pgm_time_t now = 1; + const pgm_time_t nak_rdata_expiry = 2; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_BOUNDS == pgm_rxw_confirm (window, 0, now, nak_rdata_expiry, nak_rb_expiry), "confirm not bounds"); +/* #1 at 100 */ + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (100); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (1 == pgm_rxw_length (window), "length failed"); + fail_unless (PGM_RXW_BOUNDS == pgm_rxw_confirm (window, 99, now, nak_rdata_expiry, nak_rb_expiry), "confirm not bounds"); + fail_unless (PGM_RXW_DUPLICATE == pgm_rxw_confirm (window, 100, now, nak_rdata_expiry, nak_rb_expiry), "confirm not duplicate"); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_confirm (window, 101, now, nak_rdata_expiry, nak_rb_expiry), "confirm not appended"); + fail_unless (2 == pgm_rxw_length (window)); + fail_unless (PGM_RXW_UPDATED == pgm_rxw_confirm (window, 101, now, nak_rdata_expiry, nak_rb_expiry), "confirm not updated"); +/* #2 at 101 */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (101); + fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); + struct pgm_msgv_t msgv[2], *pmsg = msgv; + fail_unless (2000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + pgm_rxw_destroy (window); +} +END_TEST + +/* constrained confirm */ +START_TEST (test_confirm_pass_002) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_msgv_t msgv[1], *pmsg; + struct pgm_sk_buff_t* skb; + for (unsigned i = 0; i < 100; i++) + { + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (MIN(100, 1 + i) == pgm_rxw_length (window), "length failed"); + } + fail_unless (pgm_rxw_is_full (window), "is_full failed"); + fail_unless (_pgm_rxw_commit_is_empty (window), "is_empty failed"); +/* read one skb */ + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + fail_unless (1 == _pgm_rxw_commit_length (window), "commit_length failed"); + } +/* confirm next sequence */ + const pgm_time_t now = 1; + const pgm_time_t nak_rdata_expiry = 2; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_BOUNDS == pgm_rxw_confirm (window, 100, now, nak_rdata_expiry, nak_rb_expiry), "confirm not bounds"); +/* read off 99 more skbs */ + for (unsigned i = 0; i < 99; i++) + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + fail_unless ((2 + i) == _pgm_rxw_commit_length (window), "commit_length failed"); + } +/* read end-of-window */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + } + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_confirm_fail_001) +{ + int retval = pgm_rxw_confirm (NULL, 0, 0, 0, 0); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_rxw_lost ( + * pgm_rxw_t* const window, + * const uint32_t sequence + * ) + */ + +START_TEST (test_lost_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + const pgm_time_t now = 1; + const pgm_time_t nak_rdata_expiry = 2; + const pgm_time_t nak_rb_expiry = 2; +/* #1 at 100 */ + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (100); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); + fail_unless (1 == pgm_rxw_length (window), "length failed"); + fail_unless (1000 == pgm_rxw_size (window), "size failed"); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_confirm (window, 101, now, nak_rdata_expiry, nak_rb_expiry), "confirm not appended"); + fail_unless (2 == pgm_rxw_length (window), "length failed"); + fail_unless (1000 == pgm_rxw_size (window), "size failed"); + pgm_rxw_lost (window, 101); + fail_unless (2 == pgm_rxw_length (window), "length failed"); + fail_unless (1000 == pgm_rxw_size (window), "size failed"); +/* #2 at 101 */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (101); + fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); + fail_unless (2 == pgm_rxw_length (window), "length failed"); + fail_unless (2000 == pgm_rxw_size (window), "size failed"); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_lost_fail_001) +{ + pgm_rxw_lost (NULL, 0); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_rxw_state ( + * pgm_rxw_t* const window, + * struct pgm_sk_buff_t* skb, + * int new_state + * ) + */ + +START_TEST (test_state_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + const pgm_time_t now = 1; + const pgm_time_t nak_rdata_expiry = 2; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (0 == pgm_rxw_update (window, 100, 99, now, nak_rb_expiry), "update failed"); + fail_unless (PGM_RXW_APPENDED == pgm_rxw_confirm (window, 101, now, nak_rdata_expiry, nak_rb_expiry), "confirm not appended"); + struct pgm_sk_buff_t* skb = pgm_rxw_peek (window, 101); + pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_NCF); + pgm_rxw_state (window, skb, PGM_PKT_STATE_WAIT_DATA); + pgm_rxw_destroy (window); +} +END_TEST + +START_TEST (test_state_fail_001) +{ + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + pgm_rxw_state (NULL, skb, PGM_PKT_STATE_BACK_OFF); + fail ("reached"); +} +END_TEST + +START_TEST (test_state_fail_002) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + pgm_rxw_state (window, NULL, PGM_PKT_STATE_BACK_OFF); + fail ("reached"); +} +END_TEST + +START_TEST (test_state_fail_003) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + pgm_rxw_state (window, skb, -1); + fail ("reached"); +} +END_TEST + +/* pgm_peer_has_pending + */ + +START_TEST (test_has_pending_pass_001) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window, "create failed"); +/* empty */ + fail_unless (0 == window->has_event, "unexpected event"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (0); + const pgm_time_t now = 1; + const pgm_time_t nak_rdata_expiry = 2; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not appended"); +/* 1 sequence */ + fail_unless (1 == window->has_event, "no event"); + window->has_event = 0; +/* jump */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (2); + fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not missing"); + fail_unless (0 == window->has_event, "unexpected event"); +/* loss */ + pgm_rxw_lost (window, 1); + fail_unless (1 == window->has_event, "no event"); + window->has_event = 0; +/* insert */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + skb->pgm_data->data_sqn = g_htonl (1); + fail_unless (PGM_RXW_INSERTED == pgm_rxw_add (window, skb, now, nak_rb_expiry), "add not inserted"); + fail_unless (1 == window->has_event, "no event"); + window->has_event = 0; +/* confirm */ + fail_unless (PGM_RXW_APPENDED == pgm_rxw_confirm (window, 3, now, nak_rdata_expiry, nak_rb_expiry), "confirm not appended"); + fail_unless (0 == window->has_event, "unexpected event"); +/* partial read */ + struct pgm_msgv_t msgv[2], *pmsg = msgv; + fail_unless (2000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + fail_unless (0 == window->has_event, "unexpected event"); +/* finish read */ + pmsg = msgv; + fail_unless (1000 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)), "readv failed"); + fail_unless (0 == window->has_event, "unexpected event"); + pgm_rxw_destroy (window); +} +END_TEST + +static +Suite* +make_basic_test_suite (void) +{ + Suite* s; + + s = suite_create ("basic receive window API"); + + TCase* tc_create = tcase_create ("create"); + suite_add_tcase (s, tc_create); + tcase_add_test (tc_create, test_create_pass_001); + tcase_add_test (tc_create, test_create_pass_002); + tcase_add_test (tc_create, test_create_pass_003); + tcase_add_test (tc_create, test_create_pass_004); + tcase_add_test_raise_signal (tc_create, test_create_fail_001, SIGABRT); + tcase_add_test_raise_signal (tc_create, test_create_fail_002, SIGABRT); + tcase_add_test_raise_signal (tc_create, test_create_fail_003, SIGABRT); + tcase_add_test_raise_signal (tc_create, test_create_fail_004, SIGABRT); + + TCase* tc_destroy = tcase_create ("destroy"); + suite_add_tcase (s, tc_destroy); + tcase_add_test (tc_destroy, test_destroy_pass_001); + tcase_add_test_raise_signal (tc_destroy, test_destroy_fail_001, SIGABRT); + + TCase* tc_add = tcase_create ("add"); + suite_add_tcase (s, tc_add); + tcase_add_test (tc_add, test_add_pass_001); + tcase_add_test (tc_add, test_add_pass_002); + tcase_add_test (tc_add, test_add_pass_003); + tcase_add_test (tc_add, test_add_pass_004); + tcase_add_test (tc_add, test_add_pass_005); + tcase_add_test_raise_signal (tc_add, test_add_fail_001, SIGABRT); + tcase_add_test_raise_signal (tc_add, test_add_fail_002, SIGABRT); + tcase_add_test_raise_signal (tc_add, test_add_fail_003, SIGABRT); + + TCase* tc_peek = tcase_create ("peek"); + suite_add_tcase (s, tc_peek); + tcase_add_test (tc_peek, test_peek_pass_001); + tcase_add_test_raise_signal (tc_peek, test_peek_fail_001, SIGABRT); + + TCase* tc_max_length = tcase_create ("max-length"); + suite_add_tcase (s, tc_max_length); + tcase_add_test (tc_max_length, test_max_length_pass_001); + tcase_add_test_raise_signal (tc_max_length, test_max_length_fail_001, SIGABRT); + + TCase* tc_length = tcase_create ("length"); + suite_add_tcase (s, tc_length); + tcase_add_test (tc_length, test_length_pass_001); + tcase_add_test_raise_signal (tc_length, test_length_fail_001, SIGABRT); + + TCase* tc_size = tcase_create ("size"); + suite_add_tcase (s, tc_size); + tcase_add_test (tc_size, test_size_pass_001); + tcase_add_test_raise_signal (tc_size, test_size_fail_001, SIGABRT); + + TCase* tc_is_empty = tcase_create ("is-empty"); + suite_add_tcase (s, tc_is_empty); + tcase_add_test (tc_is_empty, test_is_empty_pass_001); + tcase_add_test_raise_signal (tc_is_empty, test_is_empty_fail_001, SIGABRT); + + TCase* tc_is_full = tcase_create ("is-full"); + suite_add_tcase (s, tc_is_full); + tcase_add_test (tc_is_full, test_is_full_pass_001); + tcase_add_test_raise_signal (tc_is_full, test_is_full_fail_001, SIGABRT); + + TCase* tc_lead = tcase_create ("lead"); + suite_add_tcase (s, tc_lead); + tcase_add_test (tc_lead, test_lead_pass_001); + tcase_add_test_raise_signal (tc_lead, test_lead_fail_001, SIGABRT); + + TCase* tc_next_lead = tcase_create ("next-lead"); + suite_add_tcase (s, tc_next_lead); + tcase_add_test (tc_next_lead, test_next_lead_pass_001); + tcase_add_test_raise_signal (tc_next_lead, test_next_lead_fail_001, SIGABRT); + + TCase* tc_readv = tcase_create ("readv"); + suite_add_tcase (s, tc_readv); + tcase_add_test (tc_readv, test_readv_pass_001); + tcase_add_test (tc_readv, test_readv_pass_002); + tcase_add_test (tc_readv, test_readv_pass_003); + tcase_add_test (tc_readv, test_readv_pass_004); + tcase_add_test (tc_readv, test_readv_pass_005); + tcase_add_test (tc_readv, test_readv_pass_006); + tcase_add_test_raise_signal (tc_readv, test_readv_fail_001, SIGABRT); + tcase_add_test_raise_signal (tc_readv, test_readv_fail_002, SIGABRT); + tcase_add_test_raise_signal (tc_readv, test_readv_fail_003, SIGABRT); + + TCase* tc_remove_commit = tcase_create ("remove-commit"); + suite_add_tcase (s, tc_remove_commit); + tcase_add_test (tc_remove_commit, test_remove_commit_pass_001); + tcase_add_test_raise_signal (tc_remove_commit, test_remove_commit_fail_001, SIGABRT); + + TCase* tc_remove_trail = tcase_create ("remove-trail"); + TCase* tc_update = tcase_create ("update"); + suite_add_tcase (s, tc_update); + tcase_add_test (tc_update, test_update_pass_001); + tcase_add_test_raise_signal (tc_update, test_update_fail_001, SIGABRT); + + TCase* tc_confirm = tcase_create ("confirm"); + suite_add_tcase (s, tc_confirm); + tcase_add_test (tc_confirm, test_confirm_pass_001); + tcase_add_test (tc_confirm, test_confirm_pass_002); + tcase_add_test_raise_signal (tc_confirm, test_confirm_fail_001, SIGABRT); + + TCase* tc_lost = tcase_create ("lost"); + suite_add_tcase (s, tc_lost); + tcase_add_test (tc_lost, test_lost_pass_001); + tcase_add_test_raise_signal (tc_lost, test_lost_fail_001, SIGABRT); + + TCase* tc_state = tcase_create ("state"); + suite_add_tcase (s, tc_state); + tcase_add_test (tc_state, test_state_pass_001); + tcase_add_test_raise_signal (tc_state, test_state_fail_001, SIGABRT); + + return s; +} + +/* read through lost packet */ +START_TEST (test_readv_pass_007) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window); + struct pgm_msgv_t msgv[1], *pmsg; + struct pgm_sk_buff_t* skb; +/* add #0 */ + { + unsigned i = 0; + skb = generate_valid_skb (); + fail_if (NULL == skb); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry)); + fail_unless ((1 + i) == pgm_rxw_length (window)); + } +/* add # 2 */ + { + unsigned i = 2; + skb = generate_valid_skb (); + fail_if (NULL == skb); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry)); + fail_unless ((1 + i) == pgm_rxw_length (window)); + } +/* lose #1 */ + { + pgm_rxw_lost (window, 1); + } + fail_unless (_pgm_rxw_commit_is_empty (window)); +/* read #0 */ + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + } +/* end-of-window */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + } + pgm_rxw_remove_commit (window); +/* read lost skb #1 */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + } + pgm_rxw_remove_commit (window); +/* read #2 */ + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + } +/* end-of-window */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + } + pgm_rxw_destroy (window); +} +END_TEST + +/* read through loss extended window */ +START_TEST (test_readv_pass_008) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window); + struct pgm_msgv_t msgv[1], *pmsg; + struct pgm_sk_buff_t* skb; +/* add #0 */ + { + unsigned i = 0; + skb = generate_valid_skb (); + fail_if (NULL == skb); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry)); + fail_unless ((1 + i) == pgm_rxw_length (window)); + } + fail_unless (_pgm_rxw_commit_is_empty (window)); +/* read #0 */ + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + } + pgm_rxw_remove_commit (window); +/* end-of-window */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + } +/* add #100 */ + { + unsigned i = 100; + skb = generate_valid_skb (); + fail_if (NULL == skb); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry)); + } +/* lose #1-99 */ + { + for (unsigned i = 1; i < 100; i++) + pgm_rxw_lost (window, i); + } +/* read #100 */ + { + int i = 0; + int bytes_read; + pmsg = msgv; + do { + bytes_read = pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)); + pgm_rxw_remove_commit (window); + i++; + if (i > 100) break; + } while (-1 == bytes_read); + fail_unless (100 == i); + } +/* end-of-window */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + } + pgm_rxw_destroy (window); +} +END_TEST + +/* read through long data-loss */ +START_TEST (test_readv_pass_009) +{ + pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const uint32_t ack_c_p = 500; + pgm_rxw_t* window = pgm_rxw_create (&tsi, 1500, 100, 0, 0, ack_c_p); + fail_if (NULL == window); + struct pgm_msgv_t msgv[1], *pmsg; + struct pgm_sk_buff_t* skb; +/* add #0 */ + { + unsigned i = 0; + skb = generate_valid_skb (); + fail_if (NULL == skb); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_APPENDED == pgm_rxw_add (window, skb, now, nak_rb_expiry)); + fail_unless ((1 + i) == pgm_rxw_length (window)); + } + fail_unless (_pgm_rxw_commit_is_empty (window)); +/* read #0 */ + { + pmsg = msgv; + fail_unless (0 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + } + pgm_rxw_remove_commit (window); +/* end-of-window */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + } +/* add #2000 */ + { + unsigned i = 2000; + skb = generate_valid_skb (); + fail_if (NULL == skb); + skb->pgm_header->pgm_tsdu_length = g_htons (0); + skb->tail = (guint8*)skb->tail - skb->len; + skb->len = 0; + skb->pgm_data->data_sqn = g_htonl (i); + const pgm_time_t now = 1; + const pgm_time_t nak_rb_expiry = 2; + fail_unless (PGM_RXW_MISSING == pgm_rxw_add (window, skb, now, nak_rb_expiry)); + } +/* lose #1-1999 */ + { + for (unsigned i = 1901; i < 2000; i++) + pgm_rxw_lost (window, i); + } +/* read #2000 */ + { + int i = 0; + int bytes_read; + pmsg = msgv; + do { + bytes_read = pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv)); + pgm_rxw_remove_commit (window); + i++; + if (i > 100) break; + } while (-1 == bytes_read); + fail_unless (100 == i); + } +/* end-of-window */ + { + pmsg = msgv; + fail_unless (-1 == pgm_rxw_readv (window, &pmsg, G_N_ELEMENTS(msgv))); + } + pgm_rxw_destroy (window); +} +END_TEST + +/* a.k.a. unreliable delivery + */ + +static +Suite* +make_best_effort_test_suite (void) +{ + Suite* s; + + s = suite_create ("Best effort delivery"); + + TCase* tc_readv = tcase_create ("readv"); + suite_add_tcase (s, tc_readv); + tcase_add_test (tc_readv, test_readv_pass_007); + tcase_add_test (tc_readv, test_readv_pass_008); + tcase_add_test (tc_readv, test_readv_pass_009); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_basic_test_suite ()); + srunner_add_suite (sr, make_best_effort_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/signal.c b/3rdparty/openpgm-svn-r1135/pgm/signal.c new file mode 100644 index 0000000..ab1fb86 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/signal.c @@ -0,0 +1,179 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Re-entrant safe signal handling. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#include /* _GNU_SOURCE for strsignal() */ +#include +#ifndef G_OS_WIN32 +# include +#else +# include +#endif +#include +#include "pgm/signal.h" + + +//#define SIGNAL_DEBUG + + +/* globals */ + +static pgm_sighandler_t signal_list[NSIG]; +static int signal_pipe[2]; +static GIOChannel* signal_io = NULL; + +static void on_signal (int); +static gboolean on_io_signal (GIOChannel*, GIOCondition, gpointer); +static const char* cond_string (GIOCondition); + + +static +void +set_nonblock ( + const int s, + const gboolean v + ) +{ +#ifndef G_OS_WIN32 + int flags = fcntl (s, F_GETFL); + if (!v) flags &= ~O_NONBLOCK; + else flags |= O_NONBLOCK; + fcntl (s, F_SETFL, flags); +#else + u_long mode = v; + ioctlsocket (s, FIONBIO, &mode); +#endif +} + +/* install signal handler and return unix fd to add to event loop + */ + +gboolean +pgm_signal_install ( + int signum, + pgm_sighandler_t handler, + gpointer user_data + ) +{ + g_debug ("pgm_signal_install (signum:%d handler:%p user_data:%p)", + signum, (const void*)handler, user_data); + + if (NULL == signal_io) + { +#ifdef G_OS_UNIX + if (pipe (signal_pipe)) +#else + if (_pipe (signal_pipe, 4096, _O_BINARY | _O_NOINHERIT)) +#endif + return FALSE; + + set_nonblock (signal_pipe[0], TRUE); + set_nonblock (signal_pipe[1], TRUE); +/* add to evm */ + signal_io = g_io_channel_unix_new (signal_pipe[0]); + g_io_add_watch (signal_io, G_IO_IN, on_io_signal, user_data); + } + + signal_list[signum] = handler; + return (SIG_ERR != signal (signum, on_signal)); +} + +/* process signal from operating system + */ + +static +void +on_signal ( + int signum + ) +{ + g_debug ("on_signal (signum:%d)", signum); + if (write (signal_pipe[1], &signum, sizeof(signum)) != sizeof(signum)) + { +#ifndef G_OS_WIN32 + g_warning ("Unix signal %s (%d) lost", strsignal (signum), signum); +#else + g_warning ("Unix signal (%d) lost", signum); +#endif + } +} + +/* process signal from pipe + */ + +static +gboolean +on_io_signal ( + GIOChannel* source, + GIOCondition cond, + gpointer user_data + ) +{ +/* pre-conditions */ + g_assert (NULL != source); + g_assert (G_IO_IN == cond); + + g_debug ("on_io_signal (source:%p cond:%s user_data:%p)", + (gpointer)source, cond_string (cond), user_data); + + int signum; + const gsize bytes_read = read (g_io_channel_unix_get_fd (source), &signum, sizeof(signum)); + + if (sizeof(signum) == bytes_read) + { + signal_list[signum] (signum, user_data); + } + else + { + g_warning ("Lost data in signal pipe, read %" G_GSIZE_FORMAT " byte%s expected %" G_GSIZE_FORMAT ".", + bytes_read, bytes_read > 1 ? "s" : "", sizeof(signum)); + } + + return TRUE; +} + +static +const char* +cond_string ( + GIOCondition cond + ) +{ + const char* c; + + switch (cond) { + case G_IO_IN: c = "G_IO_IN"; break; + case G_IO_OUT: c = "G_IO_OUT"; break; + case G_IO_PRI: c = "G_IO_PRI"; break; + case G_IO_ERR: c = "G_IO_ERR"; break; + case G_IO_HUP: c = "G_IO_HUP"; break; + case G_IO_NVAL: c = "G_IO_NVAL"; break; + default: c = "(unknown)"; break; + } + + return c; +} + + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/signal_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/signal_unittest.c new file mode 100644 index 0000000..4784053 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/signal_unittest.c @@ -0,0 +1,115 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for re-entrant safe signal handling. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include + + +/* mock state */ + +static +void +on_sigusr1 ( + int signum, + gpointer user_data + ) +{ + g_assert (SIGUSR1 == signum); + g_assert (NULL != user_data); + GMainLoop* loop = (GMainLoop*)user_data; + g_debug ("on_sigusr1 (signum:%d)", signum); + g_main_loop_quit (loop); +} + +/* mock functions for external references */ + +#define SIGNAL_DEBUG +#include "signal.c" + + +/* target: + * pgm_sighandler_t + * pgm_signal_install ( + * int signum, + pgm_sighandler_t handler + * ) + */ + +static +gboolean +on_startup ( + gpointer data + ) +{ + g_assert (NULL != data); + const int signum = *(const int*)data; + fail_unless (0 == raise (signum)); + return FALSE; +} + +START_TEST (test_install_pass_001) +{ + const int signum = SIGUSR1; + GMainLoop* loop = g_main_loop_new (NULL, FALSE); + fail_unless (TRUE == pgm_signal_install (signum, on_sigusr1, loop)); + g_timeout_add (0, (GSourceFunc)on_startup, &signum); + g_main_loop_run (loop); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_install = tcase_create ("install"); + suite_add_tcase (s, tc_install); + tcase_add_test (tc_install, test_install_pass_001); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/skbuff.c b/3rdparty/openpgm-svn-r1135/pgm/skbuff.c new file mode 100644 index 0000000..5db6ffc --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/skbuff.c @@ -0,0 +1,115 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM socket buffers + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "pgm/skbuff.h" + + +void +pgm_skb_over_panic ( + const struct pgm_sk_buff_t*const skb, + const uint16_t len + ) +{ + pgm_fatal ("skput:over: %u put:%u", + skb->len, len); + pgm_assert_not_reached(); +} + +void +pgm_skb_under_panic ( + const struct pgm_sk_buff_t*const skb, + const uint16_t len + ) +{ + pgm_fatal ("skput:under: %u put:%u", + skb->len, len); + pgm_assert_not_reached(); +} + +#ifndef SKB_DEBUG +bool +pgm_skb_is_valid ( + PGM_GNUC_UNUSED const struct pgm_sk_buff_t*const skb + ) +{ + return TRUE; +} +#else +bool +pgm_skb_is_valid ( + const struct pgm_sk_buff_t*const skb + ) +{ + pgm_return_val_if_fail (skb, FALSE); +/* link_ */ +/* socket */ + pgm_return_val_if_fail (skb->sock, FALSE); +/* tstamp */ + pgm_return_val_if_fail (skb->tstamp > 0, FALSE); +/* tsi */ +/* sequence can be any value */ +/* cb can be any value */ +/* len can be any value */ +/* zero_padded can be any value */ +/* gpointers */ + pgm_return_val_if_fail (skb->head, FALSE); + pgm_return_val_if_fail ((const char*)skb->head > (const char*)&skb->users, FALSE); + pgm_return_val_if_fail (skb->data, FALSE); + pgm_return_val_if_fail ((const char*)skb->data >= (const char*)skb->head, FALSE); + pgm_return_val_if_fail (skb->tail, FALSE); + pgm_return_val_if_fail ((const char*)skb->tail >= (const char*)skb->data, FALSE); + pgm_return_val_if_fail (skb->len == (char*)skb->tail - (const char*)skb->data, FALSE); + pgm_return_val_if_fail (skb->end, FALSE); + pgm_return_val_if_fail ((const char*)skb->end >= (const char*)skb->tail, FALSE); +/* pgm_header */ + if (skb->pgm_header) { + pgm_return_val_if_fail ((const char*)skb->pgm_header >= (const char*)skb->head, FALSE); + pgm_return_val_if_fail ((const char*)skb->pgm_header + sizeof(struct pgm_header) <= (const char*)skb->tail, FALSE); + pgm_return_val_if_fail (skb->pgm_data, FALSE); + pgm_return_val_if_fail ((const char*)skb->pgm_data >= (const char*)skb->pgm_header + sizeof(struct pgm_header), FALSE); + pgm_return_val_if_fail ((const char*)skb->pgm_data <= (const char*)skb->tail, FALSE); + if (skb->pgm_opt_fragment) { + pgm_return_val_if_fail ((const char*)skb->pgm_opt_fragment > (const char*)skb->pgm_data, FALSE); + pgm_return_val_if_fail ((const char*)skb->pgm_opt_fragment + sizeof(struct pgm_opt_fragment) < (const char*)skb->tail, FALSE); +/* of_apdu_first_sqn can be any value */ +/* of_frag_offset */ + pgm_return_val_if_fail (ntohl (skb->of_frag_offset) < ntohl (skb->of_apdu_len), FALSE); +/* of_apdu_len can be any value */ + } + pgm_return_val_if_fail (PGM_ODATA == skb->pgm_header->pgm_type || PGM_RDATA == skb->pgm_header->pgm_type, FALSE); +/* FEC broken */ + pgm_return_val_if_fail (0 == (skb->pgm_header->pgm_options & PGM_OPT_PARITY), FALSE); + pgm_return_val_if_fail (0 == (skb->pgm_header->pgm_options & PGM_OPT_VAR_PKTLEN), FALSE); + } else { + pgm_return_val_if_fail (NULL == skb->pgm_data, FALSE); + pgm_return_val_if_fail (NULL == skb->pgm_opt_fragment, FALSE); + } +/* truesize */ + pgm_return_val_if_fail (skb->truesize >= sizeof(struct pgm_sk_buff_t*) + skb->len, FALSE); + pgm_return_val_if_fail (skb->truesize == ((const char*)skb->end - (const char*)skb), FALSE); +/* users */ + pgm_return_val_if_fail (pgm_atomic_read32 (&skb->users) > 0, FALSE); + return TRUE; +} +#endif /* SKB_DEBUG */ + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/slist.c b/3rdparty/openpgm-svn-r1135/pgm/slist.c new file mode 100644 index 0000000..9ba68ea --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/slist.c @@ -0,0 +1,166 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable singly-linked list. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + + +//#define SLIST_DEBUG + +pgm_slist_t* +pgm_slist_append ( + pgm_slist_t* restrict list, + void* restrict data + ) +{ + pgm_slist_t* new_list; + pgm_slist_t* last; + + new_list = pgm_new (pgm_slist_t, 1); + new_list->data = data; + new_list->next = NULL; + + if (list) + { + last = pgm_slist_last (list); + last->next = new_list; + return list; + } + else + return new_list; +} + +pgm_slist_t* +pgm_slist_prepend ( + pgm_slist_t* restrict list, + void* restrict data + ) +{ + pgm_slist_t *new_list; + + new_list = pgm_new (pgm_slist_t, 1); + new_list->data = data; + new_list->next = list; + + return new_list; +} + +pgm_slist_t* +pgm_slist_prepend_link ( + pgm_slist_t* restrict list, + pgm_slist_t* restrict link_ + ) +{ + pgm_slist_t *new_list; + + new_list = link_; + new_list->next = list; + + return new_list; +} + +pgm_slist_t* +pgm_slist_remove ( + pgm_slist_t* restrict list, + const void* restrict data + ) +{ + pgm_slist_t *tmp = list, *prev = NULL; + + while (tmp) + { + if (tmp->data == data) + { + if (prev) + prev->next = tmp->next; + else + list = tmp->next; + pgm_free (tmp); + break; + } + prev = tmp; + tmp = prev->next; + } + + return list; +} + +pgm_slist_t* +pgm_slist_remove_first ( + pgm_slist_t* list + ) +{ + pgm_slist_t *tmp; + + if (PGM_LIKELY (NULL != list)) + { + tmp = list->next; + list->data = NULL; + list->next = NULL; + return tmp; + } + else + return NULL; +} + +void +pgm_slist_free ( + pgm_slist_t* list + ) +{ + while (list) + { + pgm_slist_t* current = list; + list = list->next; + pgm_free (current); + } +} + +pgm_slist_t* +pgm_slist_last ( + pgm_slist_t* list + ) +{ + if (PGM_LIKELY (NULL != list)) + { + while (list->next) + list = list->next; + } + + return list; +} + +unsigned +pgm_slist_length ( + pgm_slist_t* list + ) +{ + unsigned length = 0; + + while (list) + { + length++; + list = list->next; + } + + return length; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/snmp.c b/3rdparty/openpgm-svn-r1135/pgm/snmp.c new file mode 100644 index 0000000..5673878 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/snmp.c @@ -0,0 +1,222 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * SNMP agent, single session. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include +#include +#include + +#include "pgm/snmp.h" +#include "impl/pgmMIB.h" + + +/* globals */ + +bool pgm_agentx_subagent = TRUE; +char* pgm_agentx_socket = NULL; +char* pgm_snmp_appname = "PGM"; + +/* locals */ + +#ifndef _WIN32 +static pthread_t snmp_thread; +static void* snmp_routine (void*); +#else +static HANDLE snmp_thread; +static unsigned __stdcall snmp_routine (void*); +#endif +static pgm_notify_t snmp_notify = PGM_NOTIFY_INIT; +static volatile uint32_t snmp_ref_count = 0; + + +/* Calling application needs to redirect SNMP logging before prior to this + * function. + */ + +bool +pgm_snmp_init ( + pgm_error_t** error + ) +{ + if (pgm_atomic_exchange_and_add32 (&snmp_ref_count, 1) > 0) + return TRUE; + + if (pgm_agentx_subagent) + { + pgm_minor (_("Configuring as SNMP AgentX sub-agent.")); + if (pgm_agentx_socket) + { + pgm_minor (_("Using AgentX socket %s."), pgm_agentx_socket); + netsnmp_ds_set_string (NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_X_SOCKET, + pgm_agentx_socket); + } + netsnmp_ds_set_boolean (NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_ROLE, + TRUE); + } + + pgm_minor (_("Initialising SNMP agent.")); + if (0 != init_agent (pgm_snmp_appname)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SNMP, + PGM_ERROR_FAILED, + _("Initialise SNMP agent: see SNMP log for further details.")); + goto err_cleanup; + } + + if (!pgm_mib_init (error)) { + goto err_cleanup; + } + +/* read config and parse mib */ + pgm_minor (_("Initialising SNMP.")); + init_snmp (pgm_snmp_appname); + + if (!pgm_agentx_subagent) + { + pgm_minor (_("Connecting to SNMP master agent.")); + if (0 != init_master_agent ()) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SNMP, + PGM_ERROR_FAILED, + _("Initialise SNMP master agent: see SNMP log for further details.")); + snmp_shutdown (pgm_snmp_appname); + goto err_cleanup; + } + } + +/* create notification channel */ + if (0 != pgm_notify_init (&snmp_notify)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SNMP, + pgm_error_from_errno (errno), + _("Creating SNMP notification channel: %s"), + strerror (errno)); + snmp_shutdown (pgm_snmp_appname); + goto err_cleanup; + } + +/* spawn thread to handle SNMP requests */ +#ifndef _WIN32 + const int status = pthread_create (&snmp_thread, NULL, &snmp_routine, NULL); + if (0 != status) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SNMP, + pgm_error_from_errno (errno), + _("Creating SNMP thread: %s"), + strerror (errno)); + snmp_shutdown (pgm_snmp_appname); + goto err_cleanup; + } +#else + snmp_thread = (HANDLE)_beginthreadex (NULL, 0, &snmp_routine, NULL, 0, NULL); + const int save_errno = errno; + if (0 == snmp_thread) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SNMP, + pgm_error_from_errno (save_errno), + _("Creating SNMP thread: %s"), + strerror (save_errno)); + snmp_shutdown (pgm_snmp_appname); + goto err_cleanup; + } +#endif /* _WIN32 */ + return TRUE; +err_cleanup: + if (pgm_notify_is_valid (&snmp_notify)) { + pgm_notify_destroy (&snmp_notify); + } + pgm_atomic_dec32 (&snmp_ref_count); + return FALSE; +} + +/* Terminate SNMP thread and free resources. + */ + +bool +pgm_snmp_shutdown (void) +{ + pgm_return_val_if_fail (pgm_atomic_read32 (&snmp_ref_count) > 0, FALSE); + + if (pgm_atomic_exchange_and_add32 (&snmp_ref_count, (uint32_t)-1) != 1) + return TRUE; + + pgm_notify_send (&snmp_notify); +#ifndef _WIN32 + pthread_join (snmp_thread, NULL); +#else + CloseHandle (snmp_thread); +#endif + pgm_notify_destroy (&snmp_notify); + snmp_shutdown (pgm_snmp_appname); + return TRUE; +} + +/* Thread routine for processing SNMP requests + */ + +static +#ifndef _WIN32 +void* +#else +unsigned +__stdcall +#endif +snmp_routine ( + PGM_GNUC_UNUSED void* arg + ) +{ + const int notify_fd = pgm_notify_get_fd (&snmp_notify); + + for (;;) + { + int fds = 0, block = 1; + fd_set fdset; + struct timeval timeout; + + FD_ZERO(&fdset); + snmp_select_info (&fds, &fdset, &timeout, &block); + FD_SET(notify_fd, &fdset); + if (notify_fd+1 > fds) + fds = notify_fd+1; + fds = select (fds, &fdset, NULL, NULL, block ? NULL : &timeout); + if (FD_ISSET(notify_fd, &fdset)) + break; + if (fds) + snmp_read (&fdset); + else + snmp_timeout(); + } + +/* cleanup */ +#ifndef _WIN32 + return NULL; +#else + _endthread(); + return 0; +#endif /* WIN32 */ +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/snmp_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/snmp_unittest.c new file mode 100644 index 0000000..9005a82 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/snmp_unittest.c @@ -0,0 +1,184 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for SNMP. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include + +#include "pgm/transport.h" + + +/* mock state */ +static const guint mock_pgm_major_version = 0; +static const guint mock_pgm_minor_version = 0; +static const guint mock_pgm_micro_version = 0; +static GStaticRWLock mock_pgm_transport_list_lock = G_STATIC_RW_LOCK_INIT; +static GSList* mock_pgm_transport_list = NULL; + +static +gboolean +mock_pgm_tsi_equal ( + gconstpointer v1, + gconstpointer v2 + ) +{ + return memcmp (v1, v2, sizeof(struct pgm_tsi_t)) == 0; +} + +static +void +mock_pgm_time_since_epoch ( + pgm_time_t* pgm_time_t_time, + time_t* time_t_time + ) +{ + *time_t_time = pgm_to_secs (*pgm_time_t_time + 0); +} + +static +gboolean +mock_pgm_mib_init ( + GError** error + ) +{ + return TRUE; +} + +/* mock functions for external references */ + +#define pgm_major_version mock_pgm_major_version +#define pgm_minor_version mock_pgm_minor_version +#define pgm_micro_version mock_pgm_micro_version +#define pgm_transport_list_lock mock_pgm_transport_list_lock +#define pgm_transport_list mock_pgm_transport_list +#define pgm_tsi_equal mock_pgm_tsi_equal +#define pgm_time_since_epoch mock_pgm_time_since_epoch +#define pgm_mib_init mock_pgm_mib_init + + +#define SNMP_DEBUG +#include "snmp.c" + + +/* target: + * gboolean + * pgm_snmp_init ( + * GError** error + * ) + */ + +START_TEST (test_init_pass_001) +{ + GError* err = NULL; + fail_unless (TRUE == pgm_snmp_init (&err)); + fail_unless (NULL == err); +} +END_TEST + +/* duplicate servers */ +START_TEST (test_init_fail_001) +{ + GError* err = NULL; + fail_unless (TRUE == pgm_snmp_init (&err)); + fail_unless (FALSE == pgm_snmp_init (&err)); +} +END_TEST + +/* target: + * gboolean + * pgm_snmp_shutdown (void) + */ + +START_TEST (test_shutdown_pass_001) +{ + GError* err = NULL; + fail_unless (TRUE == pgm_snmp_init (&err)); + fail_unless (NULL == err); + fail_unless (TRUE == pgm_snmp_shutdown ()); +} +END_TEST + +/* repeatability + */ +START_TEST (test_shutdown_pass_002) +{ + GError* err = NULL; + fail_unless (TRUE == pgm_snmp_init (&err)); + fail_unless (NULL == err); + fail_unless (TRUE == pgm_snmp_shutdown ()); + fail_unless (TRUE == pgm_snmp_init (&err)); + fail_unless (NULL == err); + fail_unless (TRUE == pgm_snmp_shutdown ()); +} +END_TEST + +/* no running server */ +START_TEST (test_shutdown_fail_001) +{ + fail_unless (FALSE == pgm_snmp_shutdown ()); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_init = tcase_create ("init"); + suite_add_tcase (s, tc_init); + tcase_add_test (tc_init, test_init_pass_001); + tcase_add_test (tc_init, test_init_fail_001); + + TCase* tc_shutdown = tcase_create ("shutdown"); + suite_add_tcase (s, tc_shutdown); + tcase_add_test (tc_shutdown, test_shutdown_pass_001); + tcase_add_test (tc_shutdown, test_shutdown_pass_002); + tcase_add_test (tc_shutdown, test_shutdown_fail_001); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/sockaddr.c b/3rdparty/openpgm-svn-r1135/pgm/sockaddr.c new file mode 100644 index 0000000..df43d26 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/sockaddr.c @@ -0,0 +1,1193 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * struct sockaddr functions independent of in or in6. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#ifndef _WIN32 +# include +# include +#endif +#include + + +/* FreeBSD */ +#ifndef IPV6_ADD_MEMBERSHIP +# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif +/* OpenSolaris differences */ +#if !defined(_WIN32) && !defined(MCAST_MSFILTER) +# include +#endif +#ifndef SOL_IP +# define SOL_IP IPPROTO_IP +#endif +#ifndef SOL_IPV6 +# define SOL_IPV6 IPPROTO_IPV6 +#endif +#ifndef IP_MAX_MEMBERSHIPS +# define IP_MAX_MEMBERSHIPS 20 +#endif + + +sa_family_t +pgm_sockaddr_family ( + const struct sockaddr* sa + ) +{ + return sa->sa_family; +} + +uint16_t +pgm_sockaddr_port ( + const struct sockaddr* sa + ) +{ + uint16_t sa_port; + switch (sa->sa_family) { + case AF_INET: { + struct sockaddr_in s4; + memcpy (&s4, sa, sizeof(s4)); + sa_port = s4.sin_port; + break; + } + + case AF_INET6: { + struct sockaddr_in6 s6; + memcpy (&s6, sa, sizeof(s6)); + sa_port = s6.sin6_port; + break; + } + + default: + sa_port = 0; + break; + } + return sa_port; +} + +socklen_t +pgm_sockaddr_len ( + const struct sockaddr* sa + ) +{ + socklen_t sa_len; + switch (sa->sa_family) { + case AF_INET: sa_len = sizeof(struct sockaddr_in); break; + case AF_INET6: sa_len = sizeof(struct sockaddr_in6); break; + default: sa_len = 0; break; + } + return sa_len; +} + +socklen_t +pgm_sockaddr_storage_len ( + const struct sockaddr_storage* ss + ) +{ + socklen_t ss_len; + switch (ss->ss_family) { + case AF_INET: ss_len = sizeof(struct sockaddr_in); break; + case AF_INET6: ss_len = sizeof(struct sockaddr_in6); break; + default: ss_len = 0; break; + } + return ss_len; +} + +uint32_t +pgm_sockaddr_scope_id ( + const struct sockaddr* sa + ) +{ + uint32_t scope_id; + if (AF_INET6 == sa->sa_family) { + struct sockaddr_in6 s6; + memcpy (&s6, sa, sizeof(s6)); + scope_id = s6.sin6_scope_id; + } else + scope_id = 0; + return scope_id; +} + +int +pgm_sockaddr_ntop ( + const struct sockaddr* restrict sa, + char* restrict host, + size_t hostlen + ) +{ + return getnameinfo (sa, pgm_sockaddr_len (sa), + host, hostlen, + NULL, 0, + NI_NUMERICHOST); +} + +int +pgm_sockaddr_pton ( + const char* restrict src, + struct sockaddr* restrict dst /* will error on wrong size */ + ) +{ + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, /* not really */ + .ai_protocol = IPPROTO_TCP, /* not really */ + .ai_flags = AI_NUMERICHOST + }, *result = NULL; + const int status = getaddrinfo (src, NULL, &hints, &result); + if (PGM_LIKELY(0 == status)) { + memcpy (dst, result->ai_addr, result->ai_addrlen); + freeaddrinfo (result); + return 1; + } + return 0; +} + +/* returns tri-state value: 1 if sa is multicast, 0 if sa is not multicast, -1 on error + */ + +int +pgm_sockaddr_is_addr_multicast ( + const struct sockaddr* sa + ) +{ + int retval; + + switch (sa->sa_family) { + case AF_INET: { + struct sockaddr_in s4; + memcpy (&s4, sa, sizeof(s4)); + retval = IN_MULTICAST(ntohl( s4.sin_addr.s_addr )); + break; + } + + case AF_INET6: { + struct sockaddr_in6 s6; + memcpy (&s6, sa, sizeof(s6)); + retval = IN6_IS_ADDR_MULTICAST( &s6.sin6_addr ); + break; + } + + default: + retval = -1; + break; + } + return retval; +} + +/* returns 1 if sa is unspecified, 0 if specified. + */ + +int +pgm_sockaddr_is_addr_unspecified ( + const struct sockaddr* sa + ) +{ + int retval; + + switch (sa->sa_family) { + case AF_INET: { + struct sockaddr_in s4; + memcpy (&s4, sa, sizeof(s4)); + retval = (INADDR_ANY == s4.sin_addr.s_addr); + break; + } + + case AF_INET6: { + struct sockaddr_in6 s6; + memcpy (&s6, sa, sizeof(s6)); + retval = IN6_IS_ADDR_UNSPECIFIED( &s6.sin6_addr ); + break; + } + + default: + retval = -1; + break; + } + return retval; +} + +int +pgm_sockaddr_cmp ( + const struct sockaddr* restrict sa1, + const struct sockaddr* restrict sa2 + ) +{ + int retval = 0; + + if (sa1->sa_family != sa2->sa_family) + retval = sa1->sa_family < sa2->sa_family ? -1 : 1; + else { + switch (sa1->sa_family) { + case AF_INET: { + struct sockaddr_in sa1_in, sa2_in; + memcpy (&sa1_in, sa1, sizeof(sa1_in)); + memcpy (&sa2_in, sa2, sizeof(sa2_in)); + if (sa1_in.sin_addr.s_addr != sa2_in.sin_addr.s_addr) + retval = sa1_in.sin_addr.s_addr < sa2_in.sin_addr.s_addr ? -1 : 1; + break; + } + +/* IN6_ARE_ADDR_EQUAL(a,b) only returns true or false */ + case AF_INET6: { + struct sockaddr_in6 sa1_in6, sa2_in6; + memcpy (&sa1_in6, sa1, sizeof(sa1_in6)); + memcpy (&sa2_in6, sa2, sizeof(sa2_in6)); + retval = memcmp (&sa1_in6.sin6_addr, &sa2_in6.sin6_addr, sizeof(struct in6_addr)); + if (0 == retval && sa1_in6.sin6_scope_id != sa2_in6.sin6_scope_id) + retval = sa1_in6.sin6_scope_id < sa2_in6.sin6_scope_id ? -1 : 1; + break; + } + + default: + break; + } + } + return retval; +} + +/* IP header included with data. + * + * If no error occurs, pgm_sockaddr_hdrincl returns zero. Otherwise, a value + * of PGM_SOCKET_ERROR is returned, and a specific error code can be retrieved + * by calling pgm_sock_errno(). + */ + +int +pgm_sockaddr_hdrincl ( + const int s, + const sa_family_t sa_family, + const bool v + ) +{ + int retval = PGM_SOCKET_ERROR; + + switch (sa_family) { + case AF_INET: { +#ifndef _WIN32 +/* Solaris:ip(7P) Mentioned but not detailed. + * + * Linux:ip(7) "A boolean integer flag is zero when it is false, otherwise + * true. If enabled, the user supplies an IP header in front of the user + * data." Mentions only send-side, nothing about receive-side. + * Linux:raw(7) "For receiving the IP header is always included in the packet." + * + * FreeBSD,OS X:IP(4) provided by example "int hincl = 1;" + * + * Stevens: "IP_HDRINCL has datatype int." + */ + const int optval = v ? 1 : 0; +#else + const DWORD optval = v ? 1 : 0; +#endif + retval = setsockopt (s, IPPROTO_IP, IP_HDRINCL, (const char*)&optval, sizeof(optval)); + break; + } + + case AF_INET6: /* method only exists on Win32, just ignore */ + retval = 0; + break; + + default: break; + } + return retval; +} + +/* Return destination IP address. + * + * If no error occurs, pgm_sockaddr_pktinfo returns zero. Otherwise, a value + * of PGM_SOCKET_ERROR is returned, and a specific error code can be retrieved + * by calling pgm_sock_errno(). + */ + +int +pgm_sockaddr_pktinfo ( + const int s, + const sa_family_t sa_family, + const bool v + ) +{ + int retval = PGM_SOCKET_ERROR; +#ifndef _WIN32 +/* Solaris:ip(7P) "The following options take in_pktinfo_t as the parameter" + * Completely different, although ip6(7P) is a little better, "The following + * options are boolean switches controlling the reception of ancillary data" + * + * Linux:ip(7) "A boolean integer flag is zero when it is false, otherwise + * true. The argument is a flag that tells the socket whether the IP_PKTINFO + * message should be passed or not." + * Linux:ipv6(7) Not listed, however IPV6_PKTINFO is with "Argument is a pointer + * to a boolean value in an integer." + * + * Absent from FreeBSD & OS X, suggested replacement IP_RECVDSTADDR. + * OS X:IP6(4) "IPV6_PKTINFO int *" + * + * Stevens: "IP_RECVDSTADDR has datatype int." + */ + const int optval = v ? 1 : 0; +#else + const DWORD optval = v ? 1 : 0; +#endif + + switch (sa_family) { + case AF_INET: +#ifdef IP_RECVDSTADDR + retval = setsockopt (s, IPPROTO_IP, IP_RECVDSTADDR, (const char*)&optval, sizeof(optval)); +#else + retval = setsockopt (s, IPPROTO_IP, IP_PKTINFO, (const char*)&optval, sizeof(optval)); +#endif + break; + + case AF_INET6: +#ifdef IPV6_RECVPKTINFO + retval = setsockopt (s, IPPROTO_IPV6, IPV6_RECVPKTINFO, (const char*)&optval, sizeof(optval)); +#else + retval = setsockopt (s, IPPROTO_IPV6, IPV6_PKTINFO, (const char*)&optval, sizeof(optval)); +#endif + break; + + default: break; + } + return retval; +} + +/* Set IP Router Alert option for all outgoing packets. + * + * If no error occurs, pgm_sockaddr_router_alert returns zero. Otherwise, a + * value of PGM_SOCKET_ERROR is returned, and a specific error code can be + * retrieved by calling pgm_sock_errno(). + */ + +int +pgm_sockaddr_router_alert ( + const int s, + const sa_family_t sa_family, + const bool v + ) +{ + int retval = PGM_SOCKET_ERROR; +#ifdef CONFIG_IP_ROUTER_ALERT +/* Linux:ip(7) "A boolean integer flag is zero when it is false, otherwise + * true. Expects an integer flag." + * Linux:ipv6(7) "Argument is a pointer to an integer." + * + * Sent on special queue to rsvpd on Linux and so best avoided. + */ + const int optval = v ? 1 : 0; + + switch (sa_family) { + case AF_INET: + retval = setsockopt (s, IPPROTO_IP, IP_ROUTER_ALERT, (const char*)&optval, sizeof(optval)); + break; + + case AF_INET6: + retval = setsockopt (s, IPPROTO_IPV6, IPV6_ROUTER_ALERT, (const char*)&optval, sizeof(optval)); + break; + + default: break; + } +#else +# if defined(CONFIG_HAVE_IPOPTION) +/* NB: struct ipoption is not very portable and requires a lot of additional headers */ + const struct ipoption router_alert = { + .ipopt_dst = 0, + .ipopt_list = { PGM_IPOPT_RA, 0x04, 0x00, 0x00 } + }; + const int optlen = v ? sizeof(router_alert) : 0; +# else +/* manually set the IP option */ + const int ipopt_ra = (PGM_IPOPT_RA << 24) | (0x04 << 16); + const int router_alert = htonl (ipopt_ra); + const int optlen = v ? sizeof(router_alert) : 0; +# endif + + switch (sa_family) { + case AF_INET: +/* Linux:ip(7) "The maximum option size for IPv4 is 40 bytes." + */ + retval = setsockopt (s, IPPROTO_IP, IP_OPTIONS, (const char*)&router_alert, optlen); +retval = 0; + break; + + default: break; + } +#endif + return retval; +} + +/* Type-of-service and precedence. + * + * If no error occurs, pgm_sockaddr_tos returns zero. Otherwise, a value of + * PGM_SOCKET_ERROR is returned, and a specific error code can be retrieved by + * calling pgm_sock_errno(). + */ + +int +pgm_sockaddr_tos ( + const int s, + const sa_family_t sa_family, + const int tos + ) +{ + int retval = PGM_SOCKET_ERROR; + + switch (sa_family) { + case AF_INET: { +#ifndef _WIN32 +/* Solaris:ip(7P) "This option takes an integer argument as its input value." + * + * Linux:ip(7) "TOS is a byte." + * + * FreeBSD,OS X:IP(4) provided by example "int tos = IPTOS_LOWDELAY;" + * + * Stevens: "IP_TOS has datatype int." + */ + const int optval = tos; +#else +/* IP_TOS only works on Win32 with system override: + * http://support.microsoft.com/kb/248611 + * TODO: Implement GQoS (IPv4 only), qWAVE QOS is Vista+ only + */ + const DWORD optval = tos; +#endif + retval = setsockopt (s, IPPROTO_IP, IP_TOS, (const char*)&optval, sizeof(optval)); + break; + } + + case AF_INET6: /* TRAFFIC_CLASS not implemented */ + break; + + default: break; + } + return retval; +} + +/* Join multicast group. + * NB: IPV6_JOIN_GROUP == IPV6_ADD_MEMBERSHIP + * + * If no error occurs, pgm_sockaddr_join_group returns zero. Otherwise, a + * value of PGM_SOCKET_ERROR is returned, and a specific error code can be + * retrieved by calling pgm_sock_errno(). + */ + +int +pgm_sockaddr_join_group ( + const int s, + const sa_family_t sa_family, + const struct group_req* gr + ) +{ + int retval = PGM_SOCKET_ERROR; +#ifdef CONFIG_HAVE_MCAST_JOIN +/* Solaris:ip(7P) "The following options take a struct ip_mreq_source as the + * parameter." Presumably with source field zeroed out. + * Solaris:ip6(7P) "Takes a struct group_req as the parameter." + * Different type for each family, however group_req is protocol-independent. + * + * Stevens: "MCAST_JOIN_GROUP has datatype group_req{}." + * + * RFC3678: Argument type struct group_req + */ + const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; + retval = setsockopt (s, recv_level, MCAST_JOIN_GROUP, gr, sizeof(struct group_req)); +#else + switch (sa_family) { + case AF_INET: { +/* Solaris:ip(7P) Just mentions "Join a multicast group." + * No further details provided. + * + * Linux:ip(7) "Argument is an ip_mreqn structure. For compatibility, the old + * ip_mreq structure (present since Linux 1.2) is still supported." + * + * FreeBSD,OS X:IP(4) provided by example "struct ip_mreq mreq;" + * + * Windows can optionally abuse imt_interface to be 0.0.0. + * + * Stevens: "IP_ADD_MEMBERSHIP has datatype ip_mreq{}." + * + * RFC3678: Argument type struct ip_mreq + */ +#ifdef CONFIG_HAVE_IP_MREQN + struct ip_mreqn mreqn; + struct sockaddr_in ifaddr; + memset (&mreqn, 0, sizeof(mreqn)); + mreqn.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gr->gr_group)->sin_addr.s_addr; + if (!pgm_if_indextoaddr (gr->gr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL)) + return -1; + mreqn.imr_address.s_addr = ifaddr.sin_addr.s_addr; + mreqn.imr_ifindex = gr->gr_interface; + retval = setsockopt (s, SOL_IP, IP_ADD_MEMBERSHIP, (const char*)&mreqn, sizeof(mreqn)); +#else + struct ip_mreq mreq; + struct sockaddr_in ifaddr; + memset (&mreq, 0, sizeof(mreq)); + mreq.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gr->gr_group)->sin_addr.s_addr; + if (!pgm_if_indextoaddr (gr->gr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL)) + return -1; + mreq.imr_interface.s_addr = ifaddr.sin_addr.s_addr; + retval = setsockopt (s, SOL_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)); +#endif /* !CONFIG_HAVE_IP_MREQN */ + break; + } + + case AF_INET6: { +/* Solaris:ip6(7P) "Takes a struct ipv6_mreq as the parameter;" + * + * Linux:ipv6(7) "Argument is a pointer to a struct ipv6_mreq structure." + * + * OS X:IP6(4) "IPV6_JOIN_GROUP struct ipv6_mreq *" + * + * Stevens: "IPV6_JOIN_GROUP has datatype ipv6_mreq{}." + */ + struct ipv6_mreq mreq6; + memset (&mreq6, 0, sizeof(mreq6)); + mreq6.ipv6mr_multiaddr = ((const struct sockaddr_in6*)&gr->gr_group)->sin6_addr; + mreq6.ipv6mr_interface = gr->gr_interface; + retval = setsockopt (s, SOL_IPV6, IPV6_ADD_MEMBERSHIP, (const char*)&mreq6, sizeof(mreq6)); + break; + } + + default: break; + } +#endif /* CONFIG_HAVE_MCAST_JOIN */ + return retval; +} + +/* leave a joined group + */ + +int +pgm_sockaddr_leave_group ( + const int s, + const sa_family_t sa_family, + const struct group_req* gr + ) +{ + int retval = PGM_SOCKET_ERROR; +#ifdef CONFIG_HAVE_MCAST_JOIN + const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; + retval = setsockopt (s, recv_level, MCAST_LEAVE_GROUP, gr, sizeof(struct group_req)); +#else + switch (sa_family) { + case AF_INET: { +#ifdef CONFIG_HAVE_IP_MREQN + struct ip_mreqn mreqn; + struct sockaddr_in ifaddr; + memset (&mreqn, 0, sizeof(mreqn)); + mreqn.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gr->gr_group)->sin_addr.s_addr; + if (!pgm_if_indextoaddr (gr->gr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL)) + return -1; + mreqn.imr_address.s_addr = ifaddr.sin_addr.s_addr; + mreqn.imr_ifindex = gr->gr_interface; + retval = setsockopt (s, SOL_IP, IP_DROP_MEMBERSHIP, (const char*)&mreqn, sizeof(mreqn)); +#else + struct ip_mreq mreq; + struct sockaddr_in ifaddr; + memset (&mreq, 0, sizeof(mreq)); + mreq.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gr->gr_group)->sin_addr.s_addr; + if (!pgm_if_indextoaddr (gr->gr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL)) + return -1; + mreq.imr_interface.s_addr = ifaddr.sin_addr.s_addr; + retval = setsockopt (s, SOL_IP, IP_DROP_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)); +#endif /* !CONFIG_HAVE_IP_MREQN */ + break; + } + + case AF_INET6: { + struct ipv6_mreq mreq6; + memset (&mreq6, 0, sizeof(mreq6)); + mreq6.ipv6mr_multiaddr = ((const struct sockaddr_in6*)&gr->gr_group)->sin6_addr; + mreq6.ipv6mr_interface = gr->gr_interface; + retval = setsockopt (s, SOL_IPV6, IPV6_DROP_MEMBERSHIP, (const char*)&mreq6, sizeof(mreq6)); + break; + } + + default: break; + } +#endif /* CONFIG_HAVE_MCAST_JOIN */ + return retval; +} + +/* block either at the NIC or kernel, packets from a particular source + */ + +int +pgm_sockaddr_block_source ( + const int s, + const sa_family_t sa_family, + const struct group_source_req* gsr + ) +{ + int retval = PGM_SOCKET_ERROR; +#ifdef CONFIG_HAVE_MCAST_JOIN + const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; + retval = setsockopt (s, recv_level, MCAST_BLOCK_SOURCE, gsr, sizeof(struct group_source_req)); +#elif defined(IP_BLOCK_SOURCE) + switch (sa_family) { + case AF_INET: { + struct ip_mreq_source mreqs; + struct sockaddr_in ifaddr; + memset (&mreqs, 0, sizeof(mreqs)); + mreqs.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_group)->sin_addr.s_addr; + mreqs.imr_sourceaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_source)->sin_addr.s_addr; + pgm_if_indextoaddr (gsr->gsr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL); + mreqs.imr_interface.s_addr = ifaddr.sin_addr.s_addr; + retval = setsockopt (s, SOL_IP, IP_BLOCK_SOURCE, (const char*)&mreqs, sizeof(mreqs)); + break; + } + + case AF_INET6: +/* No IPv6 API implemented, MCAST_BLOCK_SOURCE should be available instead. + */ + break; + + default: break; + } +#endif /* CONFIG_HAVE_MCAST_JOIN */ + return retval; +} + +/* unblock a blocked multicast source. + */ + +int +pgm_sockaddr_unblock_source ( + const int s, + const sa_family_t sa_family, + const struct group_source_req* gsr + ) +{ + int retval = PGM_SOCKET_ERROR; +#ifdef CONFIG_HAVE_MCAST_JOIN + const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; + retval = setsockopt (s, recv_level, MCAST_UNBLOCK_SOURCE, gsr, sizeof(struct group_source_req)); +#elif defined(IP_UNBLOCK_SOURCE) + switch (sa_family) { + case AF_INET: { + struct ip_mreq_source mreqs; + struct sockaddr_in ifaddr; + memset (&mreqs, 0, sizeof(mreqs)); + mreqs.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_group)->sin_addr.s_addr; + mreqs.imr_sourceaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_source)->sin_addr.s_addr; + pgm_if_indextoaddr (gsr->gsr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL); + mreqs.imr_interface.s_addr = ifaddr.sin_addr.s_addr; + retval = setsockopt (s, SOL_IP, IP_UNBLOCK_SOURCE, (const char*)&mreqs, sizeof(mreqs)); + break; + } + + case AF_INET6: +/* No IPv6 API implemented, MCAST_UNBLOCK_SOURCE should be available instead. + */ + break; + + default: break; + } +#endif /* CONFIG_HAVE_MCAST_JOIN */ + return retval; +} + +/* Join source-specific multicast. + * NB: Silently reverts to ASM if SSM not supported. + * + * If no error occurs, pgm_sockaddr_join_source_group returns zero. + * Otherwise, a value of PGM_SOCKET_ERROR is returned, and a specific error + * code can be retrieved by calling pgm_sock_errno(). + */ + +int +pgm_sockaddr_join_source_group ( + const int s, + const sa_family_t sa_family, + const struct group_source_req* gsr + ) +{ + int retval = PGM_SOCKET_ERROR; +#ifdef CONFIG_HAVE_MCAST_JOIN +/* Solaris:ip(7P) "The following options take a struct ip_mreq_source as the + * parameter." + * Solaris:ip6(7P) "Takes a struct group_source_req as the parameter." + * Different type for each family, however group_source_req is protocol- + * independent. + * + * Stevens: "MCAST_JOIN_SOURCE_GROUP has datatype group_source_req{}." + * + * RFC3678: Argument type struct group_source_req + */ + const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; + retval = setsockopt (s, recv_level, MCAST_JOIN_SOURCE_GROUP, gsr, sizeof(struct group_source_req)); +#elif defined(IP_ADD_SOURCE_MEMBERSHIP) + switch (sa_family) { + case AF_INET: { +/* Solaris:ip(7P) "The following options take a struct ip_mreq as the + * parameter." Incorrect literature wrt RFC. + * + * Linux:ip(7) absent. + * + * OS X:IP(4) absent. + * + * Stevens: "IP_ADD_SOURCE_MEMBERSHIP has datatype ip_mreq_source{}." + * + * RFC3678: Argument type struct ip_mreq_source + */ + struct ip_mreq_source mreqs; + struct sockaddr_in ifaddr; + memset (&mreqs, 0, sizeof(mreqs)); + mreqs.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_group)->sin_addr.s_addr; + mreqs.imr_sourceaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_source)->sin_addr.s_addr; + pgm_if_indextoaddr (gsr->gsr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL); + mreqs.imr_interface.s_addr = ifaddr.sin_addr.s_addr; + retval = setsockopt (s, SOL_IP, IP_ADD_SOURCE_MEMBERSHIP, (const char*)&mreqs, sizeof(mreqs)); + break; + } + + case AF_INET6: +/* No IPv6 API implemented, MCAST_JOIN_SOURCE_GROUP should be available instead. + */ + retval = pgm_sockaddr_join_group (s, sa_family, (const struct group_req*)gsr); + break; + + default: break; + } +#else + retval = pgm_sockaddr_join_group (s, sa_family, (const struct group_req*)gsr); +#endif /* CONFIG_HAVE_MCAST_JOIN */ + return retval; +} + +/* drop a SSM source + */ + +int +pgm_sockaddr_leave_source_group ( + const int s, + const sa_family_t sa_family, + const struct group_source_req* gsr + ) +{ + int retval = PGM_SOCKET_ERROR; +#ifdef CONFIG_HAVE_MCAST_JOIN + const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; + retval = setsockopt (s, recv_level, MCAST_LEAVE_SOURCE_GROUP, gsr, sizeof(struct group_source_req)); +#elif defined(IP_ADD_SOURCE_MEMBERSHIP) + switch (sa_family) { + case AF_INET: { + struct ip_mreq_source mreqs; + struct sockaddr_in ifaddr; + memset (&mreqs, 0, sizeof(mreqs)); + mreqs.imr_multiaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_group)->sin_addr.s_addr; + mreqs.imr_sourceaddr.s_addr = ((const struct sockaddr_in*)&gsr->gsr_source)->sin_addr.s_addr; + pgm_if_indextoaddr (gsr->gsr_interface, AF_INET, 0, (struct sockaddr*)&ifaddr, NULL); + mreqs.imr_interface.s_addr = ifaddr.sin_addr.s_addr; + retval = setsockopt (s, SOL_IP, IP_DROP_SOURCE_MEMBERSHIP, (const char*)&mreqs, sizeof(mreqs)); + break; + } + + case AF_INET6: +/* No IPv6 API implemented, MCAST_LEAVE_SOURCE_GROUP should be available instead. + */ + retval = pgm_sockaddr_leave_group (s, sa_family, (const struct group_req*)gsr); + break; + + default: break; + } +#else + retval = pgm_sockaddr_leave_group (s, sa_family, (const struct group_req*)gsr); +#endif /* CONFIG_HAVE_MCAST_JOIN */ + return retval; +} + +#if defined(MCAST_MSFILTER) || defined(SIOCSMSFILTER) +/* Batch block and unblock sources. + */ + +int +pgm_sockaddr_msfilter ( + const int s, + const sa_family_t sa_family, + const struct group_filter* gf_list + ) +{ + int retval = PGM_SOCKET_ERROR; +#ifdef MCAST_MSFILTER + const int recv_level = (AF_INET == sa_family) ? SOL_IP : SOL_IPV6; + const socklen_t len = GROUP_FILTER_SIZE(gf_list->gf_numsrc); + retval = setsockopt (s, recv_level, MCAST_MSFILTER, (const char*)gf_list, len); +#elif defined(SIOCSMSFILTER) + retval = ioctl (s, SIOCSMSFILTER, (const char*)gf_list); +#endif + return retval; +} +#endif /* MCAST_MSFILTER || SIOCSMSFILTER */ + +/* Specify outgoing interface. + * + * If no error occurs, pgm_sockaddr_multicast_if returns zero. Otherwise, a + * value of PGM_SOCKET_ERROR is returned, and a specific error code can be + * retrieved by calling pgm_sock_errno(). + */ + +int +pgm_sockaddr_multicast_if ( + int s, + const struct sockaddr* address, + unsigned ifindex + ) +{ + int retval = PGM_SOCKET_ERROR; + + switch (address->sa_family) { + case AF_INET: { +/* Solaris:ip(7P) "This option takes a struct in_addr as an argument, and it + * selects that interface for outgoing IP multicast packets." + * + * Linux:ip(7) "Argument is an ip_mreqn or ip_mreq structure similar to + * IP_ADD_MEMBERSHIP." + * + * OS X:IP(4) provided by example "struct in_addr addr;" + * + * Stevens: "IP_MULTICAST_IF has datatype struct in_addr{}." + */ + struct sockaddr_in s4; + memcpy (&s4, address, sizeof(struct sockaddr_in)); + retval = setsockopt (s, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&s4.sin_addr, sizeof(s4.sin_addr)); + break; + } + + case AF_INET6: { +#ifndef _WIN32 +/* Solaris:ip6(7P) "This option takes an integer as an argument; the integer + * is the interface index of the selected interface." + * + * Linux:ipv6(7) "The argument is a pointer to an interface index (see + * netdevice(7)) in an integer." + * + * OS X:IP6(4) "IPV6_MULTICAST_IF u_int *" + * + * Stevens: "IPV6_MULTICAST_IF has datatype u_int." + */ + const unsigned int optval = ifindex; +#else + const DWORD optval = ifindex; +#endif + retval = setsockopt (s, IPPROTO_IPV6, IPV6_MULTICAST_IF, (const char*)&optval, sizeof(optval)); + break; + } + + default: break; + } + return retval; +} + +/* Specify multicast loop, other applications on the same host may receive + * outgoing packets. This does not affect unicast packets such as NAKs. + * + * If no error occurs, pgm_sockaddr_multicast_loop returns zero. Otherwise, a + * value of PGM_SOCKET_ERROR is returned, and a specific error code can be + * retrieved by calling pgm_sock_errno(). + */ + +int +pgm_sockaddr_multicast_loop ( + const int s, + const sa_family_t sa_family, + const bool v + ) +{ + int retval = PGM_SOCKET_ERROR; + + switch (sa_family) { + case AF_INET: { +#ifndef _WIN32 +/* Solaris:ip(7P) "Setting the unsigned character argument to 0 causes the + * opposite behavior, meaning that when multiple zones are present, the + * datagrams are delivered to all zones except the sending zone." + * + * Linux:ip(7) "Sets or reads a boolean integer argument" + * + * OS X:IP(4) provided by example "u_char loop;" + * + * Stevens: "IP_MULTICAST_LOOP has datatype u_char." + */ + const unsigned char optval = v ? 1 : 0; +#else + const DWORD optval = v ? 1 : 0; +#endif + retval = setsockopt (s, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&optval, sizeof(optval)); + break; + } + + case AF_INET6: { +#ifndef _WIN32 +/* Solaris:ip(7P) "Setting the unsigned character argument to 0 will cause the opposite behavior." + * + * Linux:ipv6(7) "Argument is a pointer to boolean." + * + * OS X:IP6(7) "IPV6_MULTICAST_LOOP u_int *" + * + * Stevens: "IPV6_MULTICAST_LOOP has datatype u_int." + */ + const unsigned int optval = v ? 1 : 0; +#else + const DWORD optval = v ? 1 : 0; +#endif + retval = setsockopt (s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const char*)&optval, sizeof(optval)); + break; + } + + default: break; + } + return retval; +} + +/* Specify TTL or outgoing hop limit. + * NB: Only affects multicast hops, unicast hop-limit is not changed. + * + * If no error occurs, pgm_sockaddr_multicast_hops returns zero. Otherwise, a + * value of PGM_SOCKET_ERROR is returned, and a specific error code can be + * retrieved by calling pgm_sock_errno(). + */ + +int +pgm_sockaddr_multicast_hops ( + const int s, + const sa_family_t sa_family, + const unsigned hops + ) +{ + int retval = PGM_SOCKET_ERROR; + + switch (sa_family) { + case AF_INET: { +#ifndef _WIN32 +/* Solaris:ip(7P) "This option takes an unsigned character as an argument." + * + * Linux:ip(7) "Argument is an integer." + * + * OS X:IP(4) provided by example for SOCK_DGRAM with IP_TTL: "int ttl = 60;", + * or for SOCK_RAW & SOCK_DGRAM with IP_MULTICAST_TTL: "u_char ttl;" + * + * Stevens: "IP_MULTICAST_TTL has datatype u_char." + */ + const unsigned char optval = hops; +#else + const DWORD optval = hops; +#endif + retval = setsockopt (s, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&optval, sizeof(optval)); + break; + } + + case AF_INET6: { +#ifndef _WIN32 +/* Solaris:ip6(7P) "This option takes an integer as an argument." + * + * Linux:ipv6(7) "Argument is a pointer to an integer." + * + * OS X:IP6(7) "IPV6_MULTICAST_HOPS int *" + * + * Stevens: "IPV6_MULTICAST_HOPS has datatype int." + */ + const int optval = hops; +#else + const DWORD optval = hops; +#endif + retval = setsockopt (s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&optval, sizeof(optval)); + break; + } + + default: break; + } + return retval; +} + +void +pgm_sockaddr_nonblocking ( + const int s, + const bool v + ) +{ +#ifndef _WIN32 + int flags = fcntl (s, F_GETFL); + if (!v) flags &= ~O_NONBLOCK; + else flags |= O_NONBLOCK; + fcntl (s, F_SETFL, flags); +#else + u_long mode = v; + ioctlsocket (s, FIONBIO, &mode); +#endif +} + +/* Note that are sockaddr structure is not passed these functions inherently + * cannot support IPv6 Zone Indices and hence are rather limited for the + * link-local scope. + */ +const char* +pgm_inet_ntop ( + int af, + const void* restrict src, + char* restrict dst, + socklen_t size + ) +{ + pgm_assert (AF_INET == af || AF_INET6 == af); + pgm_assert (NULL != src); + pgm_assert (NULL != dst); + pgm_assert (size > 0); + + switch (af) { + case AF_INET: + { + struct sockaddr_in sin; + memset (&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr = *(const struct in_addr*)src; + getnameinfo ((struct sockaddr*)&sin, sizeof(sin), + dst, size, + NULL, 0, + NI_NUMERICHOST); + return dst; + } + case AF_INET6: + { + struct sockaddr_in6 sin6; + memset (&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = *(const struct in6_addr*)src; + getnameinfo ((struct sockaddr*)&sin6, sizeof(sin6), + dst, size, + NULL, 0, + NI_NUMERICHOST); + return dst; + } + } + + errno = EAFNOSUPPORT; + return NULL; +} + +int +pgm_inet_pton ( + int af, + const char* restrict src, + void* restrict dst + ) +{ + pgm_assert (AF_INET == af || AF_INET6 == af); + pgm_assert (NULL != src); + pgm_assert (NULL != dst); + + struct addrinfo hints = { + .ai_family = af, + .ai_socktype = SOCK_STREAM, /* not really */ + .ai_protocol = IPPROTO_TCP, /* not really */ + .ai_flags = AI_NUMERICHOST + }, *result = NULL; + + const int e = getaddrinfo (src, NULL, &hints, &result); + if (0 != e) { + return 0; /* error */ + } + + pgm_assert (NULL != result->ai_addr); + pgm_assert (0 != result->ai_addrlen); + + switch (result->ai_addr->sa_family) { + case AF_INET: { + struct sockaddr_in s4; + memcpy (&s4, result->ai_addr, sizeof(s4)); + memcpy (dst, &s4.sin_addr.s_addr, sizeof(struct in_addr)); + break; + } + + case AF_INET6: { + struct sockaddr_in6 s6; + memcpy (&s6, result->ai_addr, sizeof(s6)); + memcpy (dst, &s6.sin6_addr, sizeof(struct in6_addr)); + break; + } + + default: + pgm_assert_not_reached(); + break; + } + + freeaddrinfo (result); + return 1; /* success */ +} + +int +pgm_nla_to_sockaddr ( + const void* restrict nla, + struct sockaddr* restrict sa + ) +{ + uint16_t nla_family; + int retval = 0; + + memcpy (&nla_family, nla, sizeof(nla_family)); + sa->sa_family = ntohs (nla_family); + switch (sa->sa_family) { + case AFI_IP: + sa->sa_family = AF_INET; + ((struct sockaddr_in*)sa)->sin_addr.s_addr = ((const struct in_addr*)((const char*)nla + sizeof(uint32_t)))->s_addr; + break; + + case AFI_IP6: + sa->sa_family = AF_INET6; + memcpy (&((struct sockaddr_in6*)sa)->sin6_addr, (const struct in6_addr*)((const char*)nla + sizeof(uint32_t)), sizeof(struct in6_addr)); + break; + + default: + retval = -EINVAL; + break; + } + + return retval; +} + +int +pgm_sockaddr_to_nla ( + const struct sockaddr* restrict sa, + void* restrict nla + ) +{ + int retval = 0; + + *(uint16_t*)nla = sa->sa_family; + *(uint16_t*)((char*)nla + sizeof(uint16_t)) = 0; /* reserved 16bit space */ + switch (sa->sa_family) { + case AF_INET: + *(uint16_t*)nla = htons (AFI_IP); + ((struct in_addr*)((char*)nla + sizeof(uint32_t)))->s_addr = ((const struct sockaddr_in*)sa)->sin_addr.s_addr; + break; + + case AF_INET6: + *(uint16_t*)nla = htons (AFI_IP6); + memcpy ((struct in6_addr*)((char*)nla + sizeof(uint32_t)), &((const struct sockaddr_in6*)sa)->sin6_addr, sizeof(struct in6_addr)); + break; + + default: + retval = -EINVAL; + break; + } + + return retval; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/sockaddr.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/sockaddr.c.c89.patch new file mode 100644 index 0000000..96fa367 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/sockaddr.c.c89.patch @@ -0,0 +1,75 @@ +--- sockaddr.c 2010-08-04 17:08:05.000000000 +0800 ++++ sockaddr.c89 2010-08-05 13:19:20.000000000 +0800 +@@ -145,12 +145,13 @@ + struct sockaddr* restrict dst /* will error on wrong size */ + ) + { +- struct addrinfo hints = { +- .ai_family = AF_UNSPEC, +- .ai_socktype = SOCK_STREAM, /* not really */ +- .ai_protocol = IPPROTO_TCP, /* not really */ +- .ai_flags = AI_NUMERICHOST +- }, *result = NULL; ++ struct addrinfo hints, *result; ++ memset (&hints, 0, sizeof(hints)); ++ hints.ai_family = AF_UNSPEC; ++ hints.ai_socktype = SOCK_STREAM; /* not really */ ++ hints.ai_protocol = IPPROTO_TCP; /* not really */ ++ hints.ai_flags = AI_NUMERICHOST; ++ { + const int status = getaddrinfo (src, NULL, &hints, &result); + if (PGM_LIKELY(0 == status)) { + memcpy (dst, result->ai_addr, result->ai_addrlen); +@@ -158,6 +159,7 @@ + return 1; + } + return 0; ++ } + } + + /* returns tri-state value: 1 if sa is multicast, 0 if sa is not multicast, -1 on error +@@ -830,7 +832,13 @@ + const socklen_t len = GROUP_FILTER_SIZE(gf_list->gf_numsrc); + retval = setsockopt (s, recv_level, MCAST_MSFILTER, (const char*)gf_list, len); + #elif defined(SIOCSMSFILTER) ++# ifdef _WIN32 ++# pragma warning( disable : 4090 ) ++ retval = ioctlsocket (s, SIOCSMSFILTER, (const char*)gf_list); ++# pragma warning( default : 4090 ) ++# else + retval = ioctl (s, SIOCSMSFILTER, (const char*)gf_list); ++# endif + #endif + return retval; + } +@@ -1092,13 +1100,15 @@ + pgm_assert (NULL != src); + pgm_assert (NULL != dst); + +- struct addrinfo hints = { +- .ai_family = af, +- .ai_socktype = SOCK_STREAM, /* not really */ +- .ai_protocol = IPPROTO_TCP, /* not really */ +- .ai_flags = AI_NUMERICHOST +- }, *result = NULL; ++ { ++ struct addrinfo hints, *result; ++ memset (&hints, 0, sizeof(hints)); ++ hints.ai_family = af; ++ hints.ai_socktype = SOCK_STREAM; /* not really */ ++ hints.ai_protocol = IPPROTO_TCP; /* not really */ ++ hints.ai_flags = AI_NUMERICHOST; + ++ { + const int e = getaddrinfo (src, NULL, &hints, &result); + if (0 != e) { + return 0; /* error */ +@@ -1129,6 +1139,8 @@ + + freeaddrinfo (result); + return 1; /* success */ ++ } ++ } + } + + int diff --git a/3rdparty/openpgm-svn-r1135/pgm/socket.c b/3rdparty/openpgm-svn-r1135/pgm/socket.c new file mode 100644 index 0000000..f838f18 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/socket.c @@ -0,0 +1,2150 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM socket: manage incoming & outgoing sockets with ambient SPMs, + * transmit & receive windows. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#ifdef CONFIG_HAVE_POLL +# include +#endif +#ifdef CONFIG_HAVE_EPOLL +# include +#endif +#include +#include +#include +#include +#include +#include +#include + + +//#define SOCK_DEBUG +//#define SOCK_SPM_DEBUG + + +/* global locals */ +pgm_rwlock_t pgm_sock_list_lock; /* list of all sockets for admin interfaces */ +pgm_slist_t* pgm_sock_list = NULL; + + +static const char* pgm_family_string (const int) PGM_GNUC_CONST; +static const char* pgm_sock_type_string (const int) PGM_GNUC_CONST; +static const char* pgm_protocol_string (const int) PGM_GNUC_CONST; + + +size_t +pgm_pkt_offset ( + bool can_fragment, + sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + const size_t data_size = sizeof(struct pgm_header) + sizeof(struct pgm_data); + size_t pkt_size = data_size; + if (can_fragment || (0 != pgmcc_family)) + pkt_size += sizeof(struct pgm_opt_length) + sizeof(struct pgm_opt_header); + if (can_fragment) + pkt_size += sizeof(struct pgm_opt_fragment); + if (AF_INET == pgmcc_family) + pkt_size += sizeof(struct pgm_opt_pgmcc_data); + else if (AF_INET6 == pgmcc_family) + pkt_size += sizeof(struct pgm_opt6_pgmcc_data); + return pkt_size; +} + +/* destroy a pgm_sock object and contents, if last sock also destroy + * associated event loop + * + * outstanding locks: + * 1) pgm_sock_t::lock + * 2) pgm_sock_t::receiver_mutex + * 3) pgm_sock_t::source_mutex + * 4) pgm_sock_t::txw_spinlock + * 5) pgm_sock_t::timer_mutex + * + * If application calls a function on the sock after destroy() it is a + * programmer error: segv likely to occur on unlock. + * + * on success, returns TRUE, on failure returns FALSE. + */ + +bool +pgm_close ( + pgm_sock_t* sock, + bool flush + ) +{ + pgm_return_val_if_fail (sock != NULL, FALSE); + if (!pgm_rwlock_reader_trylock (&sock->lock)) + pgm_return_val_if_reached (FALSE); + pgm_return_val_if_fail (!sock->is_destroyed, FALSE); + pgm_debug ("pgm_sock_destroy (sock:%p flush:%s)", + (const void*)sock, + flush ? "TRUE":"FALSE"); +/* flag existing calls */ + sock->is_destroyed = TRUE; +/* cancel running blocking operations */ + if (PGM_INVALID_SOCKET != sock->recv_sock) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Closing receive socket.")); + pgm_closesocket (sock->recv_sock); + sock->recv_sock = PGM_INVALID_SOCKET; + } + if (PGM_INVALID_SOCKET != sock->send_sock) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Closing send socket.")); + pgm_closesocket (sock->send_sock); + sock->send_sock = PGM_INVALID_SOCKET; + } + pgm_rwlock_reader_unlock (&sock->lock); + pgm_debug ("blocking on destroy lock ..."); + pgm_rwlock_writer_lock (&sock->lock); + + pgm_debug ("removing sock from inventory."); + pgm_rwlock_writer_lock (&pgm_sock_list_lock); + pgm_sock_list = pgm_slist_remove (pgm_sock_list, sock); + pgm_rwlock_writer_unlock (&pgm_sock_list_lock); + +/* flush source side by sending heartbeat SPMs */ + if (sock->can_send_data && + sock->is_connected && + flush) + { + pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Flushing PGM source with session finish option broadcast SPMs.")); + if (!pgm_send_spm (sock, PGM_OPT_FIN) || + !pgm_send_spm (sock, PGM_OPT_FIN) || + !pgm_send_spm (sock, PGM_OPT_FIN)) + { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Failed to send flushing SPMs.")); + } + } + + if (sock->peers_hashtable) { + pgm_debug ("destroying peer lookup table."); + pgm_hashtable_destroy (sock->peers_hashtable); + sock->peers_hashtable = NULL; + } + if (sock->peers_list) { + pgm_debug ("destroying peer list."); + do { + pgm_list_t* next = sock->peers_list->next; + pgm_peer_unref ((pgm_peer_t*)sock->peers_list->data); + + sock->peers_list = next; + } while (sock->peers_list); + } + + if (sock->window) { + pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Destroying transmit window.")); + pgm_txw_shutdown (sock->window); + sock->window = NULL; + } + pgm_trace (PGM_LOG_ROLE_RATE_CONTROL,_("Destroying rate control.")); + pgm_rate_destroy (&sock->rate_control); + if (PGM_INVALID_SOCKET != sock->send_with_router_alert_sock) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Closing send with router alert socket.")); + pgm_closesocket (sock->send_with_router_alert_sock); + sock->send_with_router_alert_sock = PGM_INVALID_SOCKET; + } + if (sock->spm_heartbeat_interval) { + pgm_debug ("freeing SPM heartbeat interval data."); + pgm_free (sock->spm_heartbeat_interval); + sock->spm_heartbeat_interval = NULL; + } + if (sock->rx_buffer) { + pgm_debug ("freeing receive buffer."); + pgm_free_skb (sock->rx_buffer); + sock->rx_buffer = NULL; + } + pgm_debug ("destroying notification channels."); + if (sock->can_send_data) { + if (sock->use_pgmcc) { + pgm_notify_destroy (&sock->ack_notify); + } + pgm_notify_destroy (&sock->rdata_notify); + } + pgm_notify_destroy (&sock->pending_notify); + pgm_debug ("freeing sock locks."); + pgm_rwlock_free (&sock->peers_lock); + pgm_spinlock_free (&sock->txw_spinlock); + pgm_mutex_free (&sock->send_mutex); + pgm_mutex_free (&sock->timer_mutex); + pgm_mutex_free (&sock->source_mutex); + pgm_mutex_free (&sock->receiver_mutex); + pgm_rwlock_writer_unlock (&sock->lock); + pgm_rwlock_free (&sock->lock); + pgm_debug ("freeing sock data."); + pgm_free (sock); + pgm_debug ("finished."); + return TRUE; +} + +/* Create a pgm_sock object. Create sockets that require superuser + * priviledges. If interface ports are specified then UDP encapsulation will + * be used instead of raw protocol. + * + * If send == recv only two sockets need to be created iff ip headers are not + * required (IPv6). + * + * All receiver addresses must be the same family. + * interface and multiaddr must be the same family. + * family cannot be AF_UNSPEC! + * + * returns TRUE on success, or FALSE on error and sets error appropriately. + */ + +#if ( AF_INET != PF_INET ) || ( AF_INET6 != PF_INET6 ) +#error AF_INET and PF_INET are different values, the bananas are jumping in their pyjamas! +#endif + +bool +pgm_socket ( + pgm_sock_t** restrict sock, + const sa_family_t family, /* communications domain */ + const int pgm_sock_type, + const int protocol, + pgm_error_t** restrict error + ) +{ + pgm_sock_t* new_sock; + + pgm_return_val_if_fail (NULL != sock, FALSE); + pgm_return_val_if_fail (AF_INET == family || AF_INET6 == family, FALSE); + pgm_return_val_if_fail (SOCK_SEQPACKET == pgm_sock_type, FALSE); + pgm_return_val_if_fail (IPPROTO_UDP == protocol || IPPROTO_PGM == protocol, FALSE); + + pgm_debug ("socket (sock:%p family:%s sock-type:%s protocol:%s error:%p)", + (const void*)sock, pgm_family_string(family), pgm_sock_type_string(pgm_sock_type), pgm_protocol_string(protocol), (const void*)error); + + new_sock = pgm_new0 (pgm_sock_t, 1); + new_sock->family = family; + new_sock->socket_type = pgm_sock_type; + new_sock->protocol = protocol; + new_sock->can_send_data = TRUE; + new_sock->can_send_nak = TRUE; + new_sock->can_recv_data = TRUE; + new_sock->dport = DEFAULT_DATA_DESTINATION_PORT; + new_sock->tsi.sport = DEFAULT_DATA_SOURCE_PORT; + new_sock->adv_mode = 0; /* advance with time */ + +/* PGMCC */ + new_sock->acker_nla.ss_family = family; + +/* source-side */ + pgm_mutex_init (&new_sock->source_mutex); +/* transmit window */ + pgm_spinlock_init (&new_sock->txw_spinlock); +/* send socket */ + pgm_mutex_init (&new_sock->send_mutex); +/* next timer & spm expiration */ + pgm_mutex_init (&new_sock->timer_mutex); +/* receiver-side */ + pgm_mutex_init (&new_sock->receiver_mutex); +/* peer hash map & list lock */ + pgm_rwlock_init (&new_sock->peers_lock); +/* destroy lock */ + pgm_rwlock_init (&new_sock->lock); + +/* open sockets to implement PGM */ + int socket_type; + if (IPPROTO_UDP == new_sock->protocol) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Opening UDP encapsulated sockets.")); + socket_type = SOCK_DGRAM; + new_sock->udp_encap_ucast_port = DEFAULT_UDP_ENCAP_UCAST_PORT; + new_sock->udp_encap_mcast_port = DEFAULT_UDP_ENCAP_MCAST_PORT; + } else { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Opening raw sockets.")); + socket_type = SOCK_RAW; + } + + if ((new_sock->recv_sock = socket (new_sock->family, + socket_type, + new_sock->protocol)) == PGM_INVALID_SOCKET) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + _("Creating receive socket: %s"), + pgm_sock_strerror (save_errno)); +#ifndef _WIN32 + if (EPERM == save_errno) { + pgm_error (_("PGM protocol requires CAP_NET_RAW capability, e.g. sudo execcap 'cap_net_raw=ep'")); + } +#endif + goto err_destroy; + } + + if ((new_sock->send_sock = socket (new_sock->family, + socket_type, + new_sock->protocol)) == PGM_INVALID_SOCKET) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + _("Creating send socket: %s"), + pgm_sock_strerror (save_errno)); + goto err_destroy; + } + + if ((new_sock->send_with_router_alert_sock = socket (new_sock->family, + socket_type, + new_sock->protocol)) == PGM_INVALID_SOCKET) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + _("Creating IP Router Alert (RFC 2113) send socket: %s"), + pgm_sock_strerror (save_errno)); + goto err_destroy; + } + + if (IPPROTO_UDP == new_sock->protocol) + { +/* Stevens: "SO_REUSEADDR has datatype int." + */ + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Set socket sharing.")); + const int v = 1; + if (PGM_SOCKET_ERROR == setsockopt (new_sock->recv_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&v, sizeof(v)) || + PGM_SOCKET_ERROR == setsockopt (new_sock->send_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&v, sizeof(v)) || + PGM_SOCKET_ERROR == setsockopt (new_sock->send_with_router_alert_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&v, sizeof(v))) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + _("Enabling reuse of socket local address: %s"), + pgm_sock_strerror (save_errno)); + goto err_destroy; + } + +/* request extra packet information to determine destination address on each packet */ +#ifndef CONFIG_TARGET_WINE + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Request socket packet-info.")); + const sa_family_t recv_family = new_sock->family; + if (PGM_SOCKET_ERROR == pgm_sockaddr_pktinfo (new_sock->recv_sock, recv_family, TRUE)) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + _("Enabling receipt of ancillary information per incoming packet: %s"), + pgm_sock_strerror (save_errno)); + goto err_destroy; + } +#endif + } + else + { + const sa_family_t recv_family = new_sock->family; + if (AF_INET == recv_family) + { +/* include IP header only for incoming data, only works for IPv4 */ + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Request IP headers.")); + if (PGM_SOCKET_ERROR == pgm_sockaddr_hdrincl (new_sock->recv_sock, recv_family, TRUE)) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + _("Enabling IP header in front of user data: %s"), + pgm_sock_strerror (save_errno)); + goto err_destroy; + } + } + else + { + pgm_assert (AF_INET6 == recv_family); + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Request socket packet-info.")); + if (PGM_SOCKET_ERROR == pgm_sockaddr_pktinfo (new_sock->recv_sock, recv_family, TRUE)) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + _("Enabling receipt of control message per incoming datagram: %s"), + pgm_sock_strerror (save_errno)); + goto err_destroy; + } + } + } + + *sock = new_sock; + + pgm_rwlock_writer_lock (&pgm_sock_list_lock); + pgm_sock_list = pgm_slist_append (pgm_sock_list, *sock); + pgm_rwlock_writer_unlock (&pgm_sock_list_lock); + pgm_debug ("PGM socket successfully created."); + return TRUE; + +err_destroy: + if (PGM_INVALID_SOCKET != new_sock->recv_sock) { + if (PGM_SOCKET_ERROR == pgm_closesocket (new_sock->recv_sock)) { + const int save_errno = pgm_sock_errno(); + pgm_warn (_("Close on receive socket failed: %s"), + pgm_sock_strerror (save_errno)); + } + new_sock->recv_sock = PGM_INVALID_SOCKET; + } + if (PGM_INVALID_SOCKET != new_sock->send_sock) { + if (PGM_SOCKET_ERROR == pgm_closesocket (new_sock->send_sock)) { + const int save_errno = pgm_sock_errno(); + pgm_warn (_("Close on send socket failed: %s"), + pgm_sock_strerror (save_errno)); + } + new_sock->send_sock = PGM_INVALID_SOCKET; + } + if (PGM_INVALID_SOCKET != new_sock->send_with_router_alert_sock) { + if (PGM_SOCKET_ERROR == pgm_closesocket (new_sock->send_with_router_alert_sock)) { + const int save_errno = pgm_sock_errno(); + pgm_warn (_("Close on IP Router Alert (RFC 2113) send socket failed: %s"), + pgm_sock_strerror (save_errno)); + } + new_sock->send_with_router_alert_sock = PGM_INVALID_SOCKET; + } + pgm_free (new_sock); + return FALSE; +} + +bool +pgm_getsockopt ( + pgm_sock_t* const restrict sock, + const int level, /* always IPPROTO_PGM */ + const int optname, + void* restrict optval, + socklen_t* restrict optlen /* required */ + ) +{ + bool status = FALSE; + pgm_return_val_if_fail (sock != NULL, status); + pgm_return_val_if_fail (level == IPPROTO_PGM, status); + pgm_return_val_if_fail (optval != NULL, status); + pgm_return_val_if_fail (optlen != NULL, status); + if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) + pgm_return_val_if_reached (status); + if (PGM_UNLIKELY(sock->is_destroyed)) { + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + switch (optname) { +/* maximum transmission packet size */ + case PGM_MTU: + if (PGM_UNLIKELY(*optlen != sizeof (int))) + break; + *(int*restrict)optval = sock->max_tpdu; + status = TRUE; + break; + +/* maximum segment size for unfragmented APDU */ + case PGM_MSSS: + if (PGM_UNLIKELY(*optlen != sizeof (int))) + break; + *(int*restrict)optval = sock->max_tsdu; + status = TRUE; + break; + +/* maximum segment size for fragmented APDU */ + case PGM_MSS: + if (PGM_UNLIKELY(*optlen != sizeof (int))) + break; + *(int*restrict)optval = sock->max_tsdu_fragment; + status = TRUE; + break; + +/* maximum payload size for an APDU */ + case PGM_PDU: + if (PGM_UNLIKELY(*optlen != sizeof (int))) + break; + *(int*restrict)optval = sock->max_apdu; + status = TRUE; + break; + + case PGM_ABORT_ON_RESET: + if (PGM_UNLIKELY(*optlen != sizeof (int))) + break; + *(int*restrict)optval = sock->is_abort_on_reset ? 1 : 0; + status = TRUE; + break; + +/* send socket */ + case PGM_SEND_SOCK: + if (PGM_UNLIKELY(!sock->is_connected)) + break; + if (PGM_UNLIKELY(*optlen != sizeof (int))) + break; + *(int*)optval = sock->send_sock; + status = TRUE; + break; + +/* receive socket */ + case PGM_RECV_SOCK: + if (PGM_UNLIKELY(!sock->is_connected)) + break; + if (PGM_UNLIKELY(*optlen != sizeof (int))) + break; + *(int*)optval = sock->recv_sock; + status = TRUE; + break; + +/* repair socket */ + case PGM_REPAIR_SOCK: + if (PGM_UNLIKELY(!sock->is_connected)) + break; + if (PGM_UNLIKELY(*optlen != sizeof (int))) + break; + *(int*)optval = pgm_notify_get_fd (&sock->rdata_notify); + status = TRUE; + break; + +/* pending socket */ + case PGM_PENDING_SOCK: + if (PGM_UNLIKELY(!sock->is_connected)) + break; + if (PGM_UNLIKELY(*optlen != sizeof (int))) + break; + *(int*)optval = pgm_notify_get_fd (&sock->pending_notify); + status = TRUE; + break; + +/* ACK or congestion socket */ + case PGM_ACK_SOCK: + if (PGM_UNLIKELY(!sock->is_connected)) + break; + if (PGM_UNLIKELY(*optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(!sock->use_pgmcc)) + break; + *(int*)optval = pgm_notify_get_fd (&sock->ack_notify); + status = TRUE; + break; + + +/* timeout for pending timer */ + case PGM_TIME_REMAIN: + if (PGM_UNLIKELY(!sock->is_connected)) + break; + if (PGM_UNLIKELY(*optlen != sizeof (struct timeval))) + break; + { + struct timeval* tv = optval; + const pgm_time_t usecs = pgm_timer_expiration (sock); + tv->tv_sec = usecs / 1000000UL; + tv->tv_usec = usecs % 1000000UL; + } + status = TRUE; + break; + +/* timeout for blocking sends */ + case PGM_RATE_REMAIN: + if (PGM_UNLIKELY(!sock->is_connected)) + break; + if (PGM_UNLIKELY(*optlen != sizeof (struct timeval))) + break; + { + struct timeval* tv = optval; + const pgm_time_t usecs = pgm_rate_remaining (&sock->rate_control, sock->blocklen); + tv->tv_sec = usecs / 1000000UL; + tv->tv_usec = usecs % 1000000UL; + } + status = TRUE; + break; + + + } + pgm_rwlock_reader_unlock (&sock->lock); + return status; +} + +bool +pgm_setsockopt ( + pgm_sock_t* const sock, + const int level, /* IPPROTO_PGM or SOL_SOCKET */ + const int optname, + const void* optval, + const socklen_t optlen + ) +{ + bool status = FALSE; + pgm_return_val_if_fail (sock != NULL, status); + pgm_return_val_if_fail (IPPROTO_PGM == level || SOL_SOCKET == level, status); + if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) + pgm_return_val_if_reached (status); + if (PGM_UNLIKELY(sock->is_connected || sock->is_destroyed)) { + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + + switch (level) { + case SOL_SOCKET: + switch (optname) { + +/* 0 < wmem < wmem_max (user) + * + * operating system and sysctl dependent maximum, minimum on Linux 256 (doubled). + */ + case SO_SNDBUF: + if (PGM_SOCKET_ERROR == setsockopt (sock->send_sock, SOL_SOCKET, SO_SNDBUF, (const char*)optval, optlen) || + PGM_SOCKET_ERROR == setsockopt (sock->send_with_router_alert_sock, SOL_SOCKET, SO_SNDBUF, (const char*)optval, optlen)) + break; + status = TRUE; + break; + +/* 0 < rmem < rmem_max (user) + * + * minimum on Linux is 2048 (doubled). + */ + case SO_RCVBUF: + if (PGM_SOCKET_ERROR == setsockopt (sock->recv_sock, SOL_SOCKET, SO_RCVBUF, (const char*)optval, optlen)) + break; + status = TRUE; + break; + + default: + break; + } + break; + + case IPPROTO_PGM: + switch (optname) { + +/* RFC2113 IP Router Alert + */ + case PGM_IP_ROUTER_ALERT: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + { + const bool v = (0 != *(const int*)optval); + if (PGM_SOCKET_ERROR == pgm_sockaddr_router_alert (sock->send_with_router_alert_sock, sock->family, v)) + break; + } + status = TRUE; + break; + +/* IPv4: 68 <= tpdu < 65536 (RFC 2765) + * IPv6: 1280 <= tpdu < 65536 (RFC 2460) + */ + case PGM_MTU: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval < (int)(sizeof(struct pgm_ip) + sizeof(struct pgm_header)))) + break; + if (PGM_UNLIKELY(*(const int*)optval > UINT16_MAX)) + break; + sock->max_tpdu = *(const int*)optval; + status = TRUE; + break; + +/* 1 = enable multicast loopback. + * 0 = default, to disable. + */ + case PGM_MULTICAST_LOOP: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + { + const bool v = (0 != *(const int*)optval); +#ifndef _WIN32 /* loop on send */ + if (PGM_SOCKET_ERROR == pgm_sockaddr_multicast_loop (sock->send_sock, sock->family, v) || + PGM_SOCKET_ERROR == pgm_sockaddr_multicast_loop (sock->send_with_router_alert_sock, sock->family, v)) + break; +#else /* loop on receive */ + if (PGM_SOCKET_ERROR == pgm_sockaddr_multicast_loop (sock->recv_sock, sock->family, v)) + break; +#endif + } + status = TRUE; + break; + +/* 0 < hops < 256, hops == -1 use kernel default (ignored). + */ + case PGM_MULTICAST_HOPS: +#ifndef CONFIG_TARGET_WINE + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + if (PGM_UNLIKELY(*(const int*)optval > UINT8_MAX)) + break; + { + sock->hops = *(const int*)optval; + if (PGM_SOCKET_ERROR == pgm_sockaddr_multicast_hops (sock->send_sock, sock->family, sock->hops) || + PGM_SOCKET_ERROR == pgm_sockaddr_multicast_hops (sock->send_with_router_alert_sock, sock->family, sock->hops)) + break; + } +#endif + status = TRUE; + break; + +/* IP Type of Service (ToS) or RFC 3246, differentiated services (DSCP) + */ + case PGM_TOS: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_SOCKET_ERROR == pgm_sockaddr_tos (sock->send_sock, sock->family, *(const int*)optval) || + PGM_SOCKET_ERROR == pgm_sockaddr_tos (sock->send_with_router_alert_sock, sock->family, *(const int*)optval)) + { + pgm_warn (_("ToS/DSCP setting requires CAP_NET_ADMIN or ADMIN capability.")); + break; + } + status = TRUE; + break; + +/* periodic ambient broadcast SPM interval in milliseconds. + */ + case PGM_AMBIENT_SPM: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + sock->spm_ambient_interval = *(const int*)optval; + status = TRUE; + break; + +/* sequence of heartbeat broadcast SPMS to flush out original + */ + case PGM_HEARTBEAT_SPM: + if (PGM_UNLIKELY(0 != optlen % sizeof (int))) + break; + { + sock->spm_heartbeat_len = optlen / sizeof (int); + sock->spm_heartbeat_interval = pgm_new (unsigned, sock->spm_heartbeat_len + 1); + sock->spm_heartbeat_interval[0] = 0; + for (unsigned i = 0; i < sock->spm_heartbeat_len; i++) + sock->spm_heartbeat_interval[i + 1] = ((const int*)optval)[i]; + } + status = TRUE; + break; + +/* size of transmit window in sequence numbers. + * 0 < txw_sqns < one less than half sequence space + */ + case PGM_TXW_SQNS: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + if (PGM_UNLIKELY(*(const int*)optval >= (int)((UINT32_MAX/2)-1))) + break; + sock->txw_sqns = *(const int*)optval; + status = TRUE; + break; + +/* size of transmit window in seconds. + * 0 < secs < ( txw_sqns / txw_max_rte ) + */ + case PGM_TXW_SECS: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + sock->txw_secs = *(const int*)optval; + status = TRUE; + break; + +/* maximum transmit rate. + * 0 < txw_max_rte < interface capacity + * 10mb : 1250000 + * 100mb : 12500000 + * 1gb : 125000000 + */ + case PGM_TXW_MAX_RTE: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + sock->txw_max_rte = *(const int*)optval; + status = TRUE; + break; + +/* timeout for peers. + * 0 < 2 * spm_ambient_interval <= peer_expiry + */ + case PGM_PEER_EXPIRY: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + sock->peer_expiry = *(const int*)optval; + status = TRUE; + break; + +/* maximum back off range for listening for multicast SPMR. + * 0 < spmr_expiry < spm_ambient_interval + */ + case PGM_SPMR_EXPIRY: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + sock->spmr_expiry = *(const int*)optval; + status = TRUE; + break; + +/* size of receive window in sequence numbers. + * 0 < rxw_sqns < one less than half sequence space + */ + case PGM_RXW_SQNS: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + if (PGM_UNLIKELY(*(const int*)optval >= (int)((UINT32_MAX/2)-1))) + break; + sock->rxw_sqns = *(const int*)optval; + status = TRUE; + break; + +/* size of receive window in seconds. + * 0 < secs < ( rxw_sqns / rxw_max_rte ) + */ + case PGM_RXW_SECS: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + sock->rxw_secs = *(const int*)optval; + status = TRUE; + break; + +/* maximum receive rate, for determining window size with txw_secs. + * 0 < rxw_max_rte < interface capacity + */ + case PGM_RXW_MAX_RTE: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + sock->rxw_max_rte = *(const int*)optval; + status = TRUE; + break; + +/* maximum NAK back-off value nak_rb_ivl in milliseconds. + * 0 < nak_rb_ivl <= nak_bo_ivl + */ + case PGM_NAK_BO_IVL: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + sock->nak_bo_ivl = *(const int*)optval; + status = TRUE; + break; + +/* repeat interval prior to re-sending a NAK, in milliseconds. + */ + case PGM_NAK_RPT_IVL: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + sock->nak_rpt_ivl = *(const int*)optval; + status = TRUE; + break; + +/* interval waiting for repair data, in milliseconds. + */ + case PGM_NAK_RDATA_IVL: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + sock->nak_rdata_ivl = *(const int*)optval; + status = TRUE; + break; + +/* limit for data. + * 0 < nak_data_retries < 256 + */ + case PGM_NAK_DATA_RETRIES: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + if (PGM_UNLIKELY(*(const int*)optval > UINT8_MAX)) + break; + sock->nak_data_retries = *(const int*)optval; + status = TRUE; + break; + +/* limit for NAK confirms. + * 0 < nak_ncf_retries < 256 + */ + case PGM_NAK_NCF_RETRIES: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + if (PGM_UNLIKELY(*(const int*)optval > UINT8_MAX)) + break; + sock->nak_ncf_retries = *(const int*)optval; + status = TRUE; + break; + +/* Enable FEC for this sock, specifically Reed Solmon encoding RS(n,k), common + * setting is RS(255, 223). + * + * inputs: + * + * n = FEC Block size = [k+1, 255] + * k = original data packets == transmission group size = [2, 4, 8, 16, 32, 64, 128] + * m = symbol size = 8 bits + * + * outputs: + * + * h = 2t = n - k = parity packets + * + * when h > k parity packets can be lost. + */ + case PGM_USE_FEC: + if (PGM_UNLIKELY(optlen != sizeof (struct pgm_fecinfo_t))) + break; + { + const struct pgm_fecinfo_t* fecinfo = optval; + if (PGM_UNLIKELY(0 != (fecinfo->group_size & (fecinfo->group_size - 1)))) + break; + if (PGM_UNLIKELY(fecinfo->group_size < 2 || fecinfo->group_size > 128)) + break; + if (PGM_UNLIKELY(fecinfo->group_size > fecinfo->block_size)) + break; + const uint8_t parity_packets = fecinfo->block_size - fecinfo->group_size; +/* technically could re-send previous packets */ + if (PGM_UNLIKELY(fecinfo->proactive_packets > parity_packets)) + break; +/* check validity of parameters */ + if (PGM_UNLIKELY(fecinfo->group_size > 223 && ((parity_packets * 223.0) / fecinfo->group_size) < 1.0)) + { + pgm_error (_("k/h ratio too low to generate parity data.")); + break; + } + sock->use_proactive_parity = (fecinfo->proactive_packets > 0); + sock->use_ondemand_parity = fecinfo->ondemand_parity_enabled; + sock->use_var_pktlen = fecinfo->var_pktlen_enabled; + sock->rs_n = fecinfo->block_size; + sock->rs_k = fecinfo->group_size; + sock->rs_proactive_h = fecinfo->proactive_packets; + } + status = TRUE; + break; + +/* congestion reporting */ + case PGM_USE_CR: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + if (PGM_UNLIKELY(*(const int*)optval <= 0)) + break; + sock->crqst_ivl = *(const int*)optval; + sock->use_cr = (sock->crqst_ivl > 0); + status = TRUE; + break; + +/* congestion control */ + case PGM_USE_PGMCC: + if (PGM_UNLIKELY(optlen != sizeof (struct pgm_pgmccinfo_t))) + break; + { + const struct pgm_pgmccinfo_t* pgmccinfo = optval; + sock->ack_bo_ivl = pgmccinfo->ack_bo_ivl; + sock->ack_c = pgmccinfo->ack_c; + sock->ack_c_p = pgmccinfo->ack_c_p; + sock->use_pgmcc = (sock->ack_c > 0); + } + status = TRUE; + break; + +/* declare socket only for sending, discard any incoming SPM, ODATA, + * RDATA, etc, packets. + */ + case PGM_SEND_ONLY: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + sock->can_recv_data = (0 == *(const int*)optval); + status = TRUE; + break; + +/* declare socket only for receiving, no transmit window will be created + * and no SPM broadcasts sent. + */ + case PGM_RECV_ONLY: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + sock->can_send_data = (0 == *(const int*)optval); + status = TRUE; + break; + +/* passive receiving socket, i.e. no back channel to source + */ + case PGM_PASSIVE: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + sock->can_send_nak = (0 == *(const int*)optval); + status = TRUE; + break; + +/* on unrecoverable data loss stop socket from further transmission and + * receiving. + */ + case PGM_ABORT_ON_RESET: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + sock->is_abort_on_reset = (0 != *(const int*)optval); + status = TRUE; + break; + +/* default non-blocking operation on send and receive sockets. + */ + case PGM_NOBLOCK: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + sock->is_nonblocking = (0 != *(const int*)optval); + pgm_sockaddr_nonblocking (sock->recv_sock, sock->is_nonblocking); + pgm_sockaddr_nonblocking (sock->send_sock, sock->is_nonblocking); + pgm_sockaddr_nonblocking (sock->send_with_router_alert_sock, sock->is_nonblocking); + status = TRUE; + break; + +/* sending group, singular. note that the address is only stored and used + * later in sendto() calls, this routine only considers the interface. + */ + case PGM_SEND_GROUP: + if (PGM_UNLIKELY(optlen != sizeof(struct group_req))) + break; + memcpy (&sock->send_gsr, optval, sizeof(struct group_req)); + if (PGM_UNLIKELY(sock->family != sock->send_gsr.gsr_group.ss_family)) + break; +/* multicast group for later usage with sendto() */ + if (sock->udp_encap_mcast_port) + ((struct sockaddr_in*)&sock->send_gsr.gsr_group)->sin_port = htons (sock->udp_encap_mcast_port); +/* interface */ + if ((PGM_SOCKET_ERROR == pgm_sockaddr_multicast_if (sock->send_sock, + (const struct sockaddr*)&sock->send_addr, + sock->send_gsr.gsr_interface)) || + (PGM_SOCKET_ERROR == pgm_sockaddr_multicast_if (sock->send_with_router_alert_sock, + (const struct sockaddr*)&sock->send_addr, + sock->send_gsr.gsr_interface))) + { + break; + } + else if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((const struct sockaddr*)&sock->send_addr, addr, sizeof(addr)); + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Multicast send interface set to %s index %u"), + addr, + (unsigned)sock->send_gsr.gsr_interface); + } + status = TRUE; + break; + +/* for any-source applications (ASM), join a new group + */ + case PGM_JOIN_GROUP: + if (PGM_UNLIKELY(optlen != sizeof(struct group_req))) + break; + if (PGM_UNLIKELY(sock->recv_gsr_len >= IP_MAX_MEMBERSHIPS)) + break; + { + const struct group_req* gr = optval; +/* verify not duplicate group/interface pairing */ + for (unsigned i = 0; i < sock->recv_gsr_len; i++) + { + if (pgm_sockaddr_cmp ((const struct sockaddr*)&gr->gr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0 && + pgm_sockaddr_cmp ((const struct sockaddr*)&gr->gr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_source) == 0 && + (gr->gr_interface == sock->recv_gsr[i].gsr_interface || + 0 == sock->recv_gsr[i].gsr_interface )) + { +#ifdef SOCKET_DEBUG + char s[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((const struct sockaddr*)&gr->gr_group, s, sizeof(s)); + if (sock->recv_gsr[i].gsr_interface) { + pgm_warn(_("Socket has already joined group %s on interface %u"), s, gr->gr_interface); + } else { + pgm_warn(_("Socket has already joined group %s on all interfaces."), s); + } +#endif + break; + } + } + if (PGM_UNLIKELY(sock->family != gr->gr_group.ss_family)) + break; + sock->recv_gsr[sock->recv_gsr_len].gsr_interface = gr->gr_interface; + memcpy (&sock->recv_gsr[sock->recv_gsr_len].gsr_group, &gr->gr_group, pgm_sockaddr_len ((const struct sockaddr*)&gr->gr_group)); + if (sock->udp_encap_mcast_port) + ((struct sockaddr_in*)&sock->recv_gsr[sock->recv_gsr_len].gsr_group)->sin_port = htons (sock->udp_encap_mcast_port); + memcpy (&sock->recv_gsr[sock->recv_gsr_len].gsr_source, &gr->gr_group, pgm_sockaddr_len ((const struct sockaddr*)&gr->gr_group)); + if (PGM_SOCKET_ERROR == pgm_sockaddr_join_group (sock->recv_sock, sock->family, gr)) + break; + else if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((const struct sockaddr*)&gr->gr_group, addr, sizeof(addr)); + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Join multicast group %s on interface index %u"), + addr, + (unsigned)gr->gr_interface); + } + sock->recv_gsr_len++; + } + status = TRUE; + break; + +/* for any-source applications (ASM), leave a joined group. + */ + case PGM_LEAVE_GROUP: + if (PGM_UNLIKELY(optlen != sizeof(struct group_req))) + break; + if (PGM_UNLIKELY(0 == sock->recv_gsr_len)) + break; + { + const struct group_req* gr = optval; + for (unsigned i = 0; i < sock->recv_gsr_len;) + { + if ((pgm_sockaddr_cmp ((const struct sockaddr*)&gr->gr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0) && +/* drop all matching receiver entries */ + (gr->gr_interface == 0 || +/* drop all sources with matching interface */ + gr->gr_interface == sock->recv_gsr[i].gsr_interface) ) + { + sock->recv_gsr_len--; + if (i < (IP_MAX_MEMBERSHIPS - 1)) + { + memmove (&sock->recv_gsr[i], &sock->recv_gsr[i+1], (sock->recv_gsr_len - i) * sizeof(struct group_source_req)); + continue; + } + } + i++; + } + if (PGM_UNLIKELY(sock->family != gr->gr_group.ss_family)) + break; + if (PGM_SOCKET_ERROR == pgm_sockaddr_leave_group (sock->recv_sock, sock->family, gr)) + break; + else if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((const struct sockaddr*)&gr->gr_group, addr, sizeof(addr)); + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Leave multicast group %s on interface index %u"), + addr, + (unsigned)gr->gr_interface); + } + } + status = TRUE; + break; + +/* for any-source applications (ASM), turn off a given source + */ + case PGM_BLOCK_SOURCE: + if (PGM_UNLIKELY(optlen != sizeof(struct group_source_req))) + break; + { + const struct group_source_req* gsr = optval; + if (PGM_UNLIKELY(sock->family != gsr->gsr_group.ss_family)) + break; + if (PGM_SOCKET_ERROR == pgm_sockaddr_block_source (sock->recv_sock, sock->family, gsr)) + break; + } + status = TRUE; + break; + +/* for any-source applications (ASM), re-allow a blocked source + */ + case PGM_UNBLOCK_SOURCE: + if (PGM_UNLIKELY(optlen != sizeof(struct group_source_req))) + break; + { + const struct group_source_req* gsr = optval; + if (PGM_UNLIKELY(sock->family != gsr->gsr_group.ss_family)) + break; + if (PGM_SOCKET_ERROR == pgm_sockaddr_unblock_source (sock->recv_sock, sock->family, gsr)) + break; + } + status = TRUE; + break; + +/* for controlled-source applications (SSM), join each group/source pair. + * + * SSM joins are allowed on top of ASM in order to merge a remote source onto the local segment. + */ + case PGM_JOIN_SOURCE_GROUP: + if (PGM_UNLIKELY(optlen != sizeof(struct group_source_req))) + break; + if (PGM_UNLIKELY(sock->recv_gsr_len >= IP_MAX_MEMBERSHIPS)) + break; + { + const struct group_source_req* gsr = optval; +/* verify if existing group/interface pairing */ + for (unsigned i = 0; i < sock->recv_gsr_len; i++) + { + if (pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0 && + (gsr->gsr_interface == sock->recv_gsr[i].gsr_interface || + 0 == sock->recv_gsr[i].gsr_interface )) + { + if (pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_source, (struct sockaddr*)&sock->recv_gsr[i].gsr_source) == 0) + { +#ifdef SOCKET_DEBUG + char s1[INET6_ADDRSTRLEN], s2[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((const struct sockaddr*)&gsr->gsr_group, s1, sizeof(s1)); + pgm_sockaddr_ntop ((const struct sockaddr*)&gsr->gsr_source, s2, sizeof(s2)); + if (sock->recv_gsr[i].gsr_interface) { + pgm_warn(_("Socket has already joined group %s from source %s on interface %d"), + s1, s2, (unsigned)gsr->gsr_interface); + } else { + pgm_warn(_("Socket has already joined group %s from source %s on all interfaces"), + s1, s2); + } +#endif + break; + } + break; + } + } + if (PGM_UNLIKELY(sock->family != gsr->gsr_group.ss_family)) + break; + if (PGM_UNLIKELY(sock->family != gsr->gsr_source.ss_family)) + break; + if (PGM_SOCKET_ERROR == pgm_sockaddr_join_source_group (sock->recv_sock, sock->family, gsr)) + break; + memcpy (&sock->recv_gsr[sock->recv_gsr_len], gsr, sizeof(struct group_source_req)); + sock->recv_gsr_len++; + } + status = TRUE; + break; + +/* for controlled-source applications (SSM), leave each group/source pair + */ + case PGM_LEAVE_SOURCE_GROUP: + if (PGM_UNLIKELY(optlen != sizeof(struct group_source_req))) + break; + if (PGM_UNLIKELY(0 == sock->recv_gsr_len)) + break; + { + const struct group_source_req* gsr = optval; +/* verify if existing group/interface pairing */ + for (unsigned i = 0; i < sock->recv_gsr_len; i++) + { + if (pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0 && + pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_source, (struct sockaddr*)&sock->recv_gsr[i].gsr_source) == 0 && + gsr->gsr_interface == sock->recv_gsr[i].gsr_interface) + { + sock->recv_gsr_len--; + if (i < (IP_MAX_MEMBERSHIPS - 1)) + { + memmove (&sock->recv_gsr[i], &sock->recv_gsr[i+1], (sock->recv_gsr_len - i) * sizeof(struct group_source_req)); + break; + } + } + } + if (PGM_UNLIKELY(sock->family != gsr->gsr_group.ss_family)) + break; + if (PGM_UNLIKELY(sock->family != gsr->gsr_source.ss_family)) + break; + if (PGM_SOCKET_ERROR == pgm_sockaddr_leave_source_group (sock->recv_sock, sock->family, gsr)) + break; + } + status = TRUE; + break; + +/* batch block and unblock sources */ + case PGM_MSFILTER: +#if defined(MCAST_MSFILTER) || defined(SIOCSMSFILTER) + if (PGM_UNLIKELY(optlen < (socklen_t)sizeof(struct group_filter))) + break; + { + const struct group_filter* gf_list = optval; + if ((socklen_t)GROUP_FILTER_SIZE( gf_list->gf_numsrc ) != optlen) + break; + if (PGM_UNLIKELY(sock->family != gf_list->gf_group.ss_family)) + break; +/* check only first */ + if (PGM_UNLIKELY(sock->family != gf_list->gf_slist[0].ss_family)) + break; + if (PGM_SOCKET_ERROR == pgm_sockaddr_msfilter (sock->recv_sock, sock->family, gf_list)) + break; + } + status = TRUE; +#endif + break; + +/* UDP encapsulation ports */ + case PGM_UDP_ENCAP_UCAST_PORT: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + sock->udp_encap_ucast_port = *(const int*)optval; + status = TRUE; + break; + + case PGM_UDP_ENCAP_MCAST_PORT: + if (PGM_UNLIKELY(optlen != sizeof (int))) + break; + sock->udp_encap_mcast_port = *(const int*)optval; + status = TRUE; + break; + + default: + break; + } + break; + + default: + break; + } + + pgm_rwlock_reader_unlock (&sock->lock); + return status; +} + +bool +pgm_bind ( + pgm_sock_t* restrict sock, + const struct pgm_sockaddr_t*const restrict sockaddr, + const socklen_t sockaddrlen, + pgm_error_t** restrict error + ) +{ + struct pgm_interface_req_t null_req; + memset (&null_req, 0, sizeof(null_req)); + return pgm_bind3 (sock, sockaddr, sockaddrlen, &null_req, sizeof(null_req), &null_req, sizeof(null_req), error); +} + +/* bind the sockets to the link layer to start receiving data. + * + * returns TRUE on success, or FALSE on error and sets error appropriately, + */ + +bool +pgm_bind3 ( + pgm_sock_t* restrict sock, + const struct pgm_sockaddr_t*const restrict sockaddr, + const socklen_t sockaddrlen, + const struct pgm_interface_req_t*const send_req, /* only use gr_interface and gr_group::sin6_scope */ + const socklen_t send_req_len, + const struct pgm_interface_req_t*const recv_req, + const socklen_t recv_req_len, + pgm_error_t** restrict error /* maybe NULL */ + ) +{ + pgm_return_val_if_fail (NULL != sock, FALSE); + pgm_return_val_if_fail (NULL != sockaddr, FALSE); + pgm_return_val_if_fail (0 != sockaddrlen, FALSE); + if (sockaddr->sa_addr.sport) pgm_return_val_if_fail (sockaddr->sa_addr.sport != sockaddr->sa_port, FALSE); + pgm_return_val_if_fail (NULL != send_req, FALSE); + pgm_return_val_if_fail (sizeof(struct pgm_interface_req_t) == send_req_len, FALSE); + pgm_return_val_if_fail (NULL != recv_req, FALSE); + pgm_return_val_if_fail (sizeof(struct pgm_interface_req_t) == recv_req_len, FALSE); + + if (!pgm_rwlock_writer_trylock (&sock->lock)) + pgm_return_val_if_reached (FALSE); + if (sock->is_bound || + sock->is_destroyed) + { + pgm_rwlock_writer_unlock (&sock->lock); + pgm_return_val_if_reached (FALSE); + } + +/* sanity checks on state */ + if (sock->max_tpdu < (sizeof(struct pgm_ip) + sizeof(struct pgm_header))) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("Invalid maximum TPDU size.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (sock->can_send_data) { + if (PGM_UNLIKELY(0 == sock->spm_ambient_interval)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("SPM ambient interval not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (PGM_UNLIKELY(0 == sock->spm_heartbeat_len)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("SPM heartbeat interval not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (PGM_UNLIKELY(0 == sock->txw_sqns && 0 == sock->txw_secs)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("TXW_SQNS not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (PGM_UNLIKELY(0 == sock->txw_sqns && 0 == sock->txw_max_rte)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("TXW_MAX_RTE not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + } + if (sock->can_recv_data) { + if (PGM_UNLIKELY(0 == sock->rxw_sqns && 0 == sock->rxw_secs)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("RXW_SQNS not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (PGM_UNLIKELY(0 == sock->rxw_sqns && 0 == sock->rxw_max_rte)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("RXW_MAX_RTE not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (PGM_UNLIKELY(0 == sock->peer_expiry)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("Peer timeout not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (PGM_UNLIKELY(0 == sock->spmr_expiry)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("SPM-Request timeout not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (PGM_UNLIKELY(0 == sock->nak_bo_ivl)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("NAK_BO_IVL not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (PGM_UNLIKELY(0 == sock->nak_rpt_ivl)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("NAK_RPT_IVL not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (PGM_UNLIKELY(0 == sock->nak_rdata_ivl)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("NAK_RDATA_IVL not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (PGM_UNLIKELY(0 == sock->nak_data_retries)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("NAK_DATA_RETRIES not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (PGM_UNLIKELY(0 == sock->nak_ncf_retries)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + PGM_ERROR_FAILED, + _("NAK_NCF_RETRIES not configured.")); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + } + + pgm_debug ("bind3 (sock:%p sockaddr:%p sockaddrlen:%u send-req:%p send-req-len:%u recv-req:%p recv-req-len:%u error:%p)", + (const void*)sock, (const void*)sockaddr, (unsigned)sockaddrlen, (const void*)send_req, (unsigned)send_req_len, (const void*)recv_req, (unsigned)recv_req_len, (const void*)error); + + memcpy (&sock->tsi, &sockaddr->sa_addr, sizeof(pgm_tsi_t)); + sock->dport = htons (sockaddr->sa_port); + if (sock->tsi.sport) { + sock->tsi.sport = htons (sock->tsi.sport); + } else { + do { + sock->tsi.sport = htons (pgm_random_int_range (0, UINT16_MAX)); + } while (sock->tsi.sport == sock->dport); + } + +/* pseudo-random number generator for back-off intervals */ + pgm_rand_create (&sock->rand_); + +/* PGM Children support of POLLs requires 32-bit random node identifier RAND_NODE_ID */ + if (sock->can_recv_data) { + sock->rand_node_id = pgm_rand_int (&sock->rand_); + } + + if (sock->can_send_data) + { +/* Windows notify call will raise an assertion on error, only Unix versions will return + * a valid error. + */ + if (sock->use_pgmcc && + 0 != pgm_notify_init (&sock->ack_notify)) + { + const int save_errno = errno; + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_errno (save_errno), + _("Creating ACK notification channel: %s"), + strerror (save_errno)); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (0 != pgm_notify_init (&sock->rdata_notify)) + { + const int save_errno = errno; + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_errno (save_errno), + _("Creating RDATA notification channel: %s"), + strerror (save_errno)); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + } + if (0 != pgm_notify_init (&sock->pending_notify)) + { + const int save_errno = errno; + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_errno (save_errno), + _("Creating waiting peer notification channel: %s"), + strerror (save_errno)); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + +/* determine IP header size for rate regulation engine & stats */ + sock->iphdr_len = (AF_INET == sock->family) ? sizeof(struct pgm_ip) : sizeof(struct pgm_ip6_hdr); + pgm_trace (PGM_LOG_ROLE_NETWORK,"Assuming IP header size of %zu bytes", sock->iphdr_len); + + if (sock->udp_encap_ucast_port) { + const size_t udphdr_len = sizeof(struct pgm_udphdr); + pgm_trace (PGM_LOG_ROLE_NETWORK,"Assuming UDP header size of %zu bytes", udphdr_len); + sock->iphdr_len += udphdr_len; + } + + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + sock->max_tsdu = sock->max_tpdu - sock->iphdr_len - pgm_pkt_offset (FALSE, pgmcc_family); + sock->max_tsdu_fragment = sock->max_tpdu - sock->iphdr_len - pgm_pkt_offset (TRUE, pgmcc_family); + const unsigned max_fragments = sock->txw_sqns ? MIN( PGM_MAX_FRAGMENTS, sock->txw_sqns ) : PGM_MAX_FRAGMENTS; + sock->max_apdu = MIN( PGM_MAX_APDU, max_fragments * sock->max_tsdu_fragment ); + + if (sock->can_send_data) + { + pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Create transmit window.")); + sock->window = sock->txw_sqns ? + pgm_txw_create (&sock->tsi, + 0, /* MAX_TPDU */ + sock->txw_sqns, /* TXW_SQNS */ + 0, /* TXW_SECS */ + 0, /* TXW_MAX_RTE */ + sock->use_ondemand_parity || sock->use_proactive_parity, + sock->rs_n, + sock->rs_k) : + pgm_txw_create (&sock->tsi, + sock->max_tpdu, /* MAX_TPDU */ + 0, /* TXW_SQNS */ + sock->txw_secs, /* TXW_SECS */ + sock->txw_max_rte, /* TXW_MAX_RTE */ + sock->use_ondemand_parity || sock->use_proactive_parity, + sock->rs_n, + sock->rs_k); + pgm_assert (NULL != sock->window); + } + +/* create peer list */ + if (sock->can_recv_data) { + sock->peers_hashtable = pgm_hashtable_new (pgm_tsi_hash, pgm_tsi_equal); + pgm_assert (NULL != sock->peers_hashtable); + } + +/* Bind UDP sockets to interfaces, note multicast on a bound interface is + * fruity on some platforms. Roughly, binding to INADDR_ANY provides all + * data, binding to the multicast group provides only multicast traffic, + * and binding to the interface address provides only unicast traffic. + * + * Multicast routing, IGMP & MLD require a link local address, for IPv4 + * this is provided through MULTICAST_IF and IPv6 through bind, and these + * may be overridden by per packet scopes. + * + * After binding, default interfaces (0.0.0.0) are resolved. + */ +/* TODO: different ports requires a new bound socket */ + + union { + struct sockaddr sa; + struct sockaddr_in s4; + struct sockaddr_in6 s6; + struct sockaddr_storage ss; + } recv_addr, recv_addr2, send_addr, send_with_router_alert_addr; + +#ifdef CONFIG_BIND_INADDR_ANY +/* force default interface for bind-only, source address is still valid for multicast membership. + * effectively same as running getaddrinfo(hints = {ai_flags = AI_PASSIVE}) + */ + if (AF_INET == sock->family) { + memset (&recv_addr.s4, 0, sizeof(struct sockaddr_in)); + recv_addr.s4.sin_family = AF_INET; + recv_addr.s4.sin_addr.s_addr = INADDR_ANY; + } else { + memset (&recv_addr.s6, 0, sizeof(struct sockaddr_in6)); + recv_addr.s6.sin6_family = AF_INET6; + recv_addr.s6.sin6_addr = in6addr_any; + } + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Binding receive socket to INADDR_ANY")); +#else + if (!pgm_if_indextoaddr (recv_req->ir_interface, + sock->family, + recv_req->ir_scope_id, + &recv_addr.sa, + error)) + { + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + else if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) + { + if (AF_INET6 == sock_family) + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Binding receive socket to interface index %u scope %u"), + recv_req->ir_interface, + recv_req->ir_scope_id); + else + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Binding receive socket to interface index %u"), + recv_req->ir_interface); + } + +#endif /* CONFIG_BIND_INADDR_ANY */ + + memcpy (&recv_addr2.sa, &recv_addr.sa, pgm_sockaddr_len (&recv_addr.sa)); + +/* UDP port */ + ((struct sockaddr_in*)&recv_addr)->sin_port = htons (sock->udp_encap_mcast_port); + + if (PGM_SOCKET_ERROR == bind (sock->recv_sock, + &recv_addr.sa, + pgm_sockaddr_len (&recv_addr.sa))) + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&recv_addr, addr, sizeof(addr)); + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + _("Binding receive socket to address %s: %s"), + addr, + pgm_sock_strerror (save_errno)); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + + if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) + { + char s[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&recv_addr, s, sizeof(s)); + pgm_debug ("bind succeeded on recv_gsr[0] interface %s", s); + } + +/* keep a copy of the original address source to re-use for router alert bind */ + memset (&send_addr, 0, sizeof(send_addr)); + + if (!pgm_if_indextoaddr (send_req->ir_interface, + sock->family, + send_req->ir_scope_id, + (struct sockaddr*)&send_addr, + error)) + { + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + else if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) + { + if (AF_INET6 == sock->family) + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Binding send socket to interface index %u scope %u"), + send_req->ir_interface, + send_req->ir_scope_id); + else + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Binding send socket to interface index %u"), + send_req->ir_interface); + } + + memcpy (&send_with_router_alert_addr, &send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)); + if (PGM_SOCKET_ERROR == bind (sock->send_sock, + (struct sockaddr*)&send_addr, + pgm_sockaddr_len ((struct sockaddr*)&send_addr))) + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&send_addr, addr, sizeof(addr)); + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + _("Binding send socket to address %s: %s"), + addr, + pgm_sock_strerror (save_errno)); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + +/* resolve bound address if 0.0.0.0 */ + if (AF_INET == send_addr.ss.ss_family) + { + if ((INADDR_ANY == ((struct sockaddr_in*)&send_addr)->sin_addr.s_addr) && + !pgm_if_getnodeaddr (AF_INET, (struct sockaddr*)&send_addr, sizeof(send_addr), error)) + { + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + } + else if ((memcmp (&in6addr_any, &((struct sockaddr_in6*)&send_addr)->sin6_addr, sizeof(in6addr_any)) == 0) && + !pgm_if_getnodeaddr (AF_INET6, (struct sockaddr*)&send_addr, sizeof(send_addr), error)) + { + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + + if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) + { + char s[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&send_addr, s, sizeof(s)); + pgm_debug ("bind succeeded on send_gsr interface %s", s); + } + + if (PGM_SOCKET_ERROR == bind (sock->send_with_router_alert_sock, + (struct sockaddr*)&send_with_router_alert_addr, + pgm_sockaddr_len((struct sockaddr*)&send_with_router_alert_addr))) + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&send_with_router_alert_addr, addr, sizeof(addr)); + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + _("Binding IP Router Alert (RFC 2113) send socket to address %s: %s"), + addr, + pgm_sock_strerror (save_errno)); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + + if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) + { + char s[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&send_with_router_alert_addr, s, sizeof(s)); + pgm_debug ("bind (router alert) succeeded on send_gsr interface %s", s); + } + +/* save send side address for broadcasting as source nla */ + memcpy (&sock->send_addr, &send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)); + +/* rx to nak processor notify channel */ + if (sock->can_send_data) + { +/* setup rate control */ + if (sock->txw_max_rte) + { + pgm_trace (PGM_LOG_ROLE_RATE_CONTROL,_("Setting rate regulation to %zd bytes per second."), + sock->txw_max_rte); + + pgm_rate_create (&sock->rate_control, sock->txw_max_rte, sock->iphdr_len, sock->max_tpdu); + sock->is_controlled_spm = TRUE; /* must always be set */ + sock->is_controlled_odata = TRUE; + sock->is_controlled_rdata = TRUE; + } + else + { + sock->is_controlled_spm = FALSE; + sock->is_controlled_odata = FALSE; + sock->is_controlled_rdata = FALSE; + } + } + +/* allocate first incoming packet buffer */ + sock->rx_buffer = pgm_alloc_skb (sock->max_tpdu); + +/* bind complete */ + sock->is_bound = TRUE; + +/* cleanup */ + pgm_rwlock_writer_unlock (&sock->lock); + pgm_debug ("PGM socket successfully bound."); + return TRUE; +} + +bool +pgm_connect ( + pgm_sock_t* restrict sock, + pgm_error_t** restrict error /* maybe NULL */ + ) +{ + pgm_return_val_if_fail (sock != NULL, FALSE); + pgm_return_val_if_fail (sock->recv_gsr_len > 0, FALSE); +#ifdef CONFIG_TARGET_WINE + pgm_return_val_if_fail (sock->recv_gsr_len == 1, FALSE); +#endif + for (unsigned i = 0; i < sock->recv_gsr_len; i++) + { + pgm_return_val_if_fail (sock->recv_gsr[i].gsr_group.ss_family == sock->recv_gsr[0].gsr_group.ss_family, FALSE); + pgm_return_val_if_fail (sock->recv_gsr[i].gsr_group.ss_family == sock->recv_gsr[i].gsr_source.ss_family, FALSE); + } + pgm_return_val_if_fail (sock->send_gsr.gsr_group.ss_family == sock->recv_gsr[0].gsr_group.ss_family, FALSE); +/* shutdown */ + if (PGM_UNLIKELY(!pgm_rwlock_writer_trylock (&sock->lock))) + pgm_return_val_if_reached (FALSE); +/* state */ + if (PGM_UNLIKELY(sock->is_connected || !sock->is_bound || sock->is_destroyed)) { + pgm_rwlock_writer_unlock (&sock->lock); + pgm_return_val_if_reached (FALSE); + } + + pgm_debug ("connect (sock:%p error:%p)", + (const void*)sock, (const void*)error); + +/* rx to nak processor notify channel */ + if (sock->can_send_data) + { +/* announce new sock by sending out SPMs */ + if (!pgm_send_spm (sock, PGM_OPT_SYN) || + !pgm_send_spm (sock, PGM_OPT_SYN) || + !pgm_send_spm (sock, PGM_OPT_SYN)) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + _("Sending SPM broadcast: %s"), + pgm_sock_strerror (save_errno)); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + + sock->next_poll = sock->next_ambient_spm = pgm_time_update_now() + sock->spm_ambient_interval; + +/* start PGMCC with one token */ + sock->tokens = sock->cwnd_size = pgm_fp8 (1); + +/* slow start threshold */ + sock->ssthresh = pgm_fp8 (4); + +/* ACK timeout, should be greater than first SPM heartbeat interval in order to be scheduled correctly */ + sock->ack_expiry_ivl = pgm_secs (3); + +/* start full history */ + sock->ack_bitmap = 0xffffffff; + } + else + { + pgm_assert (sock->can_recv_data); + sock->next_poll = pgm_time_update_now() + pgm_secs( 30 ); + } + + sock->is_connected = TRUE; + +/* cleanup */ + pgm_rwlock_writer_unlock (&sock->lock); + pgm_debug ("PGM socket successfully connected."); + return TRUE; +} + +/* return local endpoint address + */ + +bool +pgm_getsockname ( + pgm_sock_t* const restrict sock, + struct pgm_sockaddr_t* restrict addr, + socklen_t* restrict addrlen + ) +{ + pgm_assert (NULL != sock); + pgm_assert (NULL != addr); + pgm_assert (NULL != addrlen); + pgm_assert (sizeof(struct pgm_sockaddr_t) == *addrlen); + + if (!sock->is_bound) { + errno = EBADF; + return FALSE; + } + + addr->sa_port = sock->dport; + memcpy (&addr->sa_addr, &sock->tsi, sizeof(pgm_tsi_t)); + return TRUE; +} + +/* add select parameters for the receive socket(s) + * + * returns highest file descriptor used plus one. + */ + +int +pgm_select_info ( + pgm_sock_t* const restrict sock, + fd_set* const restrict readfds, /* blocking recv fds */ + fd_set* const restrict writefds, /* blocking send fds */ + int* const restrict n_fds /* in: max fds, out: max (in:fds, sock:fds) */ + ) +{ + int fds = 0; + + pgm_assert (NULL != sock); + pgm_assert (NULL != n_fds); + + if (!sock->is_bound || sock->is_destroyed) + { + errno = EBADF; + return -1; + } + + const bool is_congested = (sock->use_pgmcc && sock->tokens < pgm_fp8 (1)) ? TRUE : FALSE; + + if (readfds) + { + FD_SET(sock->recv_sock, readfds); + fds = sock->recv_sock + 1; + if (sock->can_send_data) { + const int rdata_fd = pgm_notify_get_fd (&sock->rdata_notify); + FD_SET(rdata_fd, readfds); + fds = MAX(fds, rdata_fd + 1); + if (is_congested) { + const int ack_fd = pgm_notify_get_fd (&sock->ack_notify); + FD_SET(ack_fd, readfds); + fds = MAX(fds, ack_fd + 1); + } + } + const int pending_fd = pgm_notify_get_fd (&sock->pending_notify); + FD_SET(pending_fd, readfds); + fds = MAX(fds, pending_fd + 1); + } + + if (sock->can_send_data && writefds && !is_congested) + { + FD_SET(sock->send_sock, writefds); + fds = MAX(sock->send_sock + 1, fds); + } + + return *n_fds = MAX(fds, *n_fds); +} + +#ifdef CONFIG_HAVE_POLL +/* add poll parameters for the receive socket(s) + * + * returns number of pollfd structures filled. + */ + +int +pgm_poll_info ( + pgm_sock_t* const restrict sock, + struct pollfd* const restrict fds, + int* const restrict n_fds, /* in: #fds, out: used #fds */ + const int events /* POLLIN, POLLOUT */ + ) +{ + pgm_assert (NULL != sock); + pgm_assert (NULL != fds); + pgm_assert (NULL != n_fds); + + if (!sock->is_bound || sock->is_destroyed) + { + errno = EBADF; + return -1; + } + + int moo = 0; + +/* we currently only support one incoming socket */ + if (events & POLLIN) + { + pgm_assert ( (1 + moo) <= *n_fds ); + fds[moo].fd = sock->recv_sock; + fds[moo].events = POLLIN; + moo++; + if (sock->can_send_data) { + pgm_assert ( (1 + moo) <= *n_fds ); + fds[moo].fd = pgm_notify_get_fd (&sock->rdata_notify); + fds[moo].events = POLLIN; + moo++; + } + pgm_assert ( (1 + moo) <= *n_fds ); + fds[moo].fd = pgm_notify_get_fd (&sock->pending_notify); + fds[moo].events = POLLIN; + moo++; + } + +/* ODATA only published on regular socket, no need to poll router-alert sock */ + if (sock->can_send_data && events & POLLOUT) + { + pgm_assert ( (1 + moo) <= *n_fds ); + if (sock->use_pgmcc && sock->tokens < pgm_fp8 (1)) { +/* rx thread poll for ACK */ + fds[moo].fd = pgm_notify_get_fd (&sock->ack_notify); + fds[moo].events = POLLIN; + } else { +/* kernel resource poll */ + fds[moo].fd = sock->send_sock; + fds[moo].events = POLLOUT; + } + moo++; + } + + return *n_fds = moo; +} +#endif /* CONFIG_HAVE_POLL */ + +/* add epoll parameters for the recieve socket(s), events should + * be set to EPOLLIN to wait for incoming events (data), and EPOLLOUT to wait + * for non-blocking write. + * + * returns 0 on success, -1 on failure and sets errno appropriately. + */ +#ifdef CONFIG_HAVE_EPOLL +int +pgm_epoll_ctl ( + pgm_sock_t* const sock, + const int epfd, + const int op, /* EPOLL_CTL_ADD, ... */ + const int events /* EPOLLIN, EPOLLOUT */ + ) +{ + if (!(op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD)) + { + errno = EINVAL; + return -1; + } + else if (!sock->is_bound || sock->is_destroyed) + { + errno = EBADF; + return -1; + } + + struct epoll_event event; + int retval = 0; + + if (events & EPOLLIN) + { + event.events = events & (EPOLLIN | EPOLLET | EPOLLONESHOT); + event.data.ptr = sock; + retval = epoll_ctl (epfd, op, sock->recv_sock, &event); + if (retval) + goto out; + if (sock->can_send_data) { + retval = epoll_ctl (epfd, op, pgm_notify_get_fd (&sock->rdata_notify), &event); + if (retval) + goto out; + } + retval = epoll_ctl (epfd, op, pgm_notify_get_fd (&sock->pending_notify), &event); + if (retval) + goto out; + + if (events & EPOLLET) + sock->is_edge_triggered_recv = TRUE; + } + + if (sock->can_send_data && events & EPOLLOUT) + { + bool enable_ack_socket = FALSE; + bool enable_send_socket = FALSE; + +/* both sockets need to be added when PGMCC is enabled */ + if (sock->use_pgmcc && EPOLL_CTL_ADD == op) { + enable_ack_socket = enable_send_socket = TRUE; + } else { +/* automagically switch socket when congestion stall occurs */ + if (sock->use_pgmcc && sock->tokens < pgm_fp8 (1)) + enable_ack_socket = TRUE; + else + enable_send_socket = TRUE; + } + + if (enable_ack_socket) + { +/* rx thread poll for ACK */ + event.events = EPOLLIN | (events & (EPOLLONESHOT)); + event.data.ptr = sock; + retval = epoll_ctl (epfd, op, pgm_notify_get_fd (&sock->ack_notify), &event); + } + + if (enable_send_socket) + { +/* kernel resource poll */ + event.events = events & (EPOLLOUT | EPOLLET | EPOLLONESHOT); + event.data.ptr = sock; + retval = epoll_ctl (epfd, op, sock->send_sock, &event); + } + } +out: + return retval; +} +#endif + +static +const char* +pgm_family_string ( + const int family + ) +{ + const char* c; + + switch (family) { + case AF_UNSPEC: c = "AF_UNSPEC"; break; + case AF_INET: c = "AF_INET"; break; + case AF_INET6: c = "AF_INET6"; break; + default: c = "(unknown)"; break; + } + + return c; +} + +static +const char* +pgm_sock_type_string ( + const int sock_type + ) +{ + const char* c; + + switch (sock_type) { + case SOCK_SEQPACKET: c = "SOCK_SEQPACKET"; break; + default: c = "(unknown)"; break; + } + + return c; +} + +static +const char* +pgm_protocol_string ( + const int protocol + ) +{ + const char* c; + + switch (protocol) { + case IPPROTO_UDP: c = "IPPROTO_UDP"; break; + case IPPROTO_PGM: c = "IPPROTO_PGM"; break; + default: c = "(unknown)"; break; + } + + return c; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/socket.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/socket.c.c89.patch new file mode 100644 index 0000000..ee48d8f --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/socket.c.c89.patch @@ -0,0 +1,403 @@ +--- socket.c 2010-08-04 17:24:23.000000000 +0800 ++++ socket.c89 2010-08-05 11:24:10.000000000 +0800 +@@ -243,7 +243,9 @@ + new_sock->adv_mode = 0; /* advance with time */ + + /* PGMCC */ ++#pragma warning( disable : 4244 ) + new_sock->acker_nla.ss_family = family; ++#pragma warning( default : 4244 ) + + /* source-side */ + pgm_mutex_init (&new_sock->source_mutex); +@@ -261,6 +263,7 @@ + pgm_rwlock_init (&new_sock->lock); + + /* open sockets to implement PGM */ ++ { + int socket_type; + if (IPPROTO_UDP == new_sock->protocol) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Opening UDP encapsulated sockets.")); +@@ -351,6 +354,7 @@ + } + pgm_free (new_sock); + return FALSE; ++ } + } + + bool +@@ -432,8 +436,8 @@ + { + struct timeval* tv = optval; + const pgm_time_t usecs = pgm_timer_expiration (sock); +- tv->tv_sec = usecs / 1000000UL; +- tv->tv_usec = usecs % 1000000UL; ++ tv->tv_sec = (long)(usecs / 1000000UL); ++ tv->tv_usec = (long)(usecs % 1000000UL); + } + status = TRUE; + break; +@@ -447,8 +451,8 @@ + { + struct timeval* tv = optval; + const pgm_time_t usecs = pgm_rate_remaining (&sock->rate_control, sock->blocklen); +- tv->tv_sec = usecs / 1000000UL; +- tv->tv_usec = usecs % 1000000UL; ++ tv->tv_sec = (long)(usecs / 1000000UL); ++ tv->tv_usec = (long)(usecs % 1000000UL); + } + status = TRUE; + break; +@@ -599,8 +603,11 @@ + sock->spm_heartbeat_len = optlen / sizeof (int); + sock->spm_heartbeat_interval = pgm_new (unsigned, sock->spm_heartbeat_len + 1); + sock->spm_heartbeat_interval[0] = 0; +- for (unsigned i = 0; i < sock->spm_heartbeat_len; i++) ++ { ++ unsigned i; ++ for (i = 0; i < sock->spm_heartbeat_len; i++) + sock->spm_heartbeat_interval[i + 1] = ((const int*)optval)[i]; ++ } + } + status = TRUE; + break; +@@ -795,6 +802,7 @@ + break; + if (PGM_UNLIKELY(fecinfo->group_size > fecinfo->block_size)) + break; ++ { + const uint8_t parity_packets = fecinfo->block_size - fecinfo->group_size; + /* technically could re-send previous packets */ + if (PGM_UNLIKELY(fecinfo->proactive_packets > parity_packets)) +@@ -811,6 +819,7 @@ + sock->rs_n = fecinfo->block_size; + sock->rs_k = fecinfo->group_size; + sock->rs_proactive_h = fecinfo->proactive_packets; ++ } + } + status = TRUE; + break; +@@ -916,7 +925,9 @@ + { + const struct group_req* gr = optval; + /* verify not duplicate group/interface pairing */ +- for (unsigned i = 0; i < sock->recv_gsr_len; i++) ++ { ++ unsigned i; ++ for (i = 0; i < sock->recv_gsr_len; i++) + { + if (pgm_sockaddr_cmp ((const struct sockaddr*)&gr->gr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0 && + pgm_sockaddr_cmp ((const struct sockaddr*)&gr->gr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_source) == 0 && +@@ -935,6 +946,7 @@ + break; + } + } ++ } + if (PGM_UNLIKELY(sock->family != gr->gr_group.ss_family)) + break; + if (PGM_SOCKET_ERROR == pgm_sockaddr_join_group (sock->recv_sock, sock->family, gr)) +@@ -956,7 +968,9 @@ + break; + { + const struct group_req* gr = optval; +- for (unsigned i = 0; i < sock->recv_gsr_len;) ++ { ++ unsigned i; ++ for (i = 0; i < sock->recv_gsr_len;) + { + if ((pgm_sockaddr_cmp ((const struct sockaddr*)&gr->gr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0) && + /* drop all matching receiver entries */ +@@ -973,6 +987,7 @@ + } + i++; + } ++ } + if (PGM_UNLIKELY(sock->family != gr->gr_group.ss_family)) + break; + if (PGM_SOCKET_ERROR == pgm_sockaddr_leave_group (sock->recv_sock, sock->family, gr)) +@@ -1023,7 +1038,9 @@ + { + const struct group_source_req* gsr = optval; + /* verify if existing group/interface pairing */ +- for (unsigned i = 0; i < sock->recv_gsr_len; i++) ++ { ++ unsigned i; ++ for (i = 0; i < sock->recv_gsr_len; i++) + { + if (pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0 && + (gsr->gsr_interface == sock->recv_gsr[i].gsr_interface || +@@ -1048,6 +1065,7 @@ + break; + } + } ++ } + if (PGM_UNLIKELY(sock->family != gsr->gsr_group.ss_family)) + break; + if (PGM_UNLIKELY(sock->family != gsr->gsr_source.ss_family)) +@@ -1070,7 +1088,9 @@ + { + const struct group_source_req* gsr = optval; + /* verify if existing group/interface pairing */ +- for (unsigned i = 0; i < sock->recv_gsr_len; i++) ++ { ++ unsigned i; ++ for (i = 0; i < sock->recv_gsr_len; i++) + { + if (pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (struct sockaddr*)&sock->recv_gsr[i].gsr_group) == 0 && + pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_source, (struct sockaddr*)&sock->recv_gsr[i].gsr_source) == 0 && +@@ -1084,6 +1104,7 @@ + } + } + } ++ } + if (PGM_UNLIKELY(sock->family != gsr->gsr_group.ss_family)) + break; + if (PGM_UNLIKELY(sock->family != gsr->gsr_source.ss_family)) +@@ -1336,52 +1357,78 @@ + if (sock->use_pgmcc && + 0 != pgm_notify_init (&sock->ack_notify)) + { ++#ifdef _MSC_VER ++ char buffer[1024]; ++#endif + const int save_errno = errno; + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_errno (save_errno), + _("Creating ACK notification channel: %s"), +- strerror (save_errno)); ++#ifdef _MSC_VER ++ strerror_s (buffer, sizeof(buffer), save_errno) ++#else ++ strerror (save_errno) ++#endif ++ ); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + if (0 != pgm_notify_init (&sock->rdata_notify)) + { ++#ifdef _MSC_VER ++ char buffer[1024]; ++#endif + const int save_errno = errno; + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_errno (save_errno), + _("Creating RDATA notification channel: %s"), +- strerror (save_errno)); ++#ifdef _MSC_VER ++ strerror_s (buffer, sizeof(buffer), save_errno) ++#else ++ strerror (save_errno) ++#endif ++ ); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + } + if (0 != pgm_notify_init (&sock->pending_notify)) + { ++#ifdef _MSC_VER ++ char buffer[1024]; ++#endif + const int save_errno = errno; + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_errno (save_errno), + _("Creating waiting peer notification channel: %s"), +- strerror (save_errno)); ++#ifdef _MSC_VER ++ strerror_s (buffer, sizeof(buffer), save_errno) ++#else ++ strerror (save_errno) ++#endif ++ ); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } + + /* determine IP header size for rate regulation engine & stats */ + sock->iphdr_len = (AF_INET == sock->family) ? sizeof(struct pgm_ip) : sizeof(struct pgm_ip6_hdr); +- pgm_trace (PGM_LOG_ROLE_NETWORK,"Assuming IP header size of %zu bytes", sock->iphdr_len); ++ pgm_trace (PGM_LOG_ROLE_NETWORK,"Assuming IP header size of %lu bytes", sock->iphdr_len); + + if (sock->udp_encap_ucast_port) { + const size_t udphdr_len = sizeof(struct pgm_udphdr); +- pgm_trace (PGM_LOG_ROLE_NETWORK,"Assuming UDP header size of %zu bytes", udphdr_len); ++ pgm_trace (PGM_LOG_ROLE_NETWORK,"Assuming UDP header size of %lu bytes", udphdr_len); + sock->iphdr_len += udphdr_len; + } + ++ { + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + sock->max_tsdu = sock->max_tpdu - sock->iphdr_len - pgm_pkt_offset (FALSE, pgmcc_family); + sock->max_tsdu_fragment = sock->max_tpdu - sock->iphdr_len - pgm_pkt_offset (TRUE, pgmcc_family); ++ { + const unsigned max_fragments = sock->txw_sqns ? MIN( PGM_MAX_FRAGMENTS, sock->txw_sqns ) : PGM_MAX_FRAGMENTS; + sock->max_apdu = MIN( PGM_MAX_APDU, max_fragments * sock->max_tsdu_fragment ); + +@@ -1419,6 +1466,7 @@ + /* Stevens: "SO_REUSEADDR has datatype int." + */ + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Set socket sharing.")); ++ { + const int v = 1; + if (PGM_SOCKET_ERROR == setsockopt (sock->recv_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&v, sizeof(v)) || + PGM_SOCKET_ERROR == setsockopt (sock->send_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&v, sizeof(v)) || +@@ -1433,10 +1481,12 @@ + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } ++ } + + /* request extra packet information to determine destination address on each packet */ + #ifndef CONFIG_TARGET_WINE + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Request socket packet-info.")); ++ { + const sa_family_t recv_family = sock->family; + if (PGM_SOCKET_ERROR == pgm_sockaddr_pktinfo (sock->recv_sock, recv_family, TRUE)) + { +@@ -1449,6 +1499,7 @@ + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; + } ++ } + #endif + } + else +@@ -1501,6 +1552,7 @@ + */ + /* TODO: different ports requires a new bound socket */ + ++ { + union { + struct sockaddr sa; + struct sockaddr_in s4; +@@ -1546,6 +1598,7 @@ + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&recv_addr, addr, sizeof(addr)); ++ { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, +@@ -1555,6 +1608,7 @@ + pgm_sock_strerror (save_errno)); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; ++ } + } + + if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) +@@ -1590,6 +1644,7 @@ + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&send_addr, addr, sizeof(addr)); ++ { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, +@@ -1599,6 +1654,7 @@ + pgm_sock_strerror (save_errno)); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; ++ } + } + + /* resolve bound address if 0.0.0.0 */ +@@ -1631,6 +1687,7 @@ + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&send_with_router_alert_addr, addr, sizeof(addr)); ++ { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, +@@ -1640,6 +1697,7 @@ + pgm_sock_strerror (save_errno)); + pgm_rwlock_writer_unlock (&sock->lock); + return FALSE; ++ } + } + + if (PGM_UNLIKELY(pgm_log_mask & PGM_LOG_ROLE_NETWORK)) +@@ -1658,7 +1716,7 @@ + /* setup rate control */ + if (sock->txw_max_rte) + { +- pgm_trace (PGM_LOG_ROLE_RATE_CONTROL,_("Setting rate regulation to %zd bytes per second."), ++ pgm_trace (PGM_LOG_ROLE_RATE_CONTROL,_("Setting rate regulation to %ld bytes per second."), + sock->txw_max_rte); + + pgm_rate_create (&sock->rate_control, sock->txw_max_rte, sock->iphdr_len, sock->max_tpdu); +@@ -1684,6 +1742,9 @@ + pgm_rwlock_writer_unlock (&sock->lock); + pgm_debug ("PGM socket successfully bound."); + return TRUE; ++ } ++ } ++ } + } + + bool +@@ -1697,11 +1758,14 @@ + #ifdef CONFIG_TARGET_WINE + pgm_return_val_if_fail (sock->recv_gsr_len == 1, FALSE); + #endif +- for (unsigned i = 0; i < sock->recv_gsr_len; i++) ++ { ++ unsigned i; ++ for (i = 0; i < sock->recv_gsr_len; i++) + { + pgm_return_val_if_fail (sock->recv_gsr[i].gsr_group.ss_family == sock->recv_gsr[0].gsr_group.ss_family, FALSE); + pgm_return_val_if_fail (sock->recv_gsr[i].gsr_group.ss_family == sock->recv_gsr[i].gsr_source.ss_family, FALSE); + } ++ } + pgm_return_val_if_fail (sock->send_gsr.gsr_group.ss_family == sock->recv_gsr[0].gsr_group.ss_family, FALSE); + /* shutdown */ + if (PGM_UNLIKELY(!pgm_rwlock_writer_trylock (&sock->lock))) +@@ -1810,6 +1874,7 @@ + return -1; + } + ++ { + const bool is_congested = (sock->use_pgmcc && sock->tokens < pgm_fp8 (1)) ? TRUE : FALSE; + + if (readfds) +@@ -1826,9 +1891,11 @@ + fds = MAX(fds, ack_fd + 1); + } + } ++ { + const int pending_fd = pgm_notify_get_fd (&sock->pending_notify); + FD_SET(pending_fd, readfds); + fds = MAX(fds, pending_fd + 1); ++ } + } + + if (sock->can_send_data && writefds && !is_congested) +@@ -1838,6 +1905,7 @@ + } + + return *n_fds = MAX(fds, *n_fds); ++ } + } + + #ifdef CONFIG_HAVE_POLL +@@ -1931,6 +1999,7 @@ + return -1; + } + ++ { + struct epoll_event event; + int retval = 0; + +@@ -1988,6 +2057,7 @@ + } + out: + return retval; ++ } + } + #endif + diff --git a/3rdparty/openpgm-svn-r1135/pgm/socket_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/socket_unittest.c new file mode 100644 index 0000000..f4ea446 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/socket_unittest.c @@ -0,0 +1,1293 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for PGM socket. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* mock state */ + +#define TEST_NETWORK "" +#define TEST_PORT 7500 +#define TEST_MAX_TPDU 1500 +#define TEST_TXW_SQNS 32 +#define TEST_RXW_SQNS 32 +#define TEST_HOPS 16 +#define TEST_SPM_AMBIENT ( pgm_secs(30) ) +#define TEST_SPM_HEARTBEAT_INIT { pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(1300), pgm_secs(7), pgm_secs(16), pgm_secs(25), pgm_secs(30) } +#define TEST_PEER_EXPIRY ( pgm_secs(300) ) +#define TEST_SPMR_EXPIRY ( pgm_msecs(250) ) +#define TEST_NAK_BO_IVL ( pgm_msecs(50) ) +#define TEST_NAK_RPT_IVL ( pgm_secs(2) ) +#define TEST_NAK_RDATA_IVL ( pgm_secs(2) ) +#define TEST_NAK_DATA_RETRIES 5 +#define TEST_NAK_NCF_RETRIES 2 + +#define pgm_ipproto_pgm mock_pgm_ipproto_pgm +#define pgm_peer_unref mock_pgm_peer_unref +#define pgm_on_nak_notify mock_pgm_on_nak_notify +#define pgm_send_spm mock_pgm_send_spm +#define pgm_timer_prepare mock_pgm_timer_prepare +#define pgm_timer_check mock_pgm_timer_check +#define pgm_timer_expiration mock_pgm_timer_expiration +#define pgm_timer_dispatch mock_pgm_timer_dispatch +#define pgm_txw_create mock_pgm_txw_create +#define pgm_txw_shutdown mock_pgm_txw_shutdown +#define pgm_rate_create mock_pgm_rate_create +#define pgm_rate_destroy mock_pgm_rate_destroy +#define pgm_rate_remaining mock_pgm_rate_remaining +#define pgm_rs_create mock_pgm_rs_create +#define pgm_rs_destroy mock_pgm_rs_destroy +#define pgm_time_update_now mock_pgm_time_update_now + +#define SOCK_DEBUG +#include "socket.c" + +int mock_pgm_ipproto_pgm = IPPROTO_PGM; + + +static +void +mock_setup (void) +{ + if (!g_thread_supported ()) g_thread_init (NULL); +} + +static +void +mock_teardown (void) +{ +} + +/* stock create pgm sockaddr structure for calls to pgm_bind() + */ + +static +struct pgm_sockaddr_t* +generate_asm_sockaddr (void) +{ + const pgm_gsi_t gsi = { 200, 202, 203, 204, 205, 206 }; + struct pgm_sockaddr_t* pgmsa = g_new0 (struct pgm_sockaddr_t, 1); + pgmsa->sa_port = TEST_PORT; + memcpy (&pgmsa->sa_addr.gsi, &gsi, sizeof(gsi)); + return pgmsa; +} + +/* apply minimum socket options to new socket to pass bind() + */ + +static +void +prebind_socket ( + struct pgm_sock_t* sock + ) +{ + sock->max_tpdu = TEST_MAX_TPDU; + sock->max_tsdu = TEST_MAX_TPDU - sizeof(struct pgm_ip) - pgm_pkt_offset (FALSE, FALSE); + sock->max_tsdu_fragment = TEST_MAX_TPDU - sizeof(struct pgm_ip) - pgm_pkt_offset (TRUE, FALSE); + sock->max_apdu = MIN(TEST_TXW_SQNS, PGM_MAX_FRAGMENTS) * sock->max_tsdu_fragment; + +/* tx */ + sock->can_send_data = TRUE; + sock->spm_ambient_interval = TEST_SPM_AMBIENT; + const guint interval_init[] = TEST_SPM_HEARTBEAT_INIT; + sock->spm_heartbeat_len = sizeof(interval_init) / sizeof(interval_init[0]); + sock->spm_heartbeat_interval = g_new0 (guint, sock->spm_heartbeat_len + 1); + for (guint i = 1; i < sock->spm_heartbeat_len; i++) + sock->spm_heartbeat_interval[i] = interval_init[i]; + sock->txw_sqns = TEST_TXW_SQNS; + +/* rx */ + sock->can_recv_data = TRUE; + sock->rxw_sqns = TEST_RXW_SQNS; + sock->peer_expiry = TEST_PEER_EXPIRY; + sock->spmr_expiry = TEST_SPMR_EXPIRY; + sock->nak_bo_ivl = TEST_NAK_BO_IVL; + sock->nak_rpt_ivl = TEST_NAK_RPT_IVL; + sock->nak_rdata_ivl = TEST_NAK_RDATA_IVL; + sock->nak_data_retries = TEST_NAK_DATA_RETRIES; + sock->nak_ncf_retries = TEST_NAK_NCF_RETRIES; +} + +/* apply minimum sockets options to pass connect() + */ + +static +void +preconnect_socket ( + struct pgm_sock_t* sock + ) +{ +/* tx */ + ((struct sockaddr*)&sock->send_gsr.gsr_group)->sa_family = AF_INET; + ((struct sockaddr_in*)&sock->send_gsr.gsr_group)->sin_addr.s_addr = inet_addr ("239.192.0.1"); + +/* rx */ + sock->recv_gsr_len = 1; + ((struct sockaddr*)&sock->recv_gsr[0].gsr_group)->sa_family = ((struct sockaddr*)&sock->send_gsr.gsr_group)->sa_family; + ((struct sockaddr*)&sock->recv_gsr[0].gsr_source)->sa_family = ((struct sockaddr*)&sock->send_gsr.gsr_group)->sa_family; + ((struct sockaddr_in*)&sock->recv_gsr[0].gsr_group)->sin_addr.s_addr = ((struct sockaddr_in*)&sock->send_gsr.gsr_group)->sin_addr.s_addr; + ((struct sockaddr_in*)&sock->recv_gsr[0].gsr_source)->sin_addr.s_addr = ((struct sockaddr_in*)&sock->send_gsr.gsr_group)->sin_addr.s_addr; +} + +/* stock create unconnected socket for pgm_setsockopt(), etc. + */ + +static +struct pgm_sock_t* +generate_sock (void) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, g_htons(TEST_PORT) }; + struct pgm_sock_t* sock = g_new0 (struct pgm_sock_t, 1); + sock->family = AF_INET; + sock->protocol = IPPROTO_IP; + sock->recv_sock = socket (AF_INET, SOCK_RAW, 113); + sock->send_sock = socket (AF_INET, SOCK_RAW, 113); + sock->send_with_router_alert_sock = socket (AF_INET, SOCK_RAW, 113); + ((struct sockaddr*)&sock->send_addr)->sa_family = AF_INET; + ((struct sockaddr_in*)&sock->send_addr)->sin_addr.s_addr = inet_addr ("127.0.0.2"); + memcpy (&sock->tsi, &tsi, sizeof(pgm_tsi_t)); + sock->dport = g_htons(TEST_PORT); + sock->window = g_new0 (pgm_txw_t, 1); + sock->iphdr_len = sizeof(struct pgm_ip); + pgm_rwlock_init (&sock->lock); + pgm_spinlock_init (&sock->txw_spinlock); + sock->is_bound = FALSE; + sock->is_connected = FALSE; + sock->is_destroyed = FALSE; + sock->is_reset = FALSE; + return sock; +} + +/** receiver module */ +PGM_GNUC_INTERNAL +void +mock_pgm_peer_unref ( + pgm_peer_t* peer + ) +{ +} + +/** source module */ +static +bool +mock_pgm_on_nak_notify ( + GIOChannel* source, + GIOCondition condition, + gpointer data + ) +{ + return TRUE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_send_spm ( + pgm_sock_t* sock, + int flags + ) +{ + return TRUE; +} + +/** timer module */ +PGM_GNUC_INTERNAL +bool +mock_pgm_timer_prepare ( + pgm_sock_t* const sock + ) +{ + return FALSE; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_timer_check ( + pgm_sock_t* const sock + ) +{ + return FALSE; +} + +PGM_GNUC_INTERNAL +pgm_time_t +mock_pgm_timer_expiration ( + pgm_sock_t* const sock + ) +{ + return 100L; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_timer_dispatch ( + pgm_sock_t* const sock + ) +{ + return TRUE; +} + +/** transmit window module */ +pgm_txw_t* +mock_pgm_txw_create ( + const pgm_tsi_t* const tsi, + const uint16_t tpdu_size, + const uint32_t sqns, + const unsigned secs, + const ssize_t max_rte, + const bool use_fec, + const uint8_t rs_n, + const uint8_t rs_k + ) +{ + pgm_txw_t* window = g_new0 (pgm_txw_t, 1); + return window; +} + +void +mock_pgm_txw_shutdown ( + pgm_txw_t* const window + ) +{ + g_free (window); +} + +/** rate control module */ +PGM_GNUC_INTERNAL +void +mock_pgm_rate_create ( + pgm_rate_t* bucket, + ssize_t rate_per_sec, + size_t iphdr_len, + uint16_t max_tpdu + ) +{ +} + +PGM_GNUC_INTERNAL +void +mock_pgm_rate_destroy ( + pgm_rate_t* bucket + ) +{ +} + +PGM_GNUC_INTERNAL +pgm_time_t +mock_pgm_rate_remaining ( + pgm_rate_t* bucket, + gsize packetlen + ) +{ + return 0; +} + +/** reed solomon module */ +void +mock_pgm_rs_create ( + pgm_rs_t* rs, + const uint8_t n, + const uint8_t k + ) +{ +} + +void +mock_pgm_rs_destroy ( + pgm_rs_t* rs + ) +{ +} + +/** time module */ +static pgm_time_t _mock_pgm_time_update_now (void); +pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; + +static +pgm_time_t +_mock_pgm_time_update_now (void) +{ + return 0x1; +} + + +/* mock functions for external references */ + + +/* target: + * bool + * pgm_socket ( + * pgm_sock_t** sock, + * const sa_family_t family, + * const int pgm_sock_type, + * const int protocol, + * pgm_error_t** error + * ) + */ + +START_TEST (test_create_pass_001) +{ + pgm_error_t* err = NULL; + pgm_sock_t* sock; +/* only one type currently implemented */ + const int pgm_sock_type = SOCK_SEQPACKET; +/* PGM/IPv4 */ + sock = NULL; + fail_unless (TRUE == pgm_socket (&sock, AF_INET, pgm_sock_type, IPPROTO_PGM, &err), "create failed"); +/* PGM/UDP over IPv4 */ + sock = NULL; + fail_unless (TRUE == pgm_socket (&sock, AF_INET, pgm_sock_type, IPPROTO_UDP, &err), "create failed"); +/* PGM/IPv6 */ + sock = NULL; + fail_unless (TRUE == pgm_socket (&sock, AF_INET6, pgm_sock_type, IPPROTO_PGM, &err), "create failed"); +/* PGM/UDP over IPv6 */ + sock = NULL; + fail_unless (TRUE == pgm_socket (&sock, AF_INET6, pgm_sock_type, IPPROTO_UDP, &err), "create failed"); + fail_unless (NULL == err, "error raised"); +} +END_TEST + +/* NULL socket */ +START_TEST (test_create_fail_002) +{ + pgm_error_t* err = NULL; + fail_unless (FALSE == pgm_socket (NULL, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); +} +END_TEST + +/* invalid protocol family */ +START_TEST (test_create_fail_003) +{ + pgm_error_t* err = NULL; + pgm_sock_t* sock = NULL; + fail_unless (FALSE == pgm_socket (&sock, AF_UNSPEC, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); +} +END_TEST + +/* invalid socket type */ +START_TEST (test_create_fail_004) +{ + pgm_error_t* err = NULL; + pgm_sock_t* sock = NULL; + fail_unless (FALSE == pgm_socket (&sock, AF_INET, SOCK_STREAM, IPPROTO_PGM, &err), "create failed"); + fail_unless (FALSE == pgm_socket (&sock, AF_INET, SOCK_DGRAM, IPPROTO_PGM, &err), "create failed"); +} +END_TEST + +/* invalid protocol */ +START_TEST (test_create_fail_005) +{ + pgm_error_t* err = NULL; + pgm_sock_t* sock = NULL; + fail_unless (FALSE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_TCP, &err), "create failed"); +} +END_TEST + + +/* target: + * bool + * pgm_bind ( + * pgm_sock_t* sock, + * const struct pgm_sockaddr_t* sockaddr, + * const socklen_t sockaddrlen, + * pgm_error_t** error + * ) + */ + +START_TEST (test_bind_pass_001) +{ + pgm_error_t* err = NULL; + pgm_sock_t* sock = NULL; + struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); + fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); + fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); + fail_unless (NULL == err, "error raised"); + fail_unless (TRUE == pgm_bind (sock, pgmsa, sizeof(*pgmsa), &err), "bind failed"); +} +END_TEST + +/* fail on unset options */ +START_TEST (test_bind_fail_001) +{ + pgm_error_t* err = NULL; + pgm_sock_t* sock = NULL; + struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); + fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); + fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); + fail_unless (NULL == err, "error raised"); + fail_unless (FALSE == pgm_bind (sock, pgmsa, sizeof(*pgmsa), &err), "bind failed"); +} +END_TEST + +/* invalid parameters */ +START_TEST (test_bind_fail_002) +{ + pgm_error_t* err = NULL; + fail_unless (FALSE == pgm_bind (NULL, NULL, 0, &err), "bind failed"); +} +END_TEST + +/* target: + * bool + * pgm_bind3 ( + * pgm_sock_t* sock, + * const struct pgm_sockaddr_t* sockaddr, + * const socklen_t sockaddrlen, + * const struct pgm_interface_req_t* send_req, + * const socklen_t send_req_len, + * const struct pgm_interface_req_t* recv_req, + * const socklen_t recv_req_len, + * pgm_error_t** error + * ) + */ + +/* fail on unset options */ +START_TEST (test_bind3_fail_001) +{ + pgm_error_t* err = NULL; + pgm_sock_t* sock = NULL; + struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); + fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); + fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); + fail_unless (NULL == err, "error raised"); + struct pgm_interface_req_t send_req = { .ir_interface = 0, .ir_scope_id = 0 }, + recv_req = { .ir_interface = 0, .ir_scope_id = 0 }; + fail_unless (FALSE == pgm_bind3 (sock, + pgmsa, sizeof(*pgmsa), + &send_req, sizeof(send_req), + &recv_req, sizeof(recv_req), + &err), "bind failed"); +} +END_TEST + +/* invalid parameters */ +START_TEST (test_bind3_fail_002) +{ + pgm_error_t* err = NULL; + fail_unless (FALSE == pgm_bind3 (NULL, NULL, 0, NULL, 0, NULL, 0, &err), "bind failed"); +} +END_TEST + +/* target: + * bool + * pgm_connect ( + * pgm_sock_t* sock, + * pgm_error_t** error + * ) + */ + +START_TEST (test_connect_pass_001) +{ + pgm_error_t* err = NULL; + pgm_sock_t* sock = NULL; + struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); + fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); + fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); + fail_unless (NULL == err, "error raised"); + prebind_socket (sock); + fail_unless (TRUE == pgm_bind (sock, pgmsa, sizeof(*pgmsa), &err), "bind failed"); + preconnect_socket (sock); + fail_unless (TRUE == pgm_connect (sock, &err), "connect failed"); +} +END_TEST + +/* invalid parameters */ +START_TEST (test_connect_fail_001) +{ + pgm_error_t* err = NULL; + fail_unless (FALSE == pgm_connect (NULL, &err), "connect failed"); +} +END_TEST + +/* target: + * bool + * pgm_close ( + * pgm_sock_t* sock, + * bool flush + * ) + */ + +/* socket > close */ +START_TEST (test_destroy_pass_001) +{ + pgm_error_t* err = NULL; + pgm_sock_t* sock = NULL; + fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); + fail_unless (TRUE == pgm_close (sock, FALSE), "destroy failed"); +} +END_TEST + +/* socket > bind > close */ +START_TEST (test_destroy_pass_002) +{ + pgm_error_t* err = NULL; + pgm_sock_t* sock = NULL; + struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); + fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); + fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); + fail_unless (NULL == err, "error raised"); + fail_unless (TRUE == pgm_bind (sock, pgmsa, sizeof(*pgmsa), &err), "bind failed"); + fail_unless (TRUE == pgm_close (sock, FALSE), "destroy failed"); +} +END_TEST + +/* socket > bind > connect > close */ +START_TEST (test_destroy_pass_003) +{ + pgm_error_t* err = NULL; + pgm_sock_t* sock = NULL; + struct pgm_sockaddr_t* pgmsa = generate_asm_sockaddr (); + fail_if (NULL == pgmsa, "generate_asm_sockaddr failed"); + fail_unless (TRUE == pgm_socket (&sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &err), "create failed"); + fail_unless (NULL == err, "error raised"); + fail_unless (TRUE == pgm_bind (sock, pgmsa, sizeof(*pgmsa), &err), "bind failed"); + fail_unless (TRUE == pgm_connect (sock, &err), "connect failed"); + fail_unless (TRUE == pgm_close (sock, FALSE), "destroy failed"); +} +END_TEST + +/* invalid parameters */ +START_TEST (test_destroy_fail_001) +{ + fail_unless (FALSE == pgm_close (NULL, FALSE), "destroy failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_MAX_TPDU, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_max_tpdu_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_MTU; + const int max_tpdu = 1500; + const void* optval = &max_tpdu; + const socklen_t optlen = sizeof(max_tpdu); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_max_tpdu failed"); +} +END_TEST + +/* invalid parameters */ +START_TEST (test_set_max_tpdu_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_MTU; + const int max_tpdu = 1500; + const void* optval = &max_tpdu; + const socklen_t optlen = sizeof(max_tpdu); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_max_tpdu failed"); +} +END_TEST + +/* too small */ +START_TEST (test_set_max_tpdu_fail_002) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_MTU; + const int max_tpdu = 1; + const void* optval = &max_tpdu; + const socklen_t optlen = sizeof(max_tpdu); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_max_tpdu failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_MULTICAST_LOOP, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_multicast_loop_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_MULTICAST_LOOP; + const int loop_enabled = 1; + const void* optval = &loop_enabled; + const socklen_t optlen = sizeof(loop_enabled); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_multicast_loop failed"); +} +END_TEST + +START_TEST (test_set_multicast_loop_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_MULTICAST_LOOP; + const int loop_enabled = 1; + const void* optval = &loop_enabled; + const socklen_t optlen = sizeof(loop_enabled); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_multicast_loop failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_MULTICAST_HOPS, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_hops_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_MULTICAST_HOPS; + const int hops = 16; + const void* optval = &hops; + const socklen_t optlen = sizeof(hops); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_hops failed"); +} +END_TEST + +START_TEST (test_set_hops_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_MULTICAST_HOPS; + const int hops = 16; + const void* optval = &hops; + const socklen_t optlen = sizeof(hops); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_hops failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = SOL_SOCKET, + * const int optname = SO_SNDBUF, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_sndbuf_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = SOL_SOCKET; + const int optname = SO_SNDBUF; + const int bufsize = 131071; /* 128kB */ + const void* optval = &bufsize; + const socklen_t optlen = sizeof(bufsize); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_sndbuf failed"); +} +END_TEST + +START_TEST (test_set_sndbuf_fail_001) +{ + const int level = SOL_SOCKET; + const int optname = SO_SNDBUF; + const int bufsize = 131071; /* 128kB */ + const void* optval = &bufsize; + const socklen_t optlen = sizeof(bufsize); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_sndbuf failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = SOL_SOCKET, + * const int optname = PGM_RCVBUF, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_rcvbuf_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = SOL_SOCKET; + const int optname = SO_RCVBUF; + const int bufsize = 131071; /* 128kB */ + const void* optval = &bufsize; + const socklen_t optlen = sizeof(bufsize); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_rcvbuf failed"); +} +END_TEST + +START_TEST (test_set_rcvbuf_fail_001) +{ + const int level = SOL_SOCKET; + const int optname = SO_RCVBUF; + const int bufsize = 131071; /* 128kB */ + const void* optval = &bufsize; + const socklen_t optlen = sizeof(bufsize); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_rcvbuf failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_USE_FEC, + * const void* optval, + * const socklen_t optlen = sizeof(struct pgm_fecinfo_t) + * ) + */ + +START_TEST (test_set_fec_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_USE_FEC; + const struct pgm_fecinfo_t fecinfo = { + .ondemand_parity_enabled = TRUE, + .proactive_packets = 16, + .var_pktlen_enabled = TRUE, + .block_size = 255, + .group_size = 64 + }; + const void* optval = &fecinfo; + const socklen_t optlen = sizeof(fecinfo); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_fec failed"); +} +END_TEST + +START_TEST (test_set_fec_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_USE_FEC; + const struct pgm_fecinfo_t fecinfo = { + .ondemand_parity_enabled = TRUE, + .proactive_packets = 16, + .var_pktlen_enabled = TRUE, + .block_size = 255, + .group_size = 64 + }; + const void* optval = &fecinfo; + const socklen_t optlen = sizeof(fecinfo); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_fec failed"); +} +END_TEST + +/* TODO: invalid Reed-Solomon parameters + */ + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_USE_PGMCC, + * const void* optval, + * const socklen_t optlen = sizeof(struct pgm_pgmccinfo_t) + * ) + */ + +START_TEST (test_set_pgmcc_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_USE_PGMCC; + const struct pgm_pgmccinfo_t pgmccinfo = { + .ack_bo_ivl = pgm_msecs(100), + .ack_c = 123, + .ack_c_p = 456 + }; + const void* optval = &pgmccinfo; + const socklen_t optlen = sizeof(pgmccinfo); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_pgmcc failed"); +} +END_TEST + +START_TEST (test_set_pgmcc_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_USE_PGMCC; + const struct pgm_pgmccinfo_t pgmccinfo = { + .ack_bo_ivl = pgm_msecs(100), + .ack_c = 123, + .ack_c_p = 456 + }; + const void* optval = &pgmccinfo; + const socklen_t optlen = sizeof(pgmccinfo); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_pgmcc failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_USE_CR, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_cr_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_USE_CR; + const int magic_bunny = 1; + const void* optval = &magic_bunny; + const socklen_t optlen = sizeof(magic_bunny); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_cr failed"); +} +END_TEST + +START_TEST (test_set_cr_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_USE_CR; + const int magic_bunny = 1; + const void* optval = &magic_bunny; + const socklen_t optlen = sizeof(magic_bunny); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_cr failed"); +} +END_TEST + + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_SEND_ONLY, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_send_only_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_SEND_ONLY; + const int send_only = 1; + const void* optval = &send_only; + const socklen_t optlen = sizeof(send_only); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_send_only failed"); +} +END_TEST + +START_TEST (test_set_send_only_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_SEND_ONLY; + const int send_only = 1; + const void* optval = &send_only; + const socklen_t optlen = sizeof(send_only); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_send_only failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_RECV_ONLY, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_recv_only_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_RECV_ONLY; + const int recv_only = 1; + const void* optval = &recv_only; + const socklen_t optlen = sizeof(recv_only); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_recv_only failed"); +} +END_TEST + +START_TEST (test_set_recv_only_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_RECV_ONLY; + const int recv_only = 1; + const void* optval = &recv_only; + const socklen_t optlen = sizeof(recv_only); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_recv_only failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_PASSIVE, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_recv_only_pass_002) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_PASSIVE; + const int passive = 1; + const void* optval = &passive; + const socklen_t optlen = sizeof(passive); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_passive failed"); +} +END_TEST + +START_TEST (test_set_recv_only_fail_002) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_PASSIVE; + const int passive = 1; + const void* optval = &passive; + const socklen_t optlen = sizeof(passive); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_passive failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_ABORT_ON_RESET, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_abort_on_reset_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_ABORT_ON_RESET; + const int abort_on_reset= 1; + const void* optval = &abort_on_reset; + const socklen_t optlen = sizeof(abort_on_reset); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_abort_on_reset failed"); +} +END_TEST + +START_TEST (test_set_abort_on_reset_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_ABORT_ON_RESET; + const int abort_on_reset= 1; + const void* optval = &abort_on_reset; + const socklen_t optlen = sizeof(abort_on_reset); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_abort_on_reset failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_NOBLOCK, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_noblock_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_NOBLOCK; + const int noblock = 1; + const void* optval = &noblock; + const socklen_t optlen = sizeof(noblock); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_noblock failed"); +} +END_TEST + +START_TEST (test_set_noblock_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_NOBLOCK; + const int noblock = 1; + const void* optval = &noblock; + const socklen_t optlen = sizeof(noblock); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_noblock failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_UDP_ENCAP_UCAST_PORT, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_udp_unicast_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_NOBLOCK; + const int unicast_port = 10001; + const void* optval = &unicast_port; + const socklen_t optlen = sizeof(unicast_port); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_udp_unicast failed"); +} +END_TEST + +START_TEST (test_set_udp_unicast_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_NOBLOCK; + const int unicast_port = 10001; + const void* optval = &unicast_port; + const socklen_t optlen = sizeof(unicast_port); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_udp_unicast failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_UDP_ENCAP_MCAST_PORT, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_udp_multicast_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_NOBLOCK; + const int multicast_port= 10001; + const void* optval = &multicast_port; + const socklen_t optlen = sizeof(multicast_port); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_udp_multicast failed"); +} +END_TEST + +START_TEST (test_set_udp_multicast_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_NOBLOCK; + const int multicast_port= 10002; + const void* optval = &multicast_port; + const socklen_t optlen = sizeof(multicast_port); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_udp_multicast failed"); +} +END_TEST + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_create = tcase_create ("create"); + suite_add_tcase (s, tc_create); + tcase_add_checked_fixture (tc_create, mock_setup, mock_teardown); + tcase_add_test (tc_create, test_create_pass_001); + tcase_add_test (tc_create, test_create_fail_002); + tcase_add_test (tc_create, test_create_fail_003); + tcase_add_test (tc_create, test_create_fail_004); + tcase_add_test (tc_create, test_create_fail_005); + + TCase* tc_bind = tcase_create ("bind"); + suite_add_tcase (s, tc_bind); + tcase_add_checked_fixture (tc_bind, mock_setup, mock_teardown); + tcase_add_test (tc_bind, test_bind_fail_001); + tcase_add_test (tc_bind, test_bind_fail_002); + + TCase* tc_connect = tcase_create ("connect"); + suite_add_tcase (s, tc_connect); + tcase_add_checked_fixture (tc_connect, mock_setup, mock_teardown); + tcase_add_test (tc_connect, test_connect_pass_001); + tcase_add_test (tc_connect, test_connect_fail_001); + + TCase* tc_destroy = tcase_create ("destroy"); + suite_add_tcase (s, tc_destroy); + tcase_add_checked_fixture (tc_destroy, mock_setup, mock_teardown); + tcase_add_test (tc_destroy, test_destroy_pass_001); + tcase_add_test (tc_destroy, test_destroy_fail_001); + + TCase* tc_set_max_tpdu = tcase_create ("set-max-tpdu"); + suite_add_tcase (s, tc_set_max_tpdu); + tcase_add_checked_fixture (tc_set_max_tpdu, mock_setup, mock_teardown); + tcase_add_test (tc_set_max_tpdu, test_set_max_tpdu_pass_001); + tcase_add_test (tc_set_max_tpdu, test_set_max_tpdu_fail_001); + + TCase* tc_set_multicast_loop = tcase_create ("set-multicast-loop"); + suite_add_tcase (s, tc_set_multicast_loop); + tcase_add_checked_fixture (tc_set_multicast_loop, mock_setup, mock_teardown); + tcase_add_test (tc_set_multicast_loop, test_set_multicast_loop_pass_001); + tcase_add_test (tc_set_multicast_loop, test_set_multicast_loop_fail_001); + + TCase* tc_set_hops = tcase_create ("set-hops"); + suite_add_tcase (s, tc_set_hops); + tcase_add_checked_fixture (tc_set_hops, mock_setup, mock_teardown); + tcase_add_test (tc_set_hops, test_set_hops_pass_001); + tcase_add_test (tc_set_hops, test_set_hops_fail_001); + + TCase* tc_set_sndbuf = tcase_create ("set-sndbuf"); + suite_add_tcase (s, tc_set_sndbuf); + tcase_add_checked_fixture (tc_set_sndbuf, mock_setup, mock_teardown); + tcase_add_test (tc_set_sndbuf, test_set_sndbuf_pass_001); + tcase_add_test (tc_set_sndbuf, test_set_sndbuf_fail_001); + + TCase* tc_set_rcvbuf = tcase_create ("set-rcvbuf"); + suite_add_tcase (s, tc_set_rcvbuf); + tcase_add_checked_fixture (tc_set_rcvbuf, mock_setup, mock_teardown); + tcase_add_test (tc_set_rcvbuf, test_set_rcvbuf_pass_001); + tcase_add_test (tc_set_rcvbuf, test_set_rcvbuf_fail_001); + + TCase* tc_set_fec = tcase_create ("set-fec"); + suite_add_tcase (s, tc_set_fec); + tcase_add_checked_fixture (tc_set_fec, mock_setup, mock_teardown); + tcase_add_test (tc_set_fec, test_set_fec_pass_001); + tcase_add_test (tc_set_fec, test_set_fec_fail_001); + + TCase* tc_set_pgmcc = tcase_create ("set-pgmcc"); + suite_add_tcase (s, tc_set_pgmcc); + tcase_add_checked_fixture (tc_set_pgmcc, mock_setup, mock_teardown); + tcase_add_test (tc_set_pgmcc, test_set_pgmcc_pass_001); + tcase_add_test (tc_set_pgmcc, test_set_pgmcc_fail_001); + + TCase* tc_set_cr = tcase_create ("set-cr"); + suite_add_tcase (s, tc_set_cr); + tcase_add_checked_fixture (tc_set_cr, mock_setup, mock_teardown); + tcase_add_test (tc_set_cr, test_set_cr_pass_001); + tcase_add_test (tc_set_cr, test_set_cr_fail_001); + + TCase* tc_set_send_only = tcase_create ("set-send-only"); + suite_add_tcase (s, tc_set_send_only); + tcase_add_checked_fixture (tc_set_send_only, mock_setup, mock_teardown); + tcase_add_test (tc_set_send_only, test_set_send_only_pass_001); + tcase_add_test (tc_set_send_only, test_set_send_only_fail_001); + + TCase* tc_set_recv_only = tcase_create ("set-recv-only"); + suite_add_tcase (s, tc_set_recv_only); + tcase_add_checked_fixture (tc_set_recv_only, mock_setup, mock_teardown); + tcase_add_test (tc_set_recv_only, test_set_recv_only_pass_001); + tcase_add_test (tc_set_recv_only, test_set_recv_only_pass_002); + tcase_add_test (tc_set_recv_only, test_set_recv_only_fail_001); + tcase_add_test (tc_set_recv_only, test_set_recv_only_fail_002); + + TCase* tc_set_abort_on_reset = tcase_create ("set-abort-on-reset"); + suite_add_tcase (s, tc_set_abort_on_reset); + tcase_add_checked_fixture (tc_set_abort_on_reset, mock_setup, mock_teardown); + tcase_add_test (tc_set_abort_on_reset, test_set_abort_on_reset_pass_001); + tcase_add_test (tc_set_abort_on_reset, test_set_abort_on_reset_fail_001); + + TCase* tc_set_noblock = tcase_create ("set-non-blocking"); + suite_add_tcase (s, tc_set_noblock); + tcase_add_checked_fixture (tc_set_noblock, mock_setup, mock_teardown); + tcase_add_test (tc_set_noblock, test_set_noblock_pass_001); + tcase_add_test (tc_set_noblock, test_set_noblock_fail_001); + + TCase* tc_set_udp_unicast = tcase_create ("set-udp-encap-ucast-port"); + suite_add_tcase (s, tc_set_udp_unicast); + tcase_add_checked_fixture (tc_set_udp_unicast, mock_setup, mock_teardown); + tcase_add_test (tc_set_udp_unicast, test_set_udp_unicast_pass_001); + tcase_add_test (tc_set_udp_unicast, test_set_udp_unicast_fail_001); + + TCase* tc_set_udp_multicast = tcase_create ("set-udp-encap-mcast-port"); + suite_add_tcase (s, tc_set_udp_multicast); + tcase_add_checked_fixture (tc_set_udp_multicast, mock_setup, mock_teardown); + tcase_add_test (tc_set_udp_multicast, test_set_udp_multicast_pass_001); + tcase_add_test (tc_set_udp_multicast, test_set_udp_multicast_fail_001); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + if (0 != getuid()) { + fprintf (stderr, "This test requires super-user privileges to run.\n"); + return EXIT_FAILURE; + } + + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/source.c b/3rdparty/openpgm-svn-r1135/pgm/source.c new file mode 100644 index 0000000..bea0f33 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/source.c @@ -0,0 +1,2345 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM source socket. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __STDC_FORMAT_MACROS +#ifdef _MSC_VER +# include +#else +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + + +//#define SOURCE_DEBUG + +#ifndef SOURCE_DEBUG +# define PGM_DISABLE_ASSERT +#endif + +#if !defined(ENOBUFS) && defined(WSAENOBUFS) +# define ENOBUFS WSAENOBUFS +#endif + + +/* locals */ +static inline bool peer_is_source (const pgm_peer_t*) PGM_GNUC_CONST; +static inline bool peer_is_peer (const pgm_peer_t*) PGM_GNUC_CONST; +static void reset_heartbeat_spm (pgm_sock_t*const, const pgm_time_t); +static bool send_ncf (pgm_sock_t*const restrict, const struct sockaddr*const restrict, const struct sockaddr*const restrict, const uint32_t, const bool); +static bool send_ncf_list (pgm_sock_t*const restrict, const struct sockaddr*const restrict, const struct sockaddr*const restrict, struct pgm_sqn_list_t*const restrict, const bool); +static int send_odata (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict, size_t*restrict); +static int send_odata_copy (pgm_sock_t*const restrict, const void*restrict, const uint16_t, size_t*restrict); +static int send_odatav (pgm_sock_t*const restrict, const struct pgm_iovec*const restrict, const unsigned, size_t*restrict); +static bool send_rdata (pgm_sock_t*restrict, struct pgm_sk_buff_t*restrict); + + +static inline +unsigned +_pgm_popcount ( + uint32_t n + ) +{ +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + return __builtin_popcount (n); +#else +/* MIT HAKMEM 169 */ + const uint32_t t = n - ((n >> 1) & 033333333333) + - ((n >> 2) & 011111111111); + return ((t + (t >> 3) & 030707070707)) % 63; +#endif +} + +static inline +bool +peer_is_source ( + const pgm_peer_t* peer + ) +{ + return (NULL == peer); +} + +static inline +bool +peer_is_peer ( + const pgm_peer_t* peer + ) +{ + return (NULL != peer); +} + +static inline +void +reset_spmr_timer ( + pgm_peer_t* const peer + ) +{ + peer->spmr_expiry = 0; +} + +static inline +size_t +source_max_tsdu ( + const pgm_sock_t* sock, + const bool can_fragment + ) +{ + size_t max_tsdu = can_fragment ? sock->max_tsdu_fragment : sock->max_tsdu; + if (sock->use_var_pktlen /* OPT_VAR_PKT_LEN */) + max_tsdu -= sizeof (uint16_t); + return max_tsdu; +} + +/* prototype of function to send pro-active parity NAKs. + */ +static +bool +pgm_schedule_proactive_nak ( + pgm_sock_t* sock, + uint32_t nak_tg_sqn /* transmission group (shifted) */ + ) +{ + pgm_return_val_if_fail (NULL != sock, FALSE); + const bool status = pgm_txw_retransmit_push (sock->window, + nak_tg_sqn | sock->rs_proactive_h, + TRUE /* is_parity */, + sock->tg_sqn_shift); + return status; +} + +/* a deferred request for RDATA, now processing in the timer thread, we check the transmit + * window to see if the packet exists and forward on, maintaining a lock until the queue is + * empty. + * + * returns TRUE on success, returns FALSE if operation would block. + */ + +bool +pgm_on_deferred_nak ( + pgm_sock_t* const sock + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + +/* We can flush queue and block all odata, or process one set, or process each + * sequence number individually. + */ + +/* parity packets are re-numbered across the transmission group with index h, sharing the space + * with the original packets. beyond the transmission group size (k), the PGM option OPT_PARITY_GRP + * provides the extra offset value. + */ + +/* peek from the retransmit queue so we can eliminate duplicate NAKs up until the repair packet + * has been retransmitted. + */ + pgm_spinlock_lock (&sock->txw_spinlock); + struct pgm_sk_buff_t* skb = pgm_txw_retransmit_try_peek (sock->window); + if (skb) { + skb = pgm_skb_get (skb); + pgm_spinlock_unlock (&sock->txw_spinlock); + if (!send_rdata (sock, skb)) { + pgm_free_skb (skb); + pgm_notify_send (&sock->rdata_notify); + return FALSE; + } + pgm_free_skb (skb); +/* now remove sequence number from retransmit queue, re-enabling NAK processing for this sequence number */ + pgm_txw_retransmit_remove_head (sock->window); + } else + pgm_spinlock_unlock (&sock->txw_spinlock); + return TRUE; +} + +/* SPMR indicates if multicast to cancel own SPMR, or unicast to send SPM. + * + * rate limited to 1/IHB_MIN per TSI (13.4). + * + * if SPMR was valid, returns TRUE, if invalid returns FALSE. + */ + +bool +pgm_on_spmr ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict peer, /* maybe NULL if socket is source */ + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_spmr (sock:%p peer:%p skb:%p)", + (void*)sock, (void*)peer, (void*)skb); + + if (PGM_UNLIKELY(!pgm_verify_spmr (skb))) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed SPMR rejected.")); + return FALSE; + } + + if (peer_is_source (peer)) { + const bool send_status = pgm_send_spm (sock, 0); + if (PGM_UNLIKELY(!send_status)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Failed to send SPM on SPM-Request.")); + } + } else { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Suppressing SPMR due to peer multicast SPMR.")); + reset_spmr_timer (peer); + } + return TRUE; +} + +/* Process opt_pgmcc_feedback PGM option that ships attached to ACK or NAK. + * Contents use to elect best ACKer. + * + * returns TRUE if peer is the elected ACKer. + */ + +static +bool +on_opt_pgmcc_feedback ( + pgm_sock_t* const restrict sock, + const struct pgm_sk_buff_t* const restrict skb, + const struct pgm_opt_pgmcc_feedback* restrict opt_pgmcc_feedback + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + pgm_assert (NULL != opt_pgmcc_feedback); + + const uint32_t opt_tstamp = ntohl (opt_pgmcc_feedback->opt_tstamp); + const uint16_t opt_loss_rate = ntohs (opt_pgmcc_feedback->opt_loss_rate); + + const uint32_t rtt = pgm_to_msecs (skb->tstamp) - opt_tstamp; + const uint64_t peer_loss = rtt * rtt * opt_loss_rate; + + struct sockaddr_storage peer_nla; + pgm_nla_to_sockaddr (&opt_pgmcc_feedback->opt_nla_afi, (struct sockaddr*)&peer_nla); + +/* ACKer elections */ + if (PGM_UNLIKELY(pgm_sockaddr_is_addr_unspecified ((const struct sockaddr*)&sock->acker_nla))) + { + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Elected first ACKer")); + memcpy (&sock->acker_nla, &peer_nla, pgm_sockaddr_storage_len (&peer_nla)); + } + else if (peer_loss > sock->acker_loss && + 0 != pgm_sockaddr_cmp ((const struct sockaddr*)&peer_nla, (const struct sockaddr*)&sock->acker_nla)) + { + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Elected new ACKer")); + memcpy (&sock->acker_nla, &peer_nla, pgm_sockaddr_storage_len (&peer_nla)); + } + +/* update ACKer state */ + if (0 == pgm_sockaddr_cmp ((const struct sockaddr*)&peer_nla, (const struct sockaddr*)&sock->acker_nla)) + { + sock->acker_loss = peer_loss; + return TRUE; + } + + return FALSE; +} + +/* NAK requesting RDATA transmission for a sending sock, only valid if + * sequence number(s) still in transmission window. + * + * we can potentially have different IP versions for the NAK packet to the send group. + * + * TODO: fix IPv6 AFIs + * + * take in a NAK and pass off to an asynchronous queue for another thread to process + * + * if NAK is valid, returns TRUE. on error, FALSE is returned. + */ + +bool +pgm_on_nak ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_nak (sock:%p skb:%p)", + (const void*)sock, (const void*)skb); + + const bool is_parity = skb->pgm_header->pgm_options & PGM_OPT_PARITY; + if (is_parity) { + sock->cumulative_stats[PGM_PC_SOURCE_PARITY_NAKS_RECEIVED]++; + if (!sock->use_ondemand_parity) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Parity NAK rejected as on-demand parity is not enabled.")); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } + } else + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED]++; + + if (PGM_UNLIKELY(!pgm_verify_nak (skb))) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected.")); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } + + const struct pgm_nak* nak = (struct pgm_nak*) skb->data; + const struct pgm_nak6* nak6 = (struct pgm_nak6*)skb->data; + +/* NAK_SRC_NLA contains our sock unicast NLA */ + struct sockaddr_storage nak_src_nla; + pgm_nla_to_sockaddr (&nak->nak_src_nla_afi, (struct sockaddr*)&nak_src_nla); + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nak_src_nla, (struct sockaddr*)&sock->send_addr) != 0)) + { + char saddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&nak_src_nla, saddr, sizeof(saddr)); + pgm_trace (PGM_LOG_ROLE_NETWORK,_("NAK rejected for unmatched NLA: %s"), saddr); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } + +/* NAK_GRP_NLA containers our sock multicast group */ + struct sockaddr_storage nak_grp_nla; + pgm_nla_to_sockaddr ((AF_INET6 == nak_src_nla.ss_family) ? &nak6->nak6_grp_nla_afi : &nak->nak_grp_nla_afi, (struct sockaddr*)&nak_grp_nla); + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nak_grp_nla, (struct sockaddr*)&sock->send_gsr.gsr_group) != 0)) + { + char sgroup[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&nak_src_nla, sgroup, sizeof(sgroup)); + pgm_trace (PGM_LOG_ROLE_NETWORK,_("NAK rejected as targeted for different multicast group: %s"), sgroup); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } + +/* create queue object */ + struct pgm_sqn_list_t sqn_list; + sqn_list.sqn[0] = ntohl (nak->nak_sqn); + sqn_list.len = 1; + + pgm_debug ("nak_sqn %" PRIu32, sqn_list.sqn[0]); + +/* check NAK list */ + const uint32_t* nak_list = NULL; + uint_fast8_t nak_list_len = 0; + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) + { + const struct pgm_opt_length* opt_len = (AF_INET6 == nak_src_nla.ss_family) ? + (const struct pgm_opt_length*)(nak6 + 1) : + (const struct pgm_opt_length*)(nak + 1); + if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected.")); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } + if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected.")); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } +/* TODO: check for > 16 options & past packet end */ + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); + if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_NAK_LIST) { + nak_list = ((const struct pgm_opt_nak_list*)(opt_header + 1))->opt_sqn; + nak_list_len = ( opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(uint8_t) ) / sizeof(uint32_t); + break; + } + } while (!(opt_header->opt_type & PGM_OPT_END)); + } + +/* nak list numbers */ + if (PGM_UNLIKELY(nak_list_len > 63)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected on too long sequence list.")); + return FALSE; + } + + for (uint_fast8_t i = 0; i < nak_list_len; i++) + { + sqn_list.sqn[sqn_list.len++] = ntohl (*nak_list); + nak_list++; + } + +/* send NAK confirm packet immediately, then defer to timer thread for a.s.a.p + * delivery of the actual RDATA packets. blocking send for NCF is ignored as RDATA + * broadcast will be sent later. + */ + if (nak_list_len) + send_ncf_list (sock, (struct sockaddr*)&nak_src_nla, (struct sockaddr*)&nak_grp_nla, &sqn_list, is_parity); + else + send_ncf (sock, (struct sockaddr*)&nak_src_nla, (struct sockaddr*)&nak_grp_nla, sqn_list.sqn[0], is_parity); + +/* queue retransmit requests */ + for (uint_fast8_t i = 0; i < sqn_list.len; i++) { + const bool push_status = pgm_txw_retransmit_push (sock->window, sqn_list.sqn[i], is_parity, sock->tg_sqn_shift); + if (PGM_UNLIKELY(!push_status)) { + pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Failed to push retransmit request for #%" PRIu32), sqn_list.sqn[i]); + } + } + return TRUE; +} + +/* Null-NAK, or N-NAK propogated by a DLR for hand waving excitement + * + * if NNAK is valid, returns TRUE. on error, FALSE is returned. + */ + +bool +pgm_on_nnak ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_nnak (sock:%p skb:%p)", + (void*)sock, (void*)skb); + + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED]++; + + if (PGM_UNLIKELY(!pgm_verify_nnak (skb))) { + sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; + return FALSE; + } + + const struct pgm_nak* nnak = (struct pgm_nak*) skb->data; + const struct pgm_nak6* nnak6 = (struct pgm_nak6*)skb->data; + +/* NAK_SRC_NLA contains our sock unicast NLA */ + struct sockaddr_storage nnak_src_nla; + pgm_nla_to_sockaddr (&nnak->nak_src_nla_afi, (struct sockaddr*)&nnak_src_nla); + + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nnak_src_nla, (struct sockaddr*)&sock->send_addr) != 0)) + { + sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; + return FALSE; + } + +/* NAK_GRP_NLA containers our sock multicast group */ + struct sockaddr_storage nnak_grp_nla; + pgm_nla_to_sockaddr ((AF_INET6 == nnak_src_nla.ss_family) ? &nnak6->nak6_grp_nla_afi : &nnak->nak_grp_nla_afi, (struct sockaddr*)&nnak_grp_nla); + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nnak_grp_nla, (struct sockaddr*)&sock->send_gsr.gsr_group) != 0)) + { + sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; + return FALSE; + } + +/* check NNAK list */ + uint_fast8_t nnak_list_len = 0; + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) + { + const struct pgm_opt_length* opt_len = (AF_INET6 == nnak_src_nla.ss_family) ? + (const struct pgm_opt_length*)(nnak6 + 1) : + (const struct pgm_opt_length*)(nnak + 1); + if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) { + sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; + return FALSE; + } + if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) { + sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; + return FALSE; + } +/* TODO: check for > 16 options & past packet end */ + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); + if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_NAK_LIST) { + nnak_list_len = ( opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(uint8_t) ) / sizeof(uint32_t); + break; + } + } while (!(opt_header->opt_type & PGM_OPT_END)); + } + + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED] += 1 + nnak_list_len; + return TRUE; +} + +/* ACK, sent upstream by one selected ACKER for congestion control feedback. + * + * if ACK is valid, returns TRUE. on error, FALSE is returned. + */ + +bool +pgm_on_ack ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_ack (sock:%p skb:%p)", + (const void*)sock, (const void*)skb); + + sock->cumulative_stats[PGM_PC_SOURCE_ACK_PACKETS_RECEIVED]++; + + if (PGM_UNLIKELY(!pgm_verify_ack (skb))) { + sock->cumulative_stats[PGM_PC_SOURCE_ACK_ERRORS]++; + return FALSE; + } + + if (!sock->use_pgmcc) + return FALSE; + + const struct pgm_ack* ack = (struct pgm_ack*)skb->data; + bool is_acker = FALSE; + +/* check PGMCC feedback option for new elections */ + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) + { + const struct pgm_opt_length* opt_len = (const struct pgm_opt_length*)(ack + 1); + if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed ACK rejected.")); + return FALSE; + } + if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed ACK rejected.")); + return FALSE; + } + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); + if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_PGMCC_FEEDBACK) { + const struct pgm_opt_pgmcc_feedback* opt_pgmcc_feedback = (const struct pgm_opt_pgmcc_feedback*)(opt_header + 1); + is_acker = on_opt_pgmcc_feedback (sock, skb, opt_pgmcc_feedback); + break; /* ignore other options */ + } + } while (!(opt_header->opt_type & PGM_OPT_END)); + } + +/* ignore ACKs from other receivers or sessions */ + if (!is_acker) + return TRUE; + +/* reset ACK expiration */ + sock->next_crqst = 0; + +/* count new ACK sequences */ + const uint32_t ack_rx_max = ntohl (ack->ack_rx_max); + const int32_t delta = ack_rx_max - sock->ack_rx_max; +/* ignore older ACKs when multiple active ACKers */ + if (pgm_uint32_gt (ack_rx_max, sock->ack_rx_max)) + sock->ack_rx_max = ack_rx_max; + uint32_t ack_bitmap = ntohl (ack->ack_bitmap); + if (delta > 32) sock->ack_bitmap = 0; /* sequence jump ahead beyond past bitmap */ + else if (delta > 0) sock->ack_bitmap <<= delta; /* immediate sequence */ + else if (delta > -32) ack_bitmap <<= -delta; /* repair sequence scoped by bitmap */ + else ack_bitmap = 0; /* old sequence */ + unsigned new_acks = _pgm_popcount (ack_bitmap & ~sock->ack_bitmap); + sock->ack_bitmap |= ack_bitmap; + + if (0 == new_acks) + return TRUE; + + const bool is_congestion_limited = (sock->tokens < pgm_fp8 (1)); + +/* after loss detection cancel any further manipulation of the window + * until feedback is received for the next transmitted packet. + */ + if (sock->is_congested) + { + if (pgm_uint32_lte (ack_rx_max, sock->suspended_sqn)) + { + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC window token manipulation suspended due to congestion (T:%u W:%u)"), + pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); + const uint_fast32_t token_inc = pgm_fp8mul (pgm_fp8 (new_acks), pgm_fp8 (1) + pgm_fp8div (pgm_fp8 (1), sock->cwnd_size)); + sock->tokens = MIN( sock->tokens + token_inc, sock->cwnd_size ); + goto notify_tx; + } + sock->is_congested = FALSE; + } + +/* count outstanding lost sequences */ + const unsigned total_lost = _pgm_popcount (~sock->ack_bitmap); + +/* no detected data loss at ACKer, increase congestion window size */ + if (0 == total_lost) + { + new_acks += sock->acks_after_loss; + sock->acks_after_loss = 0; + uint_fast32_t n = pgm_fp8 (new_acks); + uint_fast32_t token_inc = 0; + +/* slow-start phase, exponential increase to SSTHRESH */ + if (sock->cwnd_size < sock->ssthresh) { + const uint_fast32_t d = MIN( n, sock->ssthresh - sock->cwnd_size ); + n -= d; + token_inc = d + d; + sock->cwnd_size += d; + } + + const uint_fast32_t iw = pgm_fp8div (pgm_fp8 (1), sock->cwnd_size); + +/* linear window increase */ + token_inc += pgm_fp8mul (n, pgm_fp8 (1) + iw); + sock->cwnd_size += pgm_fp8mul (n, iw); + sock->tokens = MIN( sock->tokens + token_inc, sock->cwnd_size ); +// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC++ (T:%u W:%u)"), +// pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); + } + else + { +/* Look for an unacknowledged data packet which is followed by at least three + * acknowledged data packets, then the packet is assumed to be lost and PGMCC + * reacts by halving the window. + * + * Common value will be 0xfffffff7. + */ + sock->acks_after_loss += new_acks; + if (sock->acks_after_loss >= 3) + { + sock->acks_after_loss = 0; + sock->suspended_sqn = ack_rx_max; + sock->is_congested = TRUE; + sock->cwnd_size = pgm_fp8div (sock->cwnd_size, pgm_fp8 (2)); + if (sock->cwnd_size > sock->tokens) + sock->tokens = 0; + else + sock->tokens -= sock->cwnd_size; + sock->ack_bitmap = 0xffffffff; + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC congestion, half window size (T:%u W:%u)"), + pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); + } + } + +/* token is now available so notify tx thread that transmission time is available */ +notify_tx: + if (is_congestion_limited && + sock->tokens >= pgm_fp8 (1)) + { + pgm_notify_send (&sock->ack_notify); + } + return TRUE; +} + +/* ambient/heartbeat SPM's + * + * heartbeat: ihb_tmr decaying between ihb_min and ihb_max 2x after last packet + * + * on success, TRUE is returned, if operation would block, FALSE is returned. + */ + +bool +pgm_send_spm ( + pgm_sock_t* const sock, + const int flags + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != sock->window); + + pgm_debug ("pgm_send_spm (sock:%p flags:%d)", + (const void*)sock, flags); + + size_t tpdu_length = sizeof(struct pgm_header); + if (AF_INET == sock->send_gsr.gsr_group.ss_family) + tpdu_length += sizeof(struct pgm_spm); + else + tpdu_length += sizeof(struct pgm_spm6); + if (sock->use_proactive_parity || + sock->use_ondemand_parity || + sock->is_pending_crqst || + PGM_OPT_FIN == flags) + { + tpdu_length += sizeof(struct pgm_opt_length); +/* forward error correction */ + if (sock->use_proactive_parity || + sock->use_ondemand_parity) + tpdu_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_parity_prm); +/* congestion report request */ + if (sock->is_pending_crqst) + tpdu_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_crqst); +/* end of session */ + if (PGM_OPT_FIN == flags) + tpdu_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fin); + } + char buf[ tpdu_length ]; + if (PGM_UNLIKELY(pgm_mem_gc_friendly)) + memset (buf, 0, tpdu_length); + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_spm* spm = (struct pgm_spm *)(header + 1); + struct pgm_spm6* spm6 = (struct pgm_spm6*)(header + 1); + memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + header->pgm_sport = sock->tsi.sport; + header->pgm_dport = sock->dport; + header->pgm_type = PGM_SPM; + header->pgm_options = 0; + header->pgm_tsdu_length = 0; + +/* SPM */ + spm->spm_sqn = htonl (sock->spm_sqn); + spm->spm_trail = htonl (pgm_txw_trail_atomic (sock->window)); + spm->spm_lead = htonl (pgm_txw_lead_atomic (sock->window)); + spm->spm_reserved = 0; +/* our nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->send_addr, (char*)&spm->spm_nla_afi); + +/* PGM options */ + if (sock->use_proactive_parity || + sock->use_ondemand_parity || + sock->is_pending_crqst || + PGM_OPT_FIN == flags) + { + struct pgm_opt_length* opt_len; + struct pgm_opt_header *opt_header, *last_opt_header; + uint16_t opt_total_length; + + if (AF_INET == sock->send_gsr.gsr_group.ss_family) + opt_header = (struct pgm_opt_header*)(spm + 1); + else + opt_header = (struct pgm_opt_header*)(spm6 + 1); + header->pgm_options |= PGM_OPT_PRESENT; + opt_len = (struct pgm_opt_length*)opt_header; + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_total_length = sizeof(struct pgm_opt_length); + last_opt_header = opt_header = (struct pgm_opt_header*)(opt_len + 1); + +/* OPT_PARITY_PRM */ + if (sock->use_proactive_parity || + sock->use_ondemand_parity) + { + header->pgm_options |= PGM_OPT_NETWORK; + opt_total_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_parity_prm); + opt_header->opt_type = PGM_OPT_PARITY_PRM; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_parity_prm); + struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1); + opt_parity_prm->opt_reserved = (sock->use_proactive_parity ? PGM_PARITY_PRM_PRO : 0) | + (sock->use_ondemand_parity ? PGM_PARITY_PRM_OND : 0); + opt_parity_prm->parity_prm_tgs = htonl (sock->rs_k); + last_opt_header = opt_header; + opt_header = (struct pgm_opt_header*)(opt_parity_prm + 1); + } + +/* OPT_CRQST */ + if (sock->is_pending_crqst) + { + header->pgm_options |= PGM_OPT_NETWORK; + opt_total_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_crqst); + opt_header->opt_type = PGM_OPT_CRQST; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_crqst); + struct pgm_opt_crqst* opt_crqst = (struct pgm_opt_crqst*)(opt_header + 1); +/* request receiver worst path report, OPT_CR_RX_WP */ + opt_crqst->opt_reserved = PGM_OPT_CRQST_RXP; + sock->is_pending_crqst = FALSE; + last_opt_header = opt_header; + opt_header = (struct pgm_opt_header*)(opt_crqst + 1); + } + +/* OPT_FIN */ + if (PGM_OPT_FIN == flags) + { + opt_total_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fin); + opt_header->opt_type = PGM_OPT_FIN; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fin); + struct pgm_opt_fin* opt_fin = (struct pgm_opt_fin*)(opt_header + 1); + opt_fin->opt_reserved = 0; + last_opt_header = opt_header; + opt_header = (struct pgm_opt_header*)(opt_fin + 1); + } + + last_opt_header->opt_type |= PGM_OPT_END; + opt_len->opt_total_length = htons (opt_total_length); + } + +/* checksum optional for SPMs */ + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + + const ssize_t sent = pgm_sendto (sock, + flags != PGM_OPT_SYN && sock->is_controlled_spm, /* rate limited */ + TRUE, /* with router alert */ + buf, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->blocklen = tpdu_length; + return FALSE; + } +/* advance SPM sequence only on successful transmission */ + sock->spm_sqn++; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); + return TRUE; +} + +/* send a NAK confirm (NCF) message with provided sequence number list. + * + * on success, TRUE is returned, returns FALSE if operation would block. + */ + +static +bool +send_ncf ( + pgm_sock_t* const restrict sock, + const struct sockaddr* const restrict nak_src_nla, + const struct sockaddr* const restrict nak_grp_nla, + const uint32_t sequence, + const bool is_parity /* send parity NCF */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != nak_src_nla); + pgm_assert (NULL != nak_grp_nla); + pgm_assert (nak_src_nla->sa_family == nak_grp_nla->sa_family); + +#ifdef SOURCE_DEBUG + char saddr[INET6_ADDRSTRLEN], gaddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop (nak_src_nla, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (nak_grp_nla, gaddr, sizeof(gaddr)); + pgm_debug ("send_ncf (sock:%p nak-src-nla:%s nak-grp-nla:%s sequence:%" PRIu32" is-parity:%s)", + (void*)sock, + saddr, + gaddr, + sequence, + is_parity ? "TRUE": "FALSE" + ); +#endif + + size_t tpdu_length = sizeof(struct pgm_header); + tpdu_length += (AF_INET == nak_src_nla->sa_family) ? sizeof(struct pgm_nak) : sizeof(struct pgm_nak6); + char buf[ tpdu_length ]; + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* ncf = (struct pgm_nak *)(header + 1); + struct pgm_nak6* ncf6 = (struct pgm_nak6*)(header + 1); + memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + header->pgm_sport = sock->tsi.sport; + header->pgm_dport = sock->dport; + header->pgm_type = PGM_NCF; + header->pgm_options = is_parity ? PGM_OPT_PARITY : 0; + header->pgm_tsdu_length = 0; + +/* NCF */ + ncf->nak_sqn = htonl (sequence); + +/* source nla */ + pgm_sockaddr_to_nla (nak_src_nla, (char*)&ncf->nak_src_nla_afi); + +/* group nla */ + pgm_sockaddr_to_nla (nak_grp_nla, (AF_INET6 == nak_src_nla->sa_family) ? (char*)&ncf6->nak6_grp_nla_afi : (char*)&ncf->nak_grp_nla_afi ); + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + TRUE, /* with router alert */ + buf, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) + return FALSE; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); + return TRUE; +} + +/* A NCF packet with a OPT_NAK_LIST option extension + * + * on success, TRUE is returned. on error, FALSE is returned. + */ + +static +bool +send_ncf_list ( + pgm_sock_t* const restrict sock, + const struct sockaddr* const restrict nak_src_nla, + const struct sockaddr* const restrict nak_grp_nla, + struct pgm_sqn_list_t* const restrict sqn_list, /* will change to network-order */ + const bool is_parity /* send parity NCF */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != nak_src_nla); + pgm_assert (NULL != nak_grp_nla); + pgm_assert (sqn_list->len > 1); + pgm_assert (sqn_list->len <= 63); + pgm_assert (nak_src_nla->sa_family == nak_grp_nla->sa_family); + +#ifdef SOURCE_DEBUG + char saddr[INET6_ADDRSTRLEN], gaddr[INET6_ADDRSTRLEN]; + char list[1024]; + pgm_sockaddr_ntop (nak_src_nla, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (nak_grp_nla, gaddr, sizeof(gaddr)); + sprintf (list, "%" PRIu32, sqn_list->sqn[0]); + for (uint_fast8_t i = 1; i < sqn_list->len; i++) { + char sequence[ 2 + strlen("4294967295") ]; + sprintf (sequence, " %" PRIu32, sqn_list->sqn[i]); + strcat (list, sequence); + } + pgm_debug ("send_ncf_list (sock:%p nak-src-nla:%s nak-grp-nla:%s sqn-list:[%s] is-parity:%s)", + (void*)sock, + saddr, + gaddr, + list, + is_parity ? "TRUE": "FALSE" + ); +#endif + + size_t tpdu_length = sizeof(struct pgm_header) + + sizeof(struct pgm_opt_length) + /* includes header */ + sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ); + tpdu_length += (AF_INET == nak_src_nla->sa_family) ? sizeof(struct pgm_nak) : sizeof(struct pgm_nak6); + char buf[ tpdu_length ]; + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* ncf = (struct pgm_nak *)(header + 1); + struct pgm_nak6* ncf6 = (struct pgm_nak6*)(header + 1); + memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + header->pgm_sport = sock->tsi.sport; + header->pgm_dport = sock->dport; + header->pgm_type = PGM_NCF; + header->pgm_options = is_parity ? (PGM_OPT_PRESENT | PGM_OPT_NETWORK | PGM_OPT_PARITY) : (PGM_OPT_PRESENT | PGM_OPT_NETWORK); + header->pgm_tsdu_length = 0; +/* NCF */ + ncf->nak_sqn = htonl (sqn_list->sqn[0]); + +/* source nla */ + pgm_sockaddr_to_nla (nak_src_nla, (char*)&ncf->nak_src_nla_afi); + +/* group nla */ + pgm_sockaddr_to_nla (nak_grp_nla, (AF_INET6 == nak_src_nla->sa_family) ? (char*)&ncf6->nak6_grp_nla_afi : (char*)&ncf->nak_grp_nla_afi ); + +/* OPT_NAK_LIST */ + struct pgm_opt_length* opt_len = (AF_INET6 == nak_src_nla->sa_family) ? (struct pgm_opt_length*)(ncf6 + 1) : (struct pgm_opt_length*)(ncf + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ); + struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); + opt_nak_list->opt_reserved = 0; +/* to network-order */ + for (uint_fast8_t i = 1; i < sqn_list->len; i++) + opt_nak_list->opt_sqn[i-1] = htonl (sqn_list->sqn[i]); + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + TRUE, /* with router alert */ + buf, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) + return FALSE; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); + return TRUE; +} + +/* cancel any pending heartbeat SPM and schedule a new one + */ + +static +void +reset_heartbeat_spm ( + pgm_sock_t*const sock, + const pgm_time_t now + ) +{ + pgm_mutex_lock (&sock->timer_mutex); + const pgm_time_t next_poll = sock->next_poll; + const pgm_time_t spm_heartbeat_interval = sock->spm_heartbeat_interval[ sock->spm_heartbeat_state = 1 ]; + sock->next_heartbeat_spm = now + spm_heartbeat_interval; + if (pgm_time_after( next_poll, sock->next_heartbeat_spm )) + { + sock->next_poll = sock->next_heartbeat_spm; + if (!sock->is_pending_read) { + pgm_notify_send (&sock->pending_notify); + sock->is_pending_read = TRUE; + } + } + pgm_mutex_unlock (&sock->timer_mutex); +} + +/* state helper for resuming sends + */ +#define STATE(x) (sock->pkt_dontwait_state.x) + +/* send one PGM data packet, transmit window owned memory. + * + * On success, returns PGM_IO_STATUS_NORMAL and the number of data bytes pushed + * into the transmit window and attempted to send to the socket layer is saved + * into bytes_written. On non-blocking sockets, PGM_IO_STATUS_WOULD_BLOCK is + * returned if the send would block. PGM_IO_STATUS_RATE_LIMITED is returned if + * the packet sizes would exceed the current rate limit. + * + * ! always returns successful if data is pushed into the transmit window, even if + * sendto() double fails ¡ we don't want the application to try again as that is the + * reliable socks role. + */ + +static +int +send_odata ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb, + size_t* restrict bytes_written + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + pgm_assert (skb->len <= sock->max_tsdu); + + pgm_debug ("send_odata (sock:%p skb:%p bytes-written:%p)", + (void*)sock, (void*)skb, (void*)bytes_written); + + const uint16_t tsdu_length = skb->len; + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + const size_t tpdu_length = tsdu_length + pgm_pkt_offset (FALSE, pgmcc_family); + +/* continue if send would block */ + if (sock->is_apdu_eagain) { + STATE(skb)->tstamp = pgm_time_update_now(); + goto retry_send; + } + +/* add PGM header to skbuff */ + STATE(skb) = pgm_skb_get(skb); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = sock->use_pgmcc ? PGM_OPT_PRESENT : 0; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (tsdu_length); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + STATE(skb)->pgm_header->pgm_checksum = 0; + void* data = STATE(skb)->pgm_data + 1; + if (sock->use_pgmcc) { + struct pgm_opt_length* opt_len = data; + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_PGMCC_DATA | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)); + struct pgm_opt_pgmcc_data* pgmcc_data = (struct pgm_opt_pgmcc_data*)(opt_header + 1); + struct pgm_opt6_pgmcc_data* pgmcc_data6 = (struct pgm_opt6_pgmcc_data*)(opt_header + 1); + + pgmcc_data->opt_tstamp = htonl (pgm_to_msecs (STATE(skb)->tstamp)); +/* acker nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->acker_nla, (char*)&pgmcc_data->opt_nla_afi); + if (AF_INET6 == sock->acker_nla.ss_family) + data = (char*)pgmcc_data6 + sizeof(struct pgm_opt6_pgmcc_data); + else + data = (char*)pgmcc_data + sizeof(struct pgm_opt_pgmcc_data); + } + const size_t pgm_header_len = (char*)data - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial (data, tsdu_length, 0); + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + +/* the transmit window MUST check the user count to ensure it does not + * attempt to send a repair-data packet based on in transit original data. + */ + + ssize_t sent; +retry_send: + +/* congestion control */ + if (sock->use_pgmcc && + sock->tokens < pgm_fp8 (1)) + { +// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Token limit reached.")); + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + return PGM_IO_STATUS_CONGESTION; /* peer expiration to re-elect ACKer */ + } + + sent = pgm_sendto (sock, + sock->is_controlled_odata, /* rate limited */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + if (sock->use_pgmcc) { + sock->tokens -= pgm_fp8 (1); + sock->ack_expiry = STATE(skb)->tstamp + sock->ack_expiry_ivl; + } + + if (PGM_LIKELY((size_t)sent == tpdu_length)) { + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += tsdu_length; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] ++; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); + } + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + +/* remove applications reference to skbuff */ + pgm_free_skb (STATE(skb)); + if (bytes_written) + *bytes_written = tsdu_length; + return PGM_IO_STATUS_NORMAL; +} + +/* send one PGM original data packet, callee owned memory. + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ + +static +int +send_odata_copy ( + pgm_sock_t* const restrict sock, + const void* restrict tsdu, + const uint16_t tsdu_length, + size_t* restrict bytes_written + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (tsdu_length <= sock->max_tsdu); + if (PGM_LIKELY(tsdu_length)) pgm_assert (NULL != tsdu); + + pgm_debug ("send_odata_copy (sock:%p tsdu:%p tsdu_length:%u bytes-written:%p)", + (void*)sock, tsdu, tsdu_length, (void*)bytes_written); + + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + const size_t tpdu_length = tsdu_length + pgm_pkt_offset (FALSE, pgmcc_family); + +/* continue if blocked mid-apdu, updating timestamp */ + if (sock->is_apdu_eagain) { + STATE(skb)->tstamp = pgm_time_update_now(); + goto retry_send; + } + + STATE(skb) = pgm_alloc_skb (sock->max_tpdu); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + pgm_skb_reserve (STATE(skb), pgm_pkt_offset (FALSE, pgmcc_family)); + pgm_skb_put (STATE(skb), tsdu_length); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = sock->use_pgmcc ? PGM_OPT_PRESENT : 0; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (tsdu_length); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + STATE(skb)->pgm_header->pgm_checksum = 0; + void* data = STATE(skb)->pgm_data + 1; + if (sock->use_pgmcc) { + struct pgm_opt_length* opt_len = data; + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_PGMCC_DATA | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)); + struct pgm_opt_pgmcc_data* pgmcc_data = (struct pgm_opt_pgmcc_data*)(opt_header + 1); +/* unused */ +// struct pgm_opt6_pgmcc_data* pgmcc_data6 = (struct pgm_opt6_pgmcc_data*)(opt_header + 1); + + pgmcc_data->opt_reserved = 0; + pgmcc_data->opt_tstamp = htonl (pgm_to_msecs (STATE(skb)->tstamp)); +/* acker nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->acker_nla, (char*)&pgmcc_data->opt_nla_afi); + data = (char*)opt_header + opt_header->opt_length; + } + const size_t pgm_header_len = (char*)data - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial_copy (tsdu, data, tsdu_length, 0); + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + + ssize_t sent; +retry_send: + +/* congestion control */ + if (sock->use_pgmcc && + sock->tokens < pgm_fp8 (1)) + { +// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Token limit reached.")); + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + return PGM_IO_STATUS_CONGESTION; + } + + sent = pgm_sendto (sock, + sock->is_controlled_odata, /* rate limited */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; + } + + if (sock->use_pgmcc) { + sock->tokens -= pgm_fp8 (1); + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC tokens-- (T:%u W:%u)"), + pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); + sock->ack_expiry = STATE(skb)->tstamp + sock->ack_expiry_ivl; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + + if (PGM_LIKELY((size_t)sent == tpdu_length)) { + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += tsdu_length; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] ++; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); + } + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + +/* return data payload length sent */ + if (bytes_written) + *bytes_written = tsdu_length; + return PGM_IO_STATUS_NORMAL; +} + +/* send one PGM original data packet, callee owned scatter/gather io vector + * + * ⎢ DATA₀ ⎢ + * ⎢ DATA₁ ⎢ → send_odatav() → ⎢ TSDU₀ ⎢ → libc + * ⎢ ⋮ ⎢ + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ + +static +int +send_odatav ( + pgm_sock_t* const restrict sock, + const struct pgm_iovec* const restrict vector, + const unsigned count, /* number of items in vector */ + size_t* restrict bytes_written + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (count <= PGM_MAX_FRAGMENTS); + if (PGM_LIKELY(count)) pgm_assert (NULL != vector); + + pgm_debug ("send_odatav (sock:%p vector:%p count:%u bytes-written:%p)", + (const void*)sock, (const void*)vector, count, (const void*)bytes_written); + + if (PGM_UNLIKELY(0 == count)) + return send_odata_copy (sock, NULL, 0, bytes_written); + +/* continue if blocked on send */ + if (sock->is_apdu_eagain) + goto retry_send; + + STATE(tsdu_length) = 0; + for (unsigned i = 0; i < count; i++) + { +#ifdef TRANSPORT_DEBUG + if (PGM_LIKELY(vector[i].iov_len)) { + pgm_assert( vector[i].iov_base ); + } +#endif + STATE(tsdu_length) += vector[i].iov_len; + } + pgm_return_val_if_fail (STATE(tsdu_length) <= sock->max_tsdu, PGM_IO_STATUS_ERROR); + + STATE(skb) = pgm_alloc_skb (sock->max_tpdu); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + pgm_skb_reserve (STATE(skb), pgm_pkt_offset (FALSE, pgmcc_family)); + pgm_skb_put (STATE(skb), STATE(tsdu_length)); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->data; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = 0; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + STATE(skb)->pgm_header->pgm_checksum = 0; + const size_t pgm_header_len = (char*)(STATE(skb)->pgm_data + 1) - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + +/* unroll first iteration to make friendly branch prediction */ + char* dst = (char*)(STATE(skb)->pgm_data + 1); + STATE(unfolded_odata) = pgm_csum_partial_copy ((const char*)vector[0].iov_base, dst, vector[0].iov_len, 0); + +/* iterate over one or more vector elements to perform scatter/gather checksum & copy */ + for (unsigned i = 1; i < count; i++) { + dst += vector[i-1].iov_len; + const uint32_t unfolded_element = pgm_csum_partial_copy ((const char*)vector[i].iov_base, dst, vector[i].iov_len, 0); + STATE(unfolded_odata) = pgm_csum_block_add (STATE(unfolded_odata), unfolded_element, vector[i-1].iov_len); + } + + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + + ssize_t sent; + size_t tpdu_length; +retry_send: + pgm_assert ((char*)STATE(skb)->tail > (char*)STATE(skb)->head); + tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; + sent = pgm_sendto (sock, + sock->is_controlled_odata, /* rate limited */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + + if (PGM_LIKELY((size_t)sent == STATE(skb)->len)) { + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += STATE(tsdu_length); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] ++; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); + } + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + +/* return data payload length sent */ + if (bytes_written) + *bytes_written = STATE(tsdu_length); + return PGM_IO_STATUS_NORMAL; +} + +/* send PGM original data, callee owned memory. if larger than maximum TPDU + * size will be fragmented. + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ + +static +int +send_apdu ( + pgm_sock_t* const restrict sock, + const void* restrict apdu, + const size_t apdu_length, + size_t* restrict bytes_written + ) +{ + size_t bytes_sent = 0; /* counted at IP layer */ + unsigned packets_sent = 0; /* IP packets */ + size_t data_bytes_sent = 0; + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + + pgm_assert (NULL != sock); + pgm_assert (NULL != apdu); + +/* continue if blocked mid-apdu */ + if (sock->is_apdu_eagain) + goto retry_send; + +/* if non-blocking calculate total wire size and check rate limit */ + STATE(is_rate_limited) = FALSE; + if (sock->is_nonblocking && sock->is_controlled_odata) + { + const size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); + size_t tpdu_length = 0; + size_t offset_ = 0; + do { + const uint16_t tsdu_length = MIN( source_max_tsdu (sock, TRUE), apdu_length - offset_ ); + tpdu_length += sock->iphdr_len + header_length + tsdu_length; + offset_ += tsdu_length; + } while (offset_ < apdu_length); + +/* calculation includes one iphdr length already */ + if (!pgm_rate_check (&sock->rate_control, + tpdu_length - sock->iphdr_len, + sock->is_nonblocking)) + { + sock->blocklen = tpdu_length; + return PGM_IO_STATUS_RATE_LIMITED; + } + STATE(is_rate_limited) = TRUE; + } + + STATE(data_bytes_offset) = 0; + STATE(first_sqn) = pgm_txw_next_lead(sock->window); + + do { +/* retrieve packet storage from transmit window */ + size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); + STATE(tsdu_length) = MIN( source_max_tsdu (sock, TRUE), apdu_length - STATE(data_bytes_offset) ); + + STATE(skb) = pgm_alloc_skb (sock->max_tpdu); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + pgm_skb_reserve (STATE(skb), header_length); + pgm_skb_put (STATE(skb), STATE(tsdu_length)); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = PGM_OPT_PRESENT; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + +/* OPT_LENGTH */ + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(STATE(skb)->pgm_data + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment) ); +/* OPT_FRAGMENT */ + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment); + STATE(skb)->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + STATE(skb)->pgm_opt_fragment->opt_reserved = 0; + STATE(skb)->pgm_opt_fragment->opt_sqn = htonl (STATE(first_sqn)); + STATE(skb)->pgm_opt_fragment->opt_frag_off = htonl (STATE(data_bytes_offset)); + STATE(skb)->pgm_opt_fragment->opt_frag_len = htonl (apdu_length); + +/* TODO: the assembly checksum & copy routine is faster than memcpy & pgm_cksum on >= opteron hardware */ + STATE(skb)->pgm_header->pgm_checksum = 0; + const size_t pgm_header_len = (char*)(STATE(skb)->pgm_opt_fragment + 1) - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial_copy ((const char*)apdu + STATE(data_bytes_offset), STATE(skb)->pgm_opt_fragment + 1, STATE(tsdu_length), 0); + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + + ssize_t sent; + size_t tpdu_length; +retry_send: + pgm_assert ((char*)STATE(skb)->tail > (char*)STATE(skb)->head); + tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; + sent = pgm_sendto (sock, + !STATE(is_rate_limited), /* rate limit on blocking */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + goto blocked; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + if (PGM_LIKELY((size_t)sent == tpdu_length)) { + bytes_sent += tpdu_length + sock->iphdr_len; /* as counted at IP layer */ + packets_sent++; /* IP packets */ + data_bytes_sent += STATE(tsdu_length); + } + + STATE(data_bytes_offset) += STATE(tsdu_length); + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + + } while ( STATE(data_bytes_offset) < apdu_length); + pgm_assert( STATE(data_bytes_offset) == apdu_length ); + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + if (bytes_written) + *bytes_written = apdu_length; + return PGM_IO_STATUS_NORMAL; + +blocked: + if (bytes_sent) { + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + } + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; +} + +/* Send one APDU, whether it fits within one TPDU or more. + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ +int +pgm_send ( + pgm_sock_t* const restrict sock, + const void* restrict apdu, + const size_t apdu_length, + size_t* restrict bytes_written + ) +{ + pgm_debug ("pgm_send (sock:%p apdu:%p apdu-length:%zu bytes-written:%p)", + (void*)sock, apdu, apdu_length, (void*)bytes_written); + +/* parameters */ + pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); + if (PGM_LIKELY(apdu_length)) pgm_return_val_if_fail (NULL != apdu, PGM_IO_STATUS_ERROR); + +/* shutdown */ + if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + +/* state */ + if (PGM_UNLIKELY(!sock->is_bound || + sock->is_destroyed || + apdu_length > sock->max_apdu)) + { + pgm_rwlock_reader_unlock (&sock->lock); + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + } + +/* source */ + pgm_mutex_lock (&sock->source_mutex); + +/* pass on non-fragment calls */ + if (apdu_length <= sock->max_tsdu) + { + const int status = send_odata_copy (sock, apdu, apdu_length, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + + const int status = send_apdu (sock, apdu, apdu_length, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; +} + +/* send PGM original data, callee owned scatter/gather IO vector. if larger than maximum TPDU + * size will be fragmented. + * + * is_one_apdu = true: + * + * ⎢ DATA₀ ⎢ + * ⎢ DATA₁ ⎢ → pgm_sendv() → ⎢ ⋯ TSDU₁ TSDU₀ ⎢ → libc + * ⎢ ⋮ ⎢ + * + * is_one_apdu = false: + * + * ⎢ APDU₀ ⎢ ⎢ ⋯ TSDU₁,₀ TSDU₀,₀ ⎢ + * ⎢ APDU₁ ⎢ → pgm_sendv() → ⎢ ⋯ TSDU₁,₁ TSDU₀,₁ ⎢ → libc + * ⎢ ⋮ ⎢ ⎢ ⋮ ⋮ ⎢ + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ + +int +pgm_sendv ( + pgm_sock_t* const restrict sock, + const struct pgm_iovec* const restrict vector, + const unsigned count, /* number of items in vector */ + const bool is_one_apdu, /* true = vector = apdu, false = vector::iov_base = apdu */ + size_t* restrict bytes_written + ) +{ + pgm_debug ("pgm_sendv (sock:%p vector:%p count:%u is-one-apdu:%s bytes-written:%p)", + (const void*)sock, + (const void*)vector, + count, + is_one_apdu ? "TRUE" : "FALSE", + (const void*)bytes_written); + + pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); + pgm_return_val_if_fail (count <= PGM_MAX_FRAGMENTS, PGM_IO_STATUS_ERROR); + if (PGM_LIKELY(count)) pgm_return_val_if_fail (NULL != vector, PGM_IO_STATUS_ERROR); + if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + if (PGM_UNLIKELY(!sock->is_bound || + sock->is_destroyed)) + { + pgm_rwlock_reader_unlock (&sock->lock); + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + } + + pgm_mutex_lock (&sock->source_mutex); + +/* pass on zero length as cannot count vector lengths */ + if (PGM_UNLIKELY(0 == count)) + { + const int status = send_odata_copy (sock, NULL, count, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + + size_t bytes_sent = 0; + unsigned packets_sent = 0; + size_t data_bytes_sent = 0; + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + +/* continue if blocked mid-apdu */ + if (sock->is_apdu_eagain) { + if (is_one_apdu) { + if (STATE(apdu_length) <= sock->max_tsdu) + { + const int status = send_odatav (sock, vector, count, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + else + goto retry_one_apdu_send; + } else { + goto retry_send; + } + } + +/* calculate (total) APDU length */ + STATE(apdu_length) = 0; + for (unsigned i = 0; i < count; i++) + { +#ifdef TRANSPORT_DEBUG + if (PGM_LIKELY(vector[i].iov_len)) { + pgm_assert( vector[i].iov_base ); + } +#endif + if (!is_one_apdu && + vector[i].iov_len > sock->max_apdu) + { + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + } + STATE(apdu_length) += vector[i].iov_len; + } + +/* pass on non-fragment calls */ + if (is_one_apdu) { + if (STATE(apdu_length) <= sock->max_tsdu) { + const int status = send_odatav (sock, vector, count, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } else if (STATE(apdu_length) > sock->max_apdu) { + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + } + } + +/* if non-blocking calculate total wire size and check rate limit */ + STATE(is_rate_limited) = FALSE; + if (sock->is_nonblocking && sock->is_controlled_odata) + { + const size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); + size_t tpdu_length = 0; + size_t offset_ = 0; + do { + const uint16_t tsdu_length = MIN( source_max_tsdu (sock, TRUE), STATE(apdu_length) - offset_ ); + tpdu_length += sock->iphdr_len + header_length + tsdu_length; + offset_ += tsdu_length; + } while (offset_ < STATE(apdu_length)); + +/* calculation includes one iphdr length already */ + if (!pgm_rate_check (&sock->rate_control, + tpdu_length - sock->iphdr_len, + sock->is_nonblocking)) + { + sock->blocklen = tpdu_length; + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_RATE_LIMITED; + } + STATE(is_rate_limited) = TRUE; + } + +/* non-fragmented packets can be forwarded onto basic send() */ + if (!is_one_apdu) + { + for (STATE(data_pkt_offset) = 0; STATE(data_pkt_offset) < count; STATE(data_pkt_offset)++) + { + size_t wrote_bytes; + int status; +retry_send: + status = send_apdu (sock, + vector[STATE(data_pkt_offset)].iov_base, + vector[STATE(data_pkt_offset)].iov_len, + &wrote_bytes); + switch (status) { + case PGM_IO_STATUS_NORMAL: + break; + case PGM_IO_STATUS_WOULD_BLOCK: + case PGM_IO_STATUS_RATE_LIMITED: + sock->is_apdu_eagain = TRUE; + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + case PGM_IO_STATUS_ERROR: + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + default: + pgm_assert_not_reached(); + } + data_bytes_sent += wrote_bytes; + } + + sock->is_apdu_eagain = FALSE; + if (bytes_written) + *bytes_written = data_bytes_sent; + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_NORMAL; + } + + STATE(data_bytes_offset) = 0; + STATE(vector_index) = 0; + STATE(vector_offset) = 0; + + STATE(first_sqn) = pgm_txw_next_lead(sock->window); + + do { +/* retrieve packet storage from transmit window */ + size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); + STATE(tsdu_length) = MIN( source_max_tsdu (sock, TRUE), STATE(apdu_length) - STATE(data_bytes_offset) ); + STATE(skb) = pgm_alloc_skb (sock->max_tpdu); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + pgm_skb_reserve (STATE(skb), header_length); + pgm_skb_put (STATE(skb), STATE(tsdu_length)); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = PGM_OPT_PRESENT; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + +/* OPT_LENGTH */ + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(STATE(skb)->pgm_data + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment) ); +/* OPT_FRAGMENT */ + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment); + STATE(skb)->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + STATE(skb)->pgm_opt_fragment->opt_reserved = 0; + STATE(skb)->pgm_opt_fragment->opt_sqn = htonl (STATE(first_sqn)); + STATE(skb)->pgm_opt_fragment->opt_frag_off = htonl (STATE(data_bytes_offset)); + STATE(skb)->pgm_opt_fragment->opt_frag_len = htonl (STATE(apdu_length)); + +/* checksum & copy */ + STATE(skb)->pgm_header->pgm_checksum = 0; + const size_t pgm_header_len = (char*)(STATE(skb)->pgm_opt_fragment + 1) - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + +/* iterate over one or more vector elements to perform scatter/gather checksum & copy + * + * STATE(vector_index) - index into application scatter/gather vector + * STATE(vector_offset) - current offset into current vector element + * STATE(unfolded_odata)- checksum accumulator + */ + const char* src = (const char*)vector[STATE(vector_index)].iov_base + STATE(vector_offset); + char* dst = (char*)(STATE(skb)->pgm_opt_fragment + 1); + size_t src_length = vector[STATE(vector_index)].iov_len - STATE(vector_offset); + size_t dst_length = 0; + size_t copy_length = MIN( STATE(tsdu_length), src_length ); + STATE(unfolded_odata) = pgm_csum_partial_copy (src, dst, copy_length, 0); + + for(;;) + { + if (copy_length == src_length) { +/* application packet complete */ + STATE(vector_index)++; + STATE(vector_offset) = 0; + } else { +/* data still remaining */ + STATE(vector_offset) += copy_length; + } + + dst_length += copy_length; + +/* sock packet complete */ + if (dst_length == STATE(tsdu_length)) + break; + + src = (const char*)vector[STATE(vector_index)].iov_base + STATE(vector_offset); + dst += copy_length; + src_length = vector[STATE(vector_index)].iov_len - STATE(vector_offset); + copy_length = MIN( STATE(tsdu_length) - dst_length, src_length ); + const uint32_t unfolded_element = pgm_csum_partial_copy (src, dst, copy_length, 0); + STATE(unfolded_odata) = pgm_csum_block_add (STATE(unfolded_odata), unfolded_element, dst_length); + } + + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + + ssize_t sent; + size_t tpdu_length; +retry_one_apdu_send: + tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; + sent = pgm_sendto (sock, + !STATE(is_rate_limited), /* rate limited on blocking */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + goto blocked; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + if (PGM_LIKELY((size_t)sent == tpdu_length)) { + bytes_sent += tpdu_length + sock->iphdr_len; /* as counted at IP layer */ + packets_sent++; /* IP packets */ + data_bytes_sent += STATE(tsdu_length); + } + + STATE(data_bytes_offset) += STATE(tsdu_length); + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + + } while ( STATE(data_bytes_offset) < STATE(apdu_length) ); + pgm_assert( STATE(data_bytes_offset) == STATE(apdu_length) ); + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + if (bytes_written) + *bytes_written = STATE(apdu_length); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_NORMAL; + +blocked: + if (bytes_sent) { + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + } + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; +} + +/* send PGM original data, transmit window owned scatter/gather IO vector. + * + * ⎢ TSDU₀ ⎢ + * ⎢ TSDU₁ ⎢ → pgm_send_skbv() → ⎢ ⋯ TSDU₁ TSDU₀ ⎢ → libc + * ⎢ ⋮ ⎢ + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ + +int +pgm_send_skbv ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t** const restrict vector, /* array of skb pointers vs. array of skbs */ + const unsigned count, + const bool is_one_apdu, /* true: vector = apdu, false: vector::iov_base = apdu */ + size_t* restrict bytes_written + ) +{ + pgm_debug ("pgm_send_skbv (sock:%p vector:%p count:%u is-one-apdu:%s bytes-written:%p)", + (const void*)sock, + (const void*)vector, + count, + is_one_apdu ? "TRUE" : "FALSE", + (const void*)bytes_written); + + pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); + pgm_return_val_if_fail (count <= PGM_MAX_FRAGMENTS, PGM_IO_STATUS_ERROR); + if (PGM_LIKELY(count)) pgm_return_val_if_fail (NULL != vector, PGM_IO_STATUS_ERROR); + if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + if (PGM_UNLIKELY(!sock->is_bound || + sock->is_destroyed)) + { + pgm_rwlock_reader_unlock (&sock->lock); + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + } + + pgm_mutex_lock (&sock->source_mutex); + +/* pass on zero length as cannot count vector lengths */ + if (PGM_UNLIKELY(0 == count)) + { + const int status = send_odata_copy (sock, NULL, count, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + else if (1 == count) + { + const int status = send_odata (sock, vector[0], bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + + size_t bytes_sent = 0; + unsigned packets_sent = 0; + size_t data_bytes_sent = 0; + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + +/* continue if blocked mid-apdu */ + if (sock->is_apdu_eagain) + goto retry_send; + + STATE(is_rate_limited) = FALSE; + if (sock->is_nonblocking && sock->is_controlled_odata) + { + size_t total_tpdu_length = 0; + for (unsigned i = 0; i < count; i++) + total_tpdu_length += sock->iphdr_len + pgm_pkt_offset (is_one_apdu, pgmcc_family) + vector[i]->len; + +/* calculation includes one iphdr length already */ + if (!pgm_rate_check (&sock->rate_control, + total_tpdu_length - sock->iphdr_len, + sock->is_nonblocking)) + { + sock->blocklen = total_tpdu_length; + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_RATE_LIMITED; + } + STATE(is_rate_limited) = TRUE; + } + + if (is_one_apdu) + { + STATE(apdu_length) = 0; + STATE(first_sqn) = pgm_txw_next_lead(sock->window); + for (unsigned i = 0; i < count; i++) + { + if (PGM_UNLIKELY(vector[i]->len > sock->max_tsdu_fragment)) { + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_ERROR; + } + STATE(apdu_length) += vector[i]->len; + } + if (PGM_UNLIKELY(STATE(apdu_length) > sock->max_apdu)) { + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_ERROR; + } + } + + for (STATE(vector_index) = 0; STATE(vector_index) < count; STATE(vector_index)++) + { + STATE(tsdu_length) = vector[STATE(vector_index)]->len; + + STATE(skb) = pgm_skb_get(vector[STATE(vector_index)]); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = is_one_apdu ? PGM_OPT_PRESENT : 0; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + if (is_one_apdu) + { +/* OPT_LENGTH */ + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(STATE(skb)->pgm_data + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment) ); +/* OPT_FRAGMENT */ + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment); + STATE(skb)->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + STATE(skb)->pgm_opt_fragment->opt_reserved = 0; + STATE(skb)->pgm_opt_fragment->opt_sqn = htonl (STATE(first_sqn)); + STATE(skb)->pgm_opt_fragment->opt_frag_off = htonl (STATE(data_bytes_offset)); + STATE(skb)->pgm_opt_fragment->opt_frag_len = htonl (STATE(apdu_length)); + + pgm_assert (STATE(skb)->data == (STATE(skb)->pgm_opt_fragment + 1)); + } + else + { + pgm_assert (STATE(skb)->data == (STATE(skb)->pgm_data + 1)); + } + +/* TODO: the assembly checksum & copy routine is faster than memcpy & pgm_cksum on >= opteron hardware */ + STATE(skb)->pgm_header->pgm_checksum = 0; + pgm_assert ((char*)STATE(skb)->data > (char*)STATE(skb)->pgm_header); + const size_t pgm_header_len = (char*)STATE(skb)->data - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial ((char*)STATE(skb)->data, STATE(tsdu_length), 0); + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + ssize_t sent; + size_t tpdu_length; +retry_send: + pgm_assert ((char*)STATE(skb)->tail > (char*)STATE(skb)->head); + tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; + sent = pgm_sendto (sock, + !STATE(is_rate_limited), /* rate limited on blocking */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + goto blocked; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + if (PGM_LIKELY((size_t)sent == tpdu_length)) { + bytes_sent += tpdu_length + sock->iphdr_len; /* as counted at IP layer */ + packets_sent++; /* IP packets */ + data_bytes_sent += STATE(tsdu_length); + } + + pgm_free_skb (STATE(skb)); + STATE(data_bytes_offset) += STATE(tsdu_length); + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + + } +#ifdef TRANSPORT_DEBUG + if (is_one_apdu) + { + pgm_assert( STATE(data_bytes_offset) == STATE(apdu_length) ); + } +#endif + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + if (bytes_written) + *bytes_written = data_bytes_sent; + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_NORMAL; + +blocked: + if (bytes_sent) { + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + } + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; +} + +/* cleanup resuming send state helper + */ +#undef STATE + +/* send repair packet. + * + * on success, TRUE is returned. on error, FALSE is returned. + */ + +static +bool +send_rdata ( + pgm_sock_t* restrict sock, + struct pgm_sk_buff_t* restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + pgm_assert ((char*)skb->tail > (char*)skb->head); + + const size_t tpdu_length = (char*)skb->tail - (char*)skb->head; + +/* update previous odata/rdata contents */ + struct pgm_header* header = skb->pgm_header; + struct pgm_data* rdata = skb->pgm_data; + header->pgm_type = PGM_RDATA; +/* RDATA */ + rdata->data_trail = htonl (pgm_txw_trail(sock->window)); + + header->pgm_checksum = 0; + const size_t pgm_header_len = tpdu_length - ntohs(header->pgm_tsdu_length); + uint32_t unfolded_header = pgm_csum_partial (header, pgm_header_len, 0); + uint32_t unfolded_odata = pgm_csum_partial (skb->data, ntohs(header->pgm_tsdu_length), 0); + header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, unfolded_odata, pgm_header_len)); + +/* congestion control */ +// if (sock->use_pgmcc && +// sock->tokens < pgm_fp8 (1)) +// { +// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Token limit reached.")); +// sock->blocklen = tpdu_length; +// return FALSE; +// } + + const ssize_t sent = pgm_sendto (sock, + sock->is_controlled_rdata, /* rate limited */ + TRUE, /* with router alert */ + header, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + + if (sent < 0 && EAGAIN == errno) { + sock->blocklen = tpdu_length; + return FALSE; + } + + const pgm_time_t now = pgm_time_update_now(); + + if (sock->use_pgmcc) { + if (sock->tokens >= pgm_fp8 (1)) + sock->tokens -= pgm_fp8 (1); + sock->ack_expiry = now + sock->ack_expiry_ivl; + } + +/* re-set spm timer: we are already in the timer thread, no need to prod timers + */ + pgm_mutex_lock (&sock->timer_mutex); + sock->spm_heartbeat_state = 1; + sock->next_heartbeat_spm = now + sock->spm_heartbeat_interval[sock->spm_heartbeat_state++]; + pgm_mutex_unlock (&sock->timer_mutex); + + pgm_txw_inc_retransmit_count (skb); + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED] += ntohs(header->pgm_tsdu_length); + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED]++; /* impossible to determine APDU count */ + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); + return TRUE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/source.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/source.c.c89.patch new file mode 100644 index 0000000..dce59e9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/source.c.c89.patch @@ -0,0 +1,1021 @@ +--- source.c 2010-08-05 11:41:13.000000000 +0800 ++++ source.c89 2010-08-05 11:41:04.000000000 +0800 +@@ -124,11 +124,13 @@ + ) + { + pgm_return_val_if_fail (NULL != sock, FALSE); ++ { + const bool status = pgm_txw_retransmit_push (sock->window, + nak_tg_sqn | sock->rs_proactive_h, + TRUE /* is_parity */, + sock->tg_sqn_shift); + return status; ++ } + } + + /* a deferred request for RDATA, now processing in the timer thread, we check the transmit +@@ -159,6 +161,7 @@ + * has been retransmitted. + */ + pgm_spinlock_lock (&sock->txw_spinlock); ++ { + struct pgm_sk_buff_t* skb = pgm_txw_retransmit_try_peek (sock->window); + if (skb) { + skb = pgm_skb_get (skb); +@@ -174,6 +177,7 @@ + } else + pgm_spinlock_unlock (&sock->txw_spinlock); + return TRUE; ++ } + } + + /* SPMR indicates if multicast to cancel own SPMR, or unicast to send SPM. +@@ -233,10 +237,11 @@ + pgm_assert (NULL != skb); + pgm_assert (NULL != opt_pgmcc_feedback); + ++ { + const uint32_t opt_tstamp = ntohl (opt_pgmcc_feedback->opt_tstamp); + const uint16_t opt_loss_rate = ntohs (opt_pgmcc_feedback->opt_loss_rate); + +- const uint32_t rtt = pgm_to_msecs (skb->tstamp) - opt_tstamp; ++ const uint32_t rtt = (uint32_t)(pgm_to_msecs (skb->tstamp) - opt_tstamp); + const uint64_t peer_loss = rtt * rtt * opt_loss_rate; + + struct sockaddr_storage peer_nla; +@@ -263,6 +268,7 @@ + } + + return FALSE; ++ } + } + + /* NAK requesting RDATA transmission for a sending sock, only valid if +@@ -290,6 +296,7 @@ + pgm_debug ("pgm_on_nak (sock:%p skb:%p)", + (const void*)sock, (const void*)skb); + ++ { + const bool is_parity = skb->pgm_header->pgm_options & PGM_OPT_PARITY; + if (is_parity) { + sock->cumulative_stats[PGM_PC_SOURCE_PARITY_NAKS_RECEIVED]++; +@@ -307,6 +314,7 @@ + return FALSE; + } + ++ { + const struct pgm_nak* nak = (struct pgm_nak*) skb->data; + const struct pgm_nak6* nak6 = (struct pgm_nak6*)skb->data; + +@@ -323,6 +331,7 @@ + } + + /* NAK_GRP_NLA containers our sock multicast group */ ++ { + struct sockaddr_storage nak_grp_nla; + pgm_nla_to_sockaddr ((AF_INET6 == nak_src_nla.ss_family) ? &nak6->nak6_grp_nla_afi : &nak->nak_grp_nla_afi, (struct sockaddr*)&nak_grp_nla); + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nak_grp_nla, (struct sockaddr*)&sock->send_gsr.gsr_group) != 0)) +@@ -335,6 +344,7 @@ + } + + /* create queue object */ ++ { + struct pgm_sqn_list_t sqn_list; + sqn_list.sqn[0] = ntohl (nak->nak_sqn); + sqn_list.len = 1; +@@ -342,6 +352,7 @@ + pgm_debug ("nak_sqn %" PRIu32, sqn_list.sqn[0]); + + /* check NAK list */ ++ { + const uint32_t* nak_list = NULL; + uint_fast8_t nak_list_len = 0; + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) +@@ -360,6 +371,7 @@ + return FALSE; + } + /* TODO: check for > 16 options & past packet end */ ++ { + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); +@@ -369,6 +381,7 @@ + break; + } + } while (!(opt_header->opt_type & PGM_OPT_END)); ++ } + } + + /* nak list numbers */ +@@ -376,12 +389,15 @@ + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected on too long sequence list.")); + return FALSE; + } +- +- for (uint_fast8_t i = 0; i < nak_list_len; i++) ++ ++ { ++ uint_fast8_t i; ++ for (i = 0; i < nak_list_len; i++) + { + sqn_list.sqn[sqn_list.len++] = ntohl (*nak_list); + nak_list++; + } ++ } + + /* send NAK confirm packet immediately, then defer to timer thread for a.s.a.p + * delivery of the actual RDATA packets. blocking send for NCF is ignored as RDATA +@@ -393,13 +409,21 @@ + send_ncf (sock, (struct sockaddr*)&nak_src_nla, (struct sockaddr*)&nak_grp_nla, sqn_list.sqn[0], is_parity); + + /* queue retransmit requests */ +- for (uint_fast8_t i = 0; i < sqn_list.len; i++) { ++ { ++ uint_fast8_t i; ++ for (i = 0; i < sqn_list.len; i++) { + const bool push_status = pgm_txw_retransmit_push (sock->window, sqn_list.sqn[i], is_parity, sock->tg_sqn_shift); + if (PGM_UNLIKELY(!push_status)) { + pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Failed to push retransmit request for #%" PRIu32), sqn_list.sqn[i]); + } + } ++ } + return TRUE; ++ } ++ } ++ } ++ } ++ } + } + + /* Null-NAK, or N-NAK propogated by a DLR for hand waving excitement +@@ -427,6 +451,7 @@ + return FALSE; + } + ++ { + const struct pgm_nak* nnak = (struct pgm_nak*) skb->data; + const struct pgm_nak6* nnak6 = (struct pgm_nak6*)skb->data; + +@@ -441,6 +466,7 @@ + } + + /* NAK_GRP_NLA containers our sock multicast group */ ++ { + struct sockaddr_storage nnak_grp_nla; + pgm_nla_to_sockaddr ((AF_INET6 == nnak_src_nla.ss_family) ? &nnak6->nak6_grp_nla_afi : &nnak->nak_grp_nla_afi, (struct sockaddr*)&nnak_grp_nla); + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nnak_grp_nla, (struct sockaddr*)&sock->send_gsr.gsr_group) != 0)) +@@ -450,6 +476,7 @@ + } + + /* check NNAK list */ ++ { + uint_fast8_t nnak_list_len = 0; + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) + { +@@ -465,6 +492,7 @@ + return FALSE; + } + /* TODO: check for > 16 options & past packet end */ ++ { + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); +@@ -473,10 +501,14 @@ + break; + } + } while (!(opt_header->opt_type & PGM_OPT_END)); ++ } + } + + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED] += 1 + nnak_list_len; + return TRUE; ++ } ++ } ++ } + } + + /* ACK, sent upstream by one selected ACKER for congestion control feedback. +@@ -507,6 +539,7 @@ + if (!sock->use_pgmcc) + return FALSE; + ++ { + const struct pgm_ack* ack = (struct pgm_ack*)skb->data; + bool is_acker = FALSE; + +@@ -522,6 +555,7 @@ + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed ACK rejected.")); + return FALSE; + } ++ { + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); +@@ -531,6 +565,7 @@ + break; /* ignore other options */ + } + } while (!(opt_header->opt_type & PGM_OPT_END)); ++ } + } + + /* ignore ACKs from other receivers or sessions */ +@@ -541,22 +576,26 @@ + sock->next_crqst = 0; + + /* count new ACK sequences */ ++ { + const uint32_t ack_rx_max = ntohl (ack->ack_rx_max); + const int32_t delta = ack_rx_max - sock->ack_rx_max; + /* ignore older ACKs when multiple active ACKers */ + if (pgm_uint32_gt (ack_rx_max, sock->ack_rx_max)) + sock->ack_rx_max = ack_rx_max; ++ { + uint32_t ack_bitmap = ntohl (ack->ack_bitmap); + if (delta > 32) sock->ack_bitmap = 0; /* sequence jump ahead beyond past bitmap */ + else if (delta > 0) sock->ack_bitmap <<= delta; /* immediate sequence */ + else if (delta > -32) ack_bitmap <<= -delta; /* repair sequence scoped by bitmap */ + else ack_bitmap = 0; /* old sequence */ ++ { + unsigned new_acks = _pgm_popcount (ack_bitmap & ~sock->ack_bitmap); + sock->ack_bitmap |= ack_bitmap; + + if (0 == new_acks) + return TRUE; + ++ { + const bool is_congestion_limited = (sock->tokens < pgm_fp8 (1)); + + /* after loss detection cancel any further manipulation of the window +@@ -568,14 +607,17 @@ + { + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC window token manipulation suspended due to congestion (T:%u W:%u)"), + pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); ++ { + const uint_fast32_t token_inc = pgm_fp8mul (pgm_fp8 (new_acks), pgm_fp8 (1) + pgm_fp8div (pgm_fp8 (1), sock->cwnd_size)); + sock->tokens = MIN( sock->tokens + token_inc, sock->cwnd_size ); ++ } + goto notify_tx; + } + sock->is_congested = FALSE; + } + + /* count outstanding lost sequences */ ++ { + const unsigned total_lost = _pgm_popcount (~sock->ack_bitmap); + + /* no detected data loss at ACKer, increase congestion window size */ +@@ -583,6 +625,7 @@ + { + new_acks += sock->acks_after_loss; + sock->acks_after_loss = 0; ++ { + uint_fast32_t n = pgm_fp8 (new_acks); + uint_fast32_t token_inc = 0; + +@@ -594,6 +637,7 @@ + sock->cwnd_size += d; + } + ++ { + const uint_fast32_t iw = pgm_fp8div (pgm_fp8 (1), sock->cwnd_size); + + /* linear window increase */ +@@ -602,6 +646,8 @@ + sock->tokens = MIN( sock->tokens + token_inc, sock->cwnd_size ); + // pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC++ (T:%u W:%u)"), + // pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); ++ } ++ } + } + else + { +@@ -636,6 +682,12 @@ + pgm_notify_send (&sock->ack_notify); + } + return TRUE; ++ } ++ } ++ } ++ } ++ } ++ } + } + + /* ambient/heartbeat SPM's +@@ -658,6 +710,7 @@ + pgm_debug ("pgm_send_spm (sock:%p flags:%d)", + (const void*)sock, flags); + ++ { + size_t tpdu_length = sizeof(struct pgm_header); + if (AF_INET == sock->send_gsr.gsr_group.ss_family) + tpdu_length += sizeof(struct pgm_spm); +@@ -683,9 +736,11 @@ + tpdu_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fin); + } +- char buf[ tpdu_length ]; ++ { ++ char* buf = pgm_newa (char, tpdu_length); + if (PGM_UNLIKELY(pgm_mem_gc_friendly)) + memset (buf, 0, tpdu_length); ++ { + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_spm* spm = (struct pgm_spm *)(header + 1); + struct pgm_spm6* spm6 = (struct pgm_spm6*)(header + 1); +@@ -734,12 +789,14 @@ + sizeof(struct pgm_opt_parity_prm); + opt_header->opt_type = PGM_OPT_PARITY_PRM; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_parity_prm); ++ { + struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1); + opt_parity_prm->opt_reserved = (sock->use_proactive_parity ? PGM_PARITY_PRM_PRO : 0) | + (sock->use_ondemand_parity ? PGM_PARITY_PRM_OND : 0); + opt_parity_prm->parity_prm_tgs = htonl (sock->rs_k); + last_opt_header = opt_header; + opt_header = (struct pgm_opt_header*)(opt_parity_prm + 1); ++ } + } + + /* OPT_CRQST */ +@@ -750,12 +807,14 @@ + sizeof(struct pgm_opt_crqst); + opt_header->opt_type = PGM_OPT_CRQST; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_crqst); ++ { + struct pgm_opt_crqst* opt_crqst = (struct pgm_opt_crqst*)(opt_header + 1); + /* request receiver worst path report, OPT_CR_RX_WP */ + opt_crqst->opt_reserved = PGM_OPT_CRQST_RXP; + sock->is_pending_crqst = FALSE; + last_opt_header = opt_header; + opt_header = (struct pgm_opt_header*)(opt_crqst + 1); ++ } + } + + /* OPT_FIN */ +@@ -765,10 +824,12 @@ + sizeof(struct pgm_opt_fin); + opt_header->opt_type = PGM_OPT_FIN; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fin); ++ { + struct pgm_opt_fin* opt_fin = (struct pgm_opt_fin*)(opt_header + 1); + opt_fin->opt_reserved = 0; + last_opt_header = opt_header; + opt_header = (struct pgm_opt_header*)(opt_fin + 1); ++ } + } + + last_opt_header->opt_type |= PGM_OPT_END; +@@ -779,6 +840,7 @@ + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + ++ { + const ssize_t sent = pgm_sendto (sock, + flags != PGM_OPT_SYN && sock->is_controlled_spm, /* rate limited */ + TRUE, /* with router alert */ +@@ -794,6 +856,10 @@ + sock->spm_sqn++; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); + return TRUE; ++ } ++ } ++ } ++ } + } + + /* send a NAK confirm (NCF) message with provided sequence number list. +@@ -818,6 +884,7 @@ + pgm_assert (nak_src_nla->sa_family == nak_grp_nla->sa_family); + + #ifdef SOURCE_DEBUG ++ { + char saddr[INET6_ADDRSTRLEN], gaddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop (nak_src_nla, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (nak_grp_nla, gaddr, sizeof(gaddr)); +@@ -828,11 +895,14 @@ + sequence, + is_parity ? "TRUE": "FALSE" + ); ++ } + #endif + ++ { + size_t tpdu_length = sizeof(struct pgm_header); + tpdu_length += (AF_INET == nak_src_nla->sa_family) ? sizeof(struct pgm_nak) : sizeof(struct pgm_nak6); +- char buf[ tpdu_length ]; ++ { ++ char* buf = pgm_newa (char, tpdu_length); + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* ncf = (struct pgm_nak *)(header + 1); + struct pgm_nak6* ncf6 = (struct pgm_nak6*)(header + 1); +@@ -854,6 +924,7 @@ + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + ++ { + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + TRUE, /* with router alert */ +@@ -865,6 +936,9 @@ + return FALSE; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); + return TRUE; ++ } ++ } ++ } + } + + /* A NCF packet with a OPT_NAK_LIST option extension +@@ -891,16 +965,20 @@ + pgm_assert (nak_src_nla->sa_family == nak_grp_nla->sa_family); + + #ifdef SOURCE_DEBUG ++ { + char saddr[INET6_ADDRSTRLEN], gaddr[INET6_ADDRSTRLEN]; + char list[1024]; + pgm_sockaddr_ntop (nak_src_nla, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (nak_grp_nla, gaddr, sizeof(gaddr)); + sprintf (list, "%" PRIu32, sqn_list->sqn[0]); +- for (uint_fast8_t i = 1; i < sqn_list->len; i++) { ++ { ++ uint_fast8_t i; ++ for (i = 1; i < sqn_list->len; i++) { + char sequence[ 2 + strlen("4294967295") ]; + sprintf (sequence, " %" PRIu32, sqn_list->sqn[i]); + strcat (list, sequence); + } ++ } + pgm_debug ("send_ncf_list (sock:%p nak-src-nla:%s nak-grp-nla:%s sqn-list:[%s] is-parity:%s)", + (void*)sock, + saddr, +@@ -908,14 +986,17 @@ + list, + is_parity ? "TRUE": "FALSE" + ); ++ } + #endif + ++ { + size_t tpdu_length = sizeof(struct pgm_header) + + sizeof(struct pgm_opt_length) + /* includes header */ + sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ); + tpdu_length += (AF_INET == nak_src_nla->sa_family) ? sizeof(struct pgm_nak) : sizeof(struct pgm_nak6); +- char buf[ tpdu_length ]; ++ { ++ char* buf = pgm_newa (char, tpdu_length); + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* ncf = (struct pgm_nak *)(header + 1); + struct pgm_nak6* ncf6 = (struct pgm_nak6*)(header + 1); +@@ -935,6 +1016,7 @@ + pgm_sockaddr_to_nla (nak_grp_nla, (AF_INET6 == nak_src_nla->sa_family) ? (char*)&ncf6->nak6_grp_nla_afi : (char*)&ncf->nak_grp_nla_afi ); + + /* OPT_NAK_LIST */ ++ { + struct pgm_opt_length* opt_len = (AF_INET6 == nak_src_nla->sa_family) ? (struct pgm_opt_length*)(ncf6 + 1) : (struct pgm_opt_length*)(ncf + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); +@@ -942,20 +1024,26 @@ + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ) ); ++ { + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ); ++ { + struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); + opt_nak_list->opt_reserved = 0; + /* to network-order */ +- for (uint_fast8_t i = 1; i < sqn_list->len; i++) ++ { ++ uint_fast8_t i; ++ for (i = 1; i < sqn_list->len; i++) + opt_nak_list->opt_sqn[i-1] = htonl (sqn_list->sqn[i]); ++ } + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + ++ { + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + TRUE, /* with router alert */ +@@ -967,6 +1055,12 @@ + return FALSE; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); + return TRUE; ++ } ++ } ++ } ++ } ++ } ++ } + } + + /* cancel any pending heartbeat SPM and schedule a new one +@@ -980,6 +1074,7 @@ + ) + { + pgm_mutex_lock (&sock->timer_mutex); ++ { + const pgm_time_t next_poll = sock->next_poll; + const pgm_time_t spm_heartbeat_interval = sock->spm_heartbeat_interval[ sock->spm_heartbeat_state = 1 ]; + sock->next_heartbeat_spm = now + spm_heartbeat_interval; +@@ -992,6 +1087,7 @@ + } + } + pgm_mutex_unlock (&sock->timer_mutex); ++ } + } + + /* state helper for resuming sends +@@ -1027,6 +1123,7 @@ + pgm_debug ("send_odata (sock:%p skb:%p bytes-written:%p)", + (void*)sock, (void*)skb, (void*)bytes_written); + ++ { + const uint16_t tsdu_length = skb->len; + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + const size_t tpdu_length = tsdu_length + pgm_pkt_offset (FALSE, pgmcc_family); +@@ -1056,6 +1153,7 @@ + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + STATE(skb)->pgm_header->pgm_checksum = 0; ++ { + void* data = STATE(skb)->pgm_data + 1; + if (sock->use_pgmcc) { + struct pgm_opt_length* opt_len = data; +@@ -1066,23 +1164,28 @@ + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)) ); ++ { + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_PGMCC_DATA | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)); ++ { + struct pgm_opt_pgmcc_data* pgmcc_data = (struct pgm_opt_pgmcc_data*)(opt_header + 1); + struct pgm_opt6_pgmcc_data* pgmcc_data6 = (struct pgm_opt6_pgmcc_data*)(opt_header + 1); + +- pgmcc_data->opt_tstamp = htonl (pgm_to_msecs (STATE(skb)->tstamp)); ++ pgmcc_data->opt_tstamp = htonl ((unsigned long)pgm_to_msecs (STATE(skb)->tstamp)); + /* acker nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->acker_nla, (char*)&pgmcc_data->opt_nla_afi); + if (AF_INET6 == sock->acker_nla.ss_family) + data = (char*)pgmcc_data6 + sizeof(struct pgm_opt6_pgmcc_data); + else + data = (char*)pgmcc_data + sizeof(struct pgm_opt_pgmcc_data); ++ } ++ } + } ++ { + const size_t pgm_header_len = (char*)data - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial (data, tsdu_length, 0); +@@ -1097,6 +1200,7 @@ + * attempt to send a repair-data packet based on in transit original data. + */ + ++ { + ssize_t sent; + retry_send: + +@@ -1157,6 +1261,10 @@ + if (bytes_written) + *bytes_written = tsdu_length; + return PGM_IO_STATUS_NORMAL; ++ } ++ } ++ } ++ } + } + + /* send one PGM original data packet, callee owned memory. +@@ -1183,6 +1291,7 @@ + pgm_debug ("send_odata_copy (sock:%p tsdu:%p tsdu_length:%u bytes-written:%p)", + (void*)sock, tsdu, tsdu_length, (void*)bytes_written); + ++ { + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + const size_t tpdu_length = tsdu_length + pgm_pkt_offset (FALSE, pgmcc_family); + +@@ -1212,6 +1321,7 @@ + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + STATE(skb)->pgm_header->pgm_checksum = 0; ++ { + void* data = STATE(skb)->pgm_data + 1; + if (sock->use_pgmcc) { + struct pgm_opt_length* opt_len = data; +@@ -1222,21 +1332,26 @@ + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)) ); ++ { + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_PGMCC_DATA | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)); ++ { + struct pgm_opt_pgmcc_data* pgmcc_data = (struct pgm_opt_pgmcc_data*)(opt_header + 1); + struct pgm_opt6_pgmcc_data* pgmcc_data6 = (struct pgm_opt6_pgmcc_data*)(opt_header + 1); + + pgmcc_data->opt_reserved = 0; +- pgmcc_data->opt_tstamp = htonl (pgm_to_msecs (STATE(skb)->tstamp)); ++ pgmcc_data->opt_tstamp = htonl ((unsigned long)pgm_to_msecs (STATE(skb)->tstamp)); + /* acker nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->acker_nla, (char*)&pgmcc_data->opt_nla_afi); + data = (char*)opt_header + opt_header->opt_length; ++ } ++ } + } ++ { + const size_t pgm_header_len = (char*)data - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial_copy (tsdu, data, tsdu_length, 0); +@@ -1247,6 +1362,7 @@ + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + ++ { + ssize_t sent; + retry_send: + +@@ -1309,6 +1425,10 @@ + if (bytes_written) + *bytes_written = tsdu_length; + return PGM_IO_STATUS_NORMAL; ++ } ++ } ++ } ++ } + } + + /* send one PGM original data packet, callee owned scatter/gather io vector +@@ -1347,7 +1467,9 @@ + goto retry_send; + + STATE(tsdu_length) = 0; +- for (unsigned i = 0; i < count; i++) ++ { ++ unsigned i; ++ for (i = 0; i < count; i++) + { + #ifdef TRANSPORT_DEBUG + if (PGM_LIKELY(vector[i].iov_len)) { +@@ -1356,11 +1478,13 @@ + #endif + STATE(tsdu_length) += vector[i].iov_len; + } ++ } + pgm_return_val_if_fail (STATE(tsdu_length) <= sock->max_tsdu, PGM_IO_STATUS_ERROR); + + STATE(skb) = pgm_alloc_skb (sock->max_tpdu); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); ++ { + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + pgm_skb_reserve (STATE(skb), pgm_pkt_offset (FALSE, pgmcc_family)); + pgm_skb_put (STATE(skb), STATE(tsdu_length)); +@@ -1379,18 +1503,24 @@ + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + STATE(skb)->pgm_header->pgm_checksum = 0; ++ { + const size_t pgm_header_len = (char*)(STATE(skb)->pgm_data + 1) - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + + /* unroll first iteration to make friendly branch prediction */ + char* dst = (char*)(STATE(skb)->pgm_data + 1); +- STATE(unfolded_odata) = pgm_csum_partial_copy ((const char*)vector[0].iov_base, dst, vector[0].iov_len, 0); ++ STATE(unfolded_odata) = pgm_csum_partial_copy ((const char*)vector[0].iov_base, dst, (uint16_t)vector[0].iov_len, 0); + + /* iterate over one or more vector elements to perform scatter/gather checksum & copy */ +- for (unsigned i = 1; i < count; i++) { ++ { ++ unsigned i; ++ for (i = 1; i < count; i++) { + dst += vector[i-1].iov_len; +- const uint32_t unfolded_element = pgm_csum_partial_copy ((const char*)vector[i].iov_base, dst, vector[i].iov_len, 0); +- STATE(unfolded_odata) = pgm_csum_block_add (STATE(unfolded_odata), unfolded_element, vector[i-1].iov_len); ++ { ++ const uint32_t unfolded_element = pgm_csum_partial_copy ((const char*)vector[i].iov_base, dst, (uint16_t)vector[i].iov_len, 0); ++ STATE(unfolded_odata) = pgm_csum_block_add (STATE(unfolded_odata), unfolded_element, (uint16_t)vector[i-1].iov_len); ++ } ++ } + } + + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); +@@ -1400,6 +1530,7 @@ + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + ++ { + ssize_t sent; + size_t tpdu_length; + retry_send: +@@ -1447,6 +1578,9 @@ + if (bytes_written) + *bytes_written = STATE(tsdu_length); + return PGM_IO_STATUS_NORMAL; ++ } ++ } ++ } + } + + /* send PGM original data, callee owned memory. if larger than maximum TPDU +@@ -1530,6 +1664,7 @@ + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + /* OPT_LENGTH */ ++ { + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(STATE(skb)->pgm_data + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); +@@ -1537,6 +1672,7 @@ + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment) ); + /* OPT_FRAGMENT */ ++ { + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + +@@ -1549,6 +1685,7 @@ + + /* TODO: the assembly checksum & copy routine is faster than memcpy & pgm_cksum on >= opteron hardware */ + STATE(skb)->pgm_header->pgm_checksum = 0; ++ { + const size_t pgm_header_len = (char*)(STATE(skb)->pgm_opt_fragment + 1) - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial_copy ((const char*)apdu + STATE(data_bytes_offset), STATE(skb)->pgm_opt_fragment + 1, STATE(tsdu_length), 0); +@@ -1559,6 +1696,7 @@ + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + ++ { + ssize_t sent; + size_t tpdu_length; + retry_send: +@@ -1596,6 +1734,10 @@ + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + ++ } ++ } ++ } ++ } + } while ( STATE(data_bytes_offset) < apdu_length); + pgm_assert( STATE(data_bytes_offset) == apdu_length ); + +@@ -1638,7 +1780,7 @@ + size_t* restrict bytes_written + ) + { +- pgm_debug ("pgm_send (sock:%p apdu:%p apdu-length:%zu bytes-written:%p)", ++ pgm_debug ("pgm_send (sock:%p apdu:%p apdu-length:%lu bytes-written:%p)", + (void*)sock, apdu, apdu_length, (void*)bytes_written); + + /* parameters */ +@@ -1670,10 +1812,12 @@ + return status; + } + ++ { + const int status = send_apdu (sock, apdu, apdu_length, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; ++ } + } + + /* send PGM original data, callee owned scatter/gather IO vector. if larger than maximum TPDU +@@ -1735,6 +1879,7 @@ + return status; + } + ++ { + size_t bytes_sent = 0; + unsigned packets_sent = 0; + size_t data_bytes_sent = 0; +@@ -1759,7 +1904,9 @@ + + /* calculate (total) APDU length */ + STATE(apdu_length) = 0; +- for (unsigned i = 0; i < count; i++) ++ { ++ unsigned i; ++ for (i = 0; i < count; i++) + { + #ifdef TRANSPORT_DEBUG + if (PGM_LIKELY(vector[i].iov_len)) { +@@ -1775,6 +1922,7 @@ + } + STATE(apdu_length) += vector[i].iov_len; + } ++ } + + /* pass on non-fragment calls */ + if (is_one_apdu) { +@@ -1885,6 +2033,7 @@ + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + /* OPT_LENGTH */ ++ { + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(STATE(skb)->pgm_data + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); +@@ -1892,6 +2041,7 @@ + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment) ); + /* OPT_FRAGMENT */ ++ { + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + +@@ -1904,6 +2054,7 @@ + + /* checksum & copy */ + STATE(skb)->pgm_header->pgm_checksum = 0; ++ { + const size_t pgm_header_len = (char*)(STATE(skb)->pgm_opt_fragment + 1) - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + +@@ -1941,8 +2092,10 @@ + dst += copy_length; + src_length = vector[STATE(vector_index)].iov_len - STATE(vector_offset); + copy_length = MIN( STATE(tsdu_length) - dst_length, src_length ); ++ { + const uint32_t unfolded_element = pgm_csum_partial_copy (src, dst, copy_length, 0); + STATE(unfolded_odata) = pgm_csum_block_add (STATE(unfolded_odata), unfolded_element, dst_length); ++ } + } + + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); +@@ -1952,6 +2105,7 @@ + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + ++ { + ssize_t sent; + size_t tpdu_length; + retry_one_apdu_send: +@@ -1988,6 +2142,10 @@ + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + ++ } ++ } ++ } ++ } + } while ( STATE(data_bytes_offset) < STATE(apdu_length) ); + pgm_assert( STATE(data_bytes_offset) == STATE(apdu_length) ); + +@@ -2018,6 +2176,7 @@ + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; ++ } + } + + /* send PGM original data, transmit window owned scatter/gather IO vector. +@@ -2077,6 +2236,7 @@ + return status; + } + ++ { + size_t bytes_sent = 0; + unsigned packets_sent = 0; + size_t data_bytes_sent = 0; +@@ -2090,8 +2250,11 @@ + if (sock->is_nonblocking && sock->is_controlled_odata) + { + size_t total_tpdu_length = 0; +- for (unsigned i = 0; i < count; i++) ++ { ++ unsigned i; ++ for (i = 0; i < count; i++) + total_tpdu_length += sock->iphdr_len + pgm_pkt_offset (is_one_apdu, pgmcc_family) + vector[i]->len; ++ } + + /* calculation includes one iphdr length already */ + if (!pgm_rate_check (&sock->rate_control, +@@ -2110,7 +2273,9 @@ + { + STATE(apdu_length) = 0; + STATE(first_sqn) = pgm_txw_next_lead(sock->window); +- for (unsigned i = 0; i < count; i++) ++ { ++ unsigned i; ++ for (i = 0; i < count; i++) + { + if (PGM_UNLIKELY(vector[i]->len > sock->max_tsdu_fragment)) { + pgm_mutex_unlock (&sock->source_mutex); +@@ -2119,6 +2284,7 @@ + } + STATE(apdu_length) += vector[i]->len; + } ++ } + if (PGM_UNLIKELY(STATE(apdu_length) > sock->max_apdu)) { + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); +@@ -2157,6 +2323,7 @@ + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment) ); + /* OPT_FRAGMENT */ ++ { + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + +@@ -2168,6 +2335,7 @@ + STATE(skb)->pgm_opt_fragment->opt_frag_len = htonl (STATE(apdu_length)); + + pgm_assert (STATE(skb)->data == (STATE(skb)->pgm_opt_fragment + 1)); ++ } + } + else + { +@@ -2177,6 +2345,7 @@ + /* TODO: the assembly checksum & copy routine is faster than memcpy & pgm_cksum on >= opteron hardware */ + STATE(skb)->pgm_header->pgm_checksum = 0; + pgm_assert ((char*)STATE(skb)->data > (char*)STATE(skb)->pgm_header); ++ { + const size_t pgm_header_len = (char*)STATE(skb)->data - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial ((char*)STATE(skb)->data, STATE(tsdu_length), 0); +@@ -2186,6 +2355,7 @@ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); ++ { + ssize_t sent; + size_t tpdu_length; + retry_send: +@@ -2223,6 +2393,8 @@ + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } ++ } ++ } + + } + #ifdef TRANSPORT_DEBUG +@@ -2259,6 +2431,7 @@ + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; ++ } + } + + /* cleanup resuming send state helper +@@ -2282,6 +2455,7 @@ + pgm_assert (NULL != skb); + pgm_assert ((char*)skb->tail > (char*)skb->head); + ++ { + const size_t tpdu_length = (char*)skb->tail - (char*)skb->head; + + /* update previous odata/rdata contents */ +@@ -2292,6 +2466,7 @@ + rdata->data_trail = htonl (pgm_txw_trail(sock->window)); + + header->pgm_checksum = 0; ++ { + const size_t pgm_header_len = tpdu_length - ntohs(header->pgm_tsdu_length); + uint32_t unfolded_header = pgm_csum_partial (header, pgm_header_len, 0); + uint32_t unfolded_odata = pgm_txw_get_unfolded_checksum (skb); +@@ -2306,6 +2481,7 @@ + return FALSE; + } + ++ { + const ssize_t sent = pgm_sendto (sock, + sock->is_controlled_rdata, /* rate limited */ + TRUE, /* with router alert */ +@@ -2319,6 +2495,7 @@ + return FALSE; + } + ++ { + const pgm_time_t now = pgm_time_update_now(); + + if (sock->use_pgmcc) { +@@ -2338,6 +2515,10 @@ + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED]++; /* impossible to determine APDU count */ + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); + return TRUE; ++ } ++ } ++ } ++ } + } + + /* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/source.c.orig b/3rdparty/openpgm-svn-r1135/pgm/source.c.orig new file mode 100644 index 0000000..2c197cd --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/source.c.orig @@ -0,0 +1,2344 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM source socket. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __STDC_FORMAT_MACROS +#ifdef _MSC_VER +# include +#else +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + + +//#define SOURCE_DEBUG + +#ifndef SOURCE_DEBUG +# define PGM_DISABLE_ASSERT +#endif + +#if !defined(ENOBUFS) && defined(WSAENOBUFS) +# define ENOBUFS WSAENOBUFS +#endif + + +/* locals */ +static inline bool peer_is_source (const pgm_peer_t*) PGM_GNUC_CONST; +static inline bool peer_is_peer (const pgm_peer_t*) PGM_GNUC_CONST; +static void reset_heartbeat_spm (pgm_sock_t*const, const pgm_time_t); +static bool send_ncf (pgm_sock_t*const restrict, const struct sockaddr*const restrict, const struct sockaddr*const restrict, const uint32_t, const bool); +static bool send_ncf_list (pgm_sock_t*const restrict, const struct sockaddr*const restrict, const struct sockaddr*const restrict, struct pgm_sqn_list_t*const restrict, const bool); +static int send_odata (pgm_sock_t*const restrict, struct pgm_sk_buff_t*const restrict, size_t*restrict); +static int send_odata_copy (pgm_sock_t*const restrict, const void*restrict, const uint16_t, size_t*restrict); +static int send_odatav (pgm_sock_t*const restrict, const struct pgm_iovec*const restrict, const unsigned, size_t*restrict); +static bool send_rdata (pgm_sock_t*restrict, struct pgm_sk_buff_t*restrict); + + +static inline +unsigned +_pgm_popcount ( + uint32_t n + ) +{ +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + return __builtin_popcount (n); +#else +/* MIT HAKMEM 169 */ + const uint32_t t = n - ((n >> 1) & 033333333333) + - ((n >> 2) & 011111111111); + return ((t + (t >> 3) & 030707070707)) % 63; +#endif +} + +static inline +bool +peer_is_source ( + const pgm_peer_t* peer + ) +{ + return (NULL == peer); +} + +static inline +bool +peer_is_peer ( + const pgm_peer_t* peer + ) +{ + return (NULL != peer); +} + +static inline +void +reset_spmr_timer ( + pgm_peer_t* const peer + ) +{ + peer->spmr_expiry = 0; +} + +static inline +size_t +source_max_tsdu ( + const pgm_sock_t* sock, + const bool can_fragment + ) +{ + size_t max_tsdu = can_fragment ? sock->max_tsdu_fragment : sock->max_tsdu; + if (sock->use_var_pktlen /* OPT_VAR_PKT_LEN */) + max_tsdu -= sizeof (uint16_t); + return max_tsdu; +} + +/* prototype of function to send pro-active parity NAKs. + */ +static +bool +pgm_schedule_proactive_nak ( + pgm_sock_t* sock, + uint32_t nak_tg_sqn /* transmission group (shifted) */ + ) +{ + pgm_return_val_if_fail (NULL != sock, FALSE); + const bool status = pgm_txw_retransmit_push (sock->window, + nak_tg_sqn | sock->rs_proactive_h, + TRUE /* is_parity */, + sock->tg_sqn_shift); + return status; +} + +/* a deferred request for RDATA, now processing in the timer thread, we check the transmit + * window to see if the packet exists and forward on, maintaining a lock until the queue is + * empty. + * + * returns TRUE on success, returns FALSE if operation would block. + */ + +bool +pgm_on_deferred_nak ( + pgm_sock_t* const sock + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + +/* We can flush queue and block all odata, or process one set, or process each + * sequence number individually. + */ + +/* parity packets are re-numbered across the transmission group with index h, sharing the space + * with the original packets. beyond the transmission group size (k), the PGM option OPT_PARITY_GRP + * provides the extra offset value. + */ + +/* peek from the retransmit queue so we can eliminate duplicate NAKs up until the repair packet + * has been retransmitted. + */ + pgm_spinlock_lock (&sock->txw_spinlock); + struct pgm_sk_buff_t* skb = pgm_txw_retransmit_try_peek (sock->window); + if (skb) { + skb = pgm_skb_get (skb); + pgm_spinlock_unlock (&sock->txw_spinlock); + if (!send_rdata (sock, skb)) { + pgm_free_skb (skb); + pgm_notify_send (&sock->rdata_notify); + return FALSE; + } + pgm_free_skb (skb); +/* now remove sequence number from retransmit queue, re-enabling NAK processing for this sequence number */ + pgm_txw_retransmit_remove_head (sock->window); + } else + pgm_spinlock_unlock (&sock->txw_spinlock); + return TRUE; +} + +/* SPMR indicates if multicast to cancel own SPMR, or unicast to send SPM. + * + * rate limited to 1/IHB_MIN per TSI (13.4). + * + * if SPMR was valid, returns TRUE, if invalid returns FALSE. + */ + +bool +pgm_on_spmr ( + pgm_sock_t* const restrict sock, + pgm_peer_t* const restrict peer, /* maybe NULL if socket is source */ + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_spmr (sock:%p peer:%p skb:%p)", + (void*)sock, (void*)peer, (void*)skb); + + if (PGM_UNLIKELY(!pgm_verify_spmr (skb))) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed SPMR rejected.")); + return FALSE; + } + + if (peer_is_source (peer)) { + const bool send_status = pgm_send_spm (sock, 0); + if (PGM_UNLIKELY(!send_status)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Failed to send SPM on SPM-Request.")); + } + } else { + pgm_trace (PGM_LOG_ROLE_RX_WINDOW,_("Suppressing SPMR due to peer multicast SPMR.")); + reset_spmr_timer (peer); + } + return TRUE; +} + +/* Process opt_pgmcc_feedback PGM option that ships attached to ACK or NAK. + * Contents use to elect best ACKer. + * + * returns TRUE if peer is the elected ACKer. + */ + +static +bool +on_opt_pgmcc_feedback ( + pgm_sock_t* const restrict sock, + const struct pgm_sk_buff_t* const restrict skb, + const struct pgm_opt_pgmcc_feedback* restrict opt_pgmcc_feedback + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + pgm_assert (NULL != opt_pgmcc_feedback); + + const uint32_t opt_tstamp = ntohl (opt_pgmcc_feedback->opt_tstamp); + const uint16_t opt_loss_rate = ntohs (opt_pgmcc_feedback->opt_loss_rate); + + const uint32_t rtt = pgm_to_msecs (skb->tstamp) - opt_tstamp; + const uint64_t peer_loss = rtt * rtt * opt_loss_rate; + + struct sockaddr_storage peer_nla; + pgm_nla_to_sockaddr (&opt_pgmcc_feedback->opt_nla_afi, (struct sockaddr*)&peer_nla); + +/* ACKer elections */ + if (PGM_UNLIKELY(pgm_sockaddr_is_addr_unspecified ((const struct sockaddr*)&sock->acker_nla))) + { + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Elected first ACKer")); + memcpy (&sock->acker_nla, &peer_nla, pgm_sockaddr_storage_len (&peer_nla)); + } + else if (peer_loss > sock->acker_loss && + 0 != pgm_sockaddr_cmp ((const struct sockaddr*)&peer_nla, (const struct sockaddr*)&sock->acker_nla)) + { + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Elected new ACKer")); + memcpy (&sock->acker_nla, &peer_nla, pgm_sockaddr_storage_len (&peer_nla)); + } + +/* update ACKer state */ + if (0 == pgm_sockaddr_cmp ((const struct sockaddr*)&peer_nla, (const struct sockaddr*)&sock->acker_nla)) + { + sock->acker_loss = peer_loss; + return TRUE; + } + + return FALSE; +} + +/* NAK requesting RDATA transmission for a sending sock, only valid if + * sequence number(s) still in transmission window. + * + * we can potentially have different IP versions for the NAK packet to the send group. + * + * TODO: fix IPv6 AFIs + * + * take in a NAK and pass off to an asynchronous queue for another thread to process + * + * if NAK is valid, returns TRUE. on error, FALSE is returned. + */ + +bool +pgm_on_nak ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_nak (sock:%p skb:%p)", + (const void*)sock, (const void*)skb); + + const bool is_parity = skb->pgm_header->pgm_options & PGM_OPT_PARITY; + if (is_parity) { + sock->cumulative_stats[PGM_PC_SOURCE_PARITY_NAKS_RECEIVED]++; + if (!sock->use_ondemand_parity) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Parity NAK rejected as on-demand parity is not enabled.")); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } + } else + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NAKS_RECEIVED]++; + + if (PGM_UNLIKELY(!pgm_verify_nak (skb))) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected.")); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } + + const struct pgm_nak* nak = (struct pgm_nak*) skb->data; + const struct pgm_nak6* nak6 = (struct pgm_nak6*)skb->data; + +/* NAK_SRC_NLA contains our sock unicast NLA */ + struct sockaddr_storage nak_src_nla; + pgm_nla_to_sockaddr (&nak->nak_src_nla_afi, (struct sockaddr*)&nak_src_nla); + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nak_src_nla, (struct sockaddr*)&sock->send_addr) != 0)) + { + char saddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&nak_src_nla, saddr, sizeof(saddr)); + pgm_trace (PGM_LOG_ROLE_NETWORK,_("NAK rejected for unmatched NLA: %s"), saddr); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } + +/* NAK_GRP_NLA containers our sock multicast group */ + struct sockaddr_storage nak_grp_nla; + pgm_nla_to_sockaddr ((AF_INET6 == nak_src_nla.ss_family) ? &nak6->nak6_grp_nla_afi : &nak->nak_grp_nla_afi, (struct sockaddr*)&nak_grp_nla); + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nak_grp_nla, (struct sockaddr*)&sock->send_gsr.gsr_group) != 0)) + { + char sgroup[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&nak_src_nla, sgroup, sizeof(sgroup)); + pgm_trace (PGM_LOG_ROLE_NETWORK,_("NAK rejected as targeted for different multicast group: %s"), sgroup); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } + +/* create queue object */ + struct pgm_sqn_list_t sqn_list; + sqn_list.sqn[0] = ntohl (nak->nak_sqn); + sqn_list.len = 1; + + pgm_debug ("nak_sqn %" PRIu32, sqn_list.sqn[0]); + +/* check NAK list */ + const uint32_t* nak_list = NULL; + uint_fast8_t nak_list_len = 0; + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) + { + const struct pgm_opt_length* opt_len = (AF_INET6 == nak_src_nla.ss_family) ? + (const struct pgm_opt_length*)(nak6 + 1) : + (const struct pgm_opt_length*)(nak + 1); + if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected.")); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } + if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected.")); + sock->cumulative_stats[PGM_PC_SOURCE_MALFORMED_NAKS]++; + return FALSE; + } +/* TODO: check for > 16 options & past packet end */ + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); + if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_NAK_LIST) { + nak_list = ((const struct pgm_opt_nak_list*)(opt_header + 1))->opt_sqn; + nak_list_len = ( opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(uint8_t) ) / sizeof(uint32_t); + break; + } + } while (!(opt_header->opt_type & PGM_OPT_END)); + } + +/* nak list numbers */ + if (PGM_UNLIKELY(nak_list_len > 63)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed NAK rejected on too long sequence list.")); + return FALSE; + } + + for (uint_fast8_t i = 0; i < nak_list_len; i++) + { + sqn_list.sqn[sqn_list.len++] = ntohl (*nak_list); + nak_list++; + } + +/* send NAK confirm packet immediately, then defer to timer thread for a.s.a.p + * delivery of the actual RDATA packets. blocking send for NCF is ignored as RDATA + * broadcast will be sent later. + */ + if (nak_list_len) + send_ncf_list (sock, (struct sockaddr*)&nak_src_nla, (struct sockaddr*)&nak_grp_nla, &sqn_list, is_parity); + else + send_ncf (sock, (struct sockaddr*)&nak_src_nla, (struct sockaddr*)&nak_grp_nla, sqn_list.sqn[0], is_parity); + +/* queue retransmit requests */ + for (uint_fast8_t i = 0; i < sqn_list.len; i++) { + const bool push_status = pgm_txw_retransmit_push (sock->window, sqn_list.sqn[i], is_parity, sock->tg_sqn_shift); + if (PGM_UNLIKELY(!push_status)) { + pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Failed to push retransmit request for #%" PRIu32), sqn_list.sqn[i]); + } + } + return TRUE; +} + +/* Null-NAK, or N-NAK propogated by a DLR for hand waving excitement + * + * if NNAK is valid, returns TRUE. on error, FALSE is returned. + */ + +bool +pgm_on_nnak ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_nnak (sock:%p skb:%p)", + (void*)sock, (void*)skb); + + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAK_PACKETS_RECEIVED]++; + + if (PGM_UNLIKELY(!pgm_verify_nnak (skb))) { + sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; + return FALSE; + } + + const struct pgm_nak* nnak = (struct pgm_nak*) skb->data; + const struct pgm_nak6* nnak6 = (struct pgm_nak6*)skb->data; + +/* NAK_SRC_NLA contains our sock unicast NLA */ + struct sockaddr_storage nnak_src_nla; + pgm_nla_to_sockaddr (&nnak->nak_src_nla_afi, (struct sockaddr*)&nnak_src_nla); + + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nnak_src_nla, (struct sockaddr*)&sock->send_addr) != 0)) + { + sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; + return FALSE; + } + +/* NAK_GRP_NLA containers our sock multicast group */ + struct sockaddr_storage nnak_grp_nla; + pgm_nla_to_sockaddr ((AF_INET6 == nnak_src_nla.ss_family) ? &nnak6->nak6_grp_nla_afi : &nnak->nak_grp_nla_afi, (struct sockaddr*)&nnak_grp_nla); + if (PGM_UNLIKELY(pgm_sockaddr_cmp ((struct sockaddr*)&nnak_grp_nla, (struct sockaddr*)&sock->send_gsr.gsr_group) != 0)) + { + sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; + return FALSE; + } + +/* check NNAK list */ + uint_fast8_t nnak_list_len = 0; + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) + { + const struct pgm_opt_length* opt_len = (AF_INET6 == nnak_src_nla.ss_family) ? + (const struct pgm_opt_length*)(nnak6 + 1) : + (const struct pgm_opt_length*)(nnak + 1); + if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) { + sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; + return FALSE; + } + if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) { + sock->cumulative_stats[PGM_PC_SOURCE_NNAK_ERRORS]++; + return FALSE; + } +/* TODO: check for > 16 options & past packet end */ + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); + if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_NAK_LIST) { + nnak_list_len = ( opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(uint8_t) ) / sizeof(uint32_t); + break; + } + } while (!(opt_header->opt_type & PGM_OPT_END)); + } + + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_NNAKS_RECEIVED] += 1 + nnak_list_len; + return TRUE; +} + +/* ACK, sent upstream by one selected ACKER for congestion control feedback. + * + * if ACK is valid, returns TRUE. on error, FALSE is returned. + */ + +bool +pgm_on_ack ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + + pgm_debug ("pgm_on_ack (sock:%p skb:%p)", + (const void*)sock, (const void*)skb); + + sock->cumulative_stats[PGM_PC_SOURCE_ACK_PACKETS_RECEIVED]++; + + if (PGM_UNLIKELY(!pgm_verify_ack (skb))) { + sock->cumulative_stats[PGM_PC_SOURCE_ACK_ERRORS]++; + return FALSE; + } + + if (!sock->use_pgmcc) + return FALSE; + + const struct pgm_ack* ack = (struct pgm_ack*)skb->data; + bool is_acker = FALSE; + +/* check PGMCC feedback option for new elections */ + if (skb->pgm_header->pgm_options & PGM_OPT_PRESENT) + { + const struct pgm_opt_length* opt_len = (const struct pgm_opt_length*)(ack + 1); + if (PGM_UNLIKELY(opt_len->opt_type != PGM_OPT_LENGTH)) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed ACK rejected.")); + return FALSE; + } + if (PGM_UNLIKELY(opt_len->opt_length != sizeof(struct pgm_opt_length))) { + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Malformed ACK rejected.")); + return FALSE; + } + const struct pgm_opt_header* opt_header = (const struct pgm_opt_header*)opt_len; + do { + opt_header = (const struct pgm_opt_header*)((const char*)opt_header + opt_header->opt_length); + if ((opt_header->opt_type & PGM_OPT_MASK) == PGM_OPT_PGMCC_FEEDBACK) { + const struct pgm_opt_pgmcc_feedback* opt_pgmcc_feedback = (const struct pgm_opt_pgmcc_feedback*)(opt_header + 1); + is_acker = on_opt_pgmcc_feedback (sock, skb, opt_pgmcc_feedback); + break; /* ignore other options */ + } + } while (!(opt_header->opt_type & PGM_OPT_END)); + } + +/* ignore ACKs from other receivers or sessions */ + if (!is_acker) + return TRUE; + +/* reset ACK expiration */ + sock->next_crqst = 0; + +/* count new ACK sequences */ + const uint32_t ack_rx_max = ntohl (ack->ack_rx_max); + const int32_t delta = ack_rx_max - sock->ack_rx_max; +/* ignore older ACKs when multiple active ACKers */ + if (pgm_uint32_gt (ack_rx_max, sock->ack_rx_max)) + sock->ack_rx_max = ack_rx_max; + uint32_t ack_bitmap = ntohl (ack->ack_bitmap); + if (delta > 32) sock->ack_bitmap = 0; /* sequence jump ahead beyond past bitmap */ + else if (delta > 0) sock->ack_bitmap <<= delta; /* immediate sequence */ + else if (delta > -32) ack_bitmap <<= -delta; /* repair sequence scoped by bitmap */ + else ack_bitmap = 0; /* old sequence */ + unsigned new_acks = _pgm_popcount (ack_bitmap & ~sock->ack_bitmap); + sock->ack_bitmap |= ack_bitmap; + + if (0 == new_acks) + return TRUE; + + const bool is_congestion_limited = (sock->tokens < pgm_fp8 (1)); + +/* after loss detection cancel any further manipulation of the window + * until feedback is received for the next transmitted packet. + */ + if (sock->is_congested) + { + if (pgm_uint32_lte (ack_rx_max, sock->suspended_sqn)) + { + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC window token manipulation suspended due to congestion (T:%u W:%u)"), + pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); + const uint_fast32_t token_inc = pgm_fp8mul (pgm_fp8 (new_acks), pgm_fp8 (1) + pgm_fp8div (pgm_fp8 (1), sock->cwnd_size)); + sock->tokens = MIN( sock->tokens + token_inc, sock->cwnd_size ); + goto notify_tx; + } + sock->is_congested = FALSE; + } + +/* count outstanding lost sequences */ + const unsigned total_lost = _pgm_popcount (~sock->ack_bitmap); + +/* no detected data loss at ACKer, increase congestion window size */ + if (0 == total_lost) + { + new_acks += sock->acks_after_loss; + sock->acks_after_loss = 0; + uint_fast32_t n = pgm_fp8 (new_acks); + uint_fast32_t token_inc = 0; + +/* slow-start phase, exponential increase to SSTHRESH */ + if (sock->cwnd_size < sock->ssthresh) { + const uint_fast32_t d = MIN( n, sock->ssthresh - sock->cwnd_size ); + n -= d; + token_inc = d + d; + sock->cwnd_size += d; + } + + const uint_fast32_t iw = pgm_fp8div (pgm_fp8 (1), sock->cwnd_size); + +/* linear window increase */ + token_inc += pgm_fp8mul (n, pgm_fp8 (1) + iw); + sock->cwnd_size += pgm_fp8mul (n, iw); + sock->tokens = MIN( sock->tokens + token_inc, sock->cwnd_size ); +// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC++ (T:%u W:%u)"), +// pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); + } + else + { +/* Look for an unacknowledged data packet which is followed by at least three + * acknowledged data packets, then the packet is assumed to be lost and PGMCC + * reacts by halving the window. + * + * Common value will be 0xfffffff7. + */ + sock->acks_after_loss += new_acks; + if (sock->acks_after_loss >= 3) + { + sock->acks_after_loss = 0; + sock->suspended_sqn = ack_rx_max; + sock->is_congested = TRUE; + sock->cwnd_size = pgm_fp8div (sock->cwnd_size, pgm_fp8 (2)); + if (sock->cwnd_size > sock->tokens) + sock->tokens = 0; + else + sock->tokens -= sock->cwnd_size; + sock->ack_bitmap = 0xffffffff; + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC congestion, half window size (T:%u W:%u)"), + pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); + } + } + +/* token is now available so notify tx thread that transmission time is available */ +notify_tx: + if (is_congestion_limited && + sock->tokens >= pgm_fp8 (1)) + { + pgm_notify_send (&sock->ack_notify); + } + return TRUE; +} + +/* ambient/heartbeat SPM's + * + * heartbeat: ihb_tmr decaying between ihb_min and ihb_max 2x after last packet + * + * on success, TRUE is returned, if operation would block, FALSE is returned. + */ + +bool +pgm_send_spm ( + pgm_sock_t* const sock, + const int flags + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != sock->window); + + pgm_debug ("pgm_send_spm (sock:%p flags:%d)", + (const void*)sock, flags); + + size_t tpdu_length = sizeof(struct pgm_header); + if (AF_INET == sock->send_gsr.gsr_group.ss_family) + tpdu_length += sizeof(struct pgm_spm); + else + tpdu_length += sizeof(struct pgm_spm6); + if (sock->use_proactive_parity || + sock->use_ondemand_parity || + sock->is_pending_crqst || + PGM_OPT_FIN == flags) + { + tpdu_length += sizeof(struct pgm_opt_length); +/* forward error correction */ + if (sock->use_proactive_parity || + sock->use_ondemand_parity) + tpdu_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_parity_prm); +/* congestion report request */ + if (sock->is_pending_crqst) + tpdu_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_crqst); +/* end of session */ + if (PGM_OPT_FIN == flags) + tpdu_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fin); + } + char buf[ tpdu_length ]; + if (PGM_UNLIKELY(pgm_mem_gc_friendly)) + memset (buf, 0, tpdu_length); + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_spm* spm = (struct pgm_spm *)(header + 1); + struct pgm_spm6* spm6 = (struct pgm_spm6*)(header + 1); + memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + header->pgm_sport = sock->tsi.sport; + header->pgm_dport = sock->dport; + header->pgm_type = PGM_SPM; + header->pgm_options = 0; + header->pgm_tsdu_length = 0; + +/* SPM */ + spm->spm_sqn = htonl (sock->spm_sqn); + spm->spm_trail = htonl (pgm_txw_trail_atomic (sock->window)); + spm->spm_lead = htonl (pgm_txw_lead_atomic (sock->window)); + spm->spm_reserved = 0; +/* our nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->send_addr, (char*)&spm->spm_nla_afi); + +/* PGM options */ + if (sock->use_proactive_parity || + sock->use_ondemand_parity || + sock->is_pending_crqst || + PGM_OPT_FIN == flags) + { + struct pgm_opt_length* opt_len; + struct pgm_opt_header *opt_header, *last_opt_header; + uint16_t opt_total_length; + + if (AF_INET == sock->send_gsr.gsr_group.ss_family) + opt_header = (struct pgm_opt_header*)(spm + 1); + else + opt_header = (struct pgm_opt_header*)(spm6 + 1); + header->pgm_options |= PGM_OPT_PRESENT; + opt_len = (struct pgm_opt_length*)opt_header; + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_total_length = sizeof(struct pgm_opt_length); + last_opt_header = opt_header = (struct pgm_opt_header*)(opt_len + 1); + +/* OPT_PARITY_PRM */ + if (sock->use_proactive_parity || + sock->use_ondemand_parity) + { + header->pgm_options |= PGM_OPT_NETWORK; + opt_total_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_parity_prm); + opt_header->opt_type = PGM_OPT_PARITY_PRM; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_parity_prm); + struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1); + opt_parity_prm->opt_reserved = (sock->use_proactive_parity ? PGM_PARITY_PRM_PRO : 0) | + (sock->use_ondemand_parity ? PGM_PARITY_PRM_OND : 0); + opt_parity_prm->parity_prm_tgs = htonl (sock->rs_k); + last_opt_header = opt_header; + opt_header = (struct pgm_opt_header*)(opt_parity_prm + 1); + } + +/* OPT_CRQST */ + if (sock->is_pending_crqst) + { + header->pgm_options |= PGM_OPT_NETWORK; + opt_total_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_crqst); + opt_header->opt_type = PGM_OPT_CRQST; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_crqst); + struct pgm_opt_crqst* opt_crqst = (struct pgm_opt_crqst*)(opt_header + 1); +/* request receiver worst path report, OPT_CR_RX_WP */ + opt_crqst->opt_reserved = PGM_OPT_CRQST_RXP; + sock->is_pending_crqst = FALSE; + last_opt_header = opt_header; + opt_header = (struct pgm_opt_header*)(opt_crqst + 1); + } + +/* OPT_FIN */ + if (PGM_OPT_FIN == flags) + { + opt_total_length += sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fin); + opt_header->opt_type = PGM_OPT_FIN; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fin); + struct pgm_opt_fin* opt_fin = (struct pgm_opt_fin*)(opt_header + 1); + opt_fin->opt_reserved = 0; + last_opt_header = opt_header; + opt_header = (struct pgm_opt_header*)(opt_fin + 1); + } + + last_opt_header->opt_type |= PGM_OPT_END; + opt_len->opt_total_length = htons (opt_total_length); + } + +/* checksum optional for SPMs */ + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + + const ssize_t sent = pgm_sendto (sock, + flags != PGM_OPT_SYN && sock->is_controlled_spm, /* rate limited */ + TRUE, /* with router alert */ + buf, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->blocklen = tpdu_length; + return FALSE; + } +/* advance SPM sequence only on successful transmission */ + sock->spm_sqn++; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); + return TRUE; +} + +/* send a NAK confirm (NCF) message with provided sequence number list. + * + * on success, TRUE is returned, returns FALSE if operation would block. + */ + +static +bool +send_ncf ( + pgm_sock_t* const restrict sock, + const struct sockaddr* const restrict nak_src_nla, + const struct sockaddr* const restrict nak_grp_nla, + const uint32_t sequence, + const bool is_parity /* send parity NCF */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != nak_src_nla); + pgm_assert (NULL != nak_grp_nla); + pgm_assert (nak_src_nla->sa_family == nak_grp_nla->sa_family); + +#ifdef SOURCE_DEBUG + char saddr[INET6_ADDRSTRLEN], gaddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop (nak_src_nla, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (nak_grp_nla, gaddr, sizeof(gaddr)); + pgm_debug ("send_ncf (sock:%p nak-src-nla:%s nak-grp-nla:%s sequence:%" PRIu32" is-parity:%s)", + (void*)sock, + saddr, + gaddr, + sequence, + is_parity ? "TRUE": "FALSE" + ); +#endif + + size_t tpdu_length = sizeof(struct pgm_header); + tpdu_length += (AF_INET == nak_src_nla->sa_family) ? sizeof(struct pgm_nak) : sizeof(struct pgm_nak6); + char buf[ tpdu_length ]; + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* ncf = (struct pgm_nak *)(header + 1); + struct pgm_nak6* ncf6 = (struct pgm_nak6*)(header + 1); + memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + header->pgm_sport = sock->tsi.sport; + header->pgm_dport = sock->dport; + header->pgm_type = PGM_NCF; + header->pgm_options = is_parity ? PGM_OPT_PARITY : 0; + header->pgm_tsdu_length = 0; + +/* NCF */ + ncf->nak_sqn = htonl (sequence); + +/* source nla */ + pgm_sockaddr_to_nla (nak_src_nla, (char*)&ncf->nak_src_nla_afi); + +/* group nla */ + pgm_sockaddr_to_nla (nak_grp_nla, (AF_INET6 == nak_src_nla->sa_family) ? (char*)&ncf6->nak6_grp_nla_afi : (char*)&ncf->nak_grp_nla_afi ); + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + TRUE, /* with router alert */ + buf, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) + return FALSE; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); + return TRUE; +} + +/* A NCF packet with a OPT_NAK_LIST option extension + * + * on success, TRUE is returned. on error, FALSE is returned. + */ + +static +bool +send_ncf_list ( + pgm_sock_t* const restrict sock, + const struct sockaddr* const restrict nak_src_nla, + const struct sockaddr* const restrict nak_grp_nla, + struct pgm_sqn_list_t* const restrict sqn_list, /* will change to network-order */ + const bool is_parity /* send parity NCF */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != nak_src_nla); + pgm_assert (NULL != nak_grp_nla); + pgm_assert (sqn_list->len > 1); + pgm_assert (sqn_list->len <= 63); + pgm_assert (nak_src_nla->sa_family == nak_grp_nla->sa_family); + +#ifdef SOURCE_DEBUG + char saddr[INET6_ADDRSTRLEN], gaddr[INET6_ADDRSTRLEN]; + char list[1024]; + pgm_sockaddr_ntop (nak_src_nla, saddr, sizeof(saddr)); + pgm_sockaddr_ntop (nak_grp_nla, gaddr, sizeof(gaddr)); + sprintf (list, "%" PRIu32, sqn_list->sqn[0]); + for (uint_fast8_t i = 1; i < sqn_list->len; i++) { + char sequence[ 2 + strlen("4294967295") ]; + sprintf (sequence, " %" PRIu32, sqn_list->sqn[i]); + strcat (list, sequence); + } + pgm_debug ("send_ncf_list (sock:%p nak-src-nla:%s nak-grp-nla:%s sqn-list:[%s] is-parity:%s)", + (void*)sock, + saddr, + gaddr, + list, + is_parity ? "TRUE": "FALSE" + ); +#endif + + size_t tpdu_length = sizeof(struct pgm_header) + + sizeof(struct pgm_opt_length) + /* includes header */ + sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ); + tpdu_length += (AF_INET == nak_src_nla->sa_family) ? sizeof(struct pgm_nak) : sizeof(struct pgm_nak6); + char buf[ tpdu_length ]; + struct pgm_header* header = (struct pgm_header*)buf; + struct pgm_nak* ncf = (struct pgm_nak *)(header + 1); + struct pgm_nak6* ncf6 = (struct pgm_nak6*)(header + 1); + memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + header->pgm_sport = sock->tsi.sport; + header->pgm_dport = sock->dport; + header->pgm_type = PGM_NCF; + header->pgm_options = is_parity ? (PGM_OPT_PRESENT | PGM_OPT_NETWORK | PGM_OPT_PARITY) : (PGM_OPT_PRESENT | PGM_OPT_NETWORK); + header->pgm_tsdu_length = 0; +/* NCF */ + ncf->nak_sqn = htonl (sqn_list->sqn[0]); + +/* source nla */ + pgm_sockaddr_to_nla (nak_src_nla, (char*)&ncf->nak_src_nla_afi); + +/* group nla */ + pgm_sockaddr_to_nla (nak_grp_nla, (AF_INET6 == nak_src_nla->sa_family) ? (char*)&ncf6->nak6_grp_nla_afi : (char*)&ncf->nak_grp_nla_afi ); + +/* OPT_NAK_LIST */ + struct pgm_opt_length* opt_len = (AF_INET6 == nak_src_nla->sa_family) ? (struct pgm_opt_length*)(ncf6 + 1) : (struct pgm_opt_length*)(ncf + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(uint32_t) ); + struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); + opt_nak_list->opt_reserved = 0; +/* to network-order */ + for (uint_fast8_t i = 1; i < sqn_list->len; i++) + opt_nak_list->opt_sqn[i-1] = htonl (sqn_list->sqn[i]); + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial (buf, tpdu_length, 0)); + + const ssize_t sent = pgm_sendto (sock, + FALSE, /* not rate limited */ + TRUE, /* with router alert */ + buf, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) + return FALSE; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length); + return TRUE; +} + +/* cancel any pending heartbeat SPM and schedule a new one + */ + +static +void +reset_heartbeat_spm ( + pgm_sock_t*const sock, + const pgm_time_t now + ) +{ + pgm_mutex_lock (&sock->timer_mutex); + const pgm_time_t next_poll = sock->next_poll; + const pgm_time_t spm_heartbeat_interval = sock->spm_heartbeat_interval[ sock->spm_heartbeat_state = 1 ]; + sock->next_heartbeat_spm = now + spm_heartbeat_interval; + if (pgm_time_after( next_poll, sock->next_heartbeat_spm )) + { + sock->next_poll = sock->next_heartbeat_spm; + if (!sock->is_pending_read) { + pgm_notify_send (&sock->pending_notify); + sock->is_pending_read = TRUE; + } + } + pgm_mutex_unlock (&sock->timer_mutex); +} + +/* state helper for resuming sends + */ +#define STATE(x) (sock->pkt_dontwait_state.x) + +/* send one PGM data packet, transmit window owned memory. + * + * On success, returns PGM_IO_STATUS_NORMAL and the number of data bytes pushed + * into the transmit window and attempted to send to the socket layer is saved + * into bytes_written. On non-blocking sockets, PGM_IO_STATUS_WOULD_BLOCK is + * returned if the send would block. PGM_IO_STATUS_RATE_LIMITED is returned if + * the packet sizes would exceed the current rate limit. + * + * ! always returns successful if data is pushed into the transmit window, even if + * sendto() double fails ¡ we don't want the application to try again as that is the + * reliable socks role. + */ + +static +int +send_odata ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t* const restrict skb, + size_t* restrict bytes_written + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + pgm_assert (skb->len <= sock->max_tsdu); + + pgm_debug ("send_odata (sock:%p skb:%p bytes-written:%p)", + (void*)sock, (void*)skb, (void*)bytes_written); + + const uint16_t tsdu_length = skb->len; + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + const size_t tpdu_length = tsdu_length + pgm_pkt_offset (FALSE, pgmcc_family); + +/* continue if send would block */ + if (sock->is_apdu_eagain) { + STATE(skb)->tstamp = pgm_time_update_now(); + goto retry_send; + } + +/* add PGM header to skbuff */ + STATE(skb) = pgm_skb_get(skb); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = sock->use_pgmcc ? PGM_OPT_PRESENT : 0; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (tsdu_length); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + STATE(skb)->pgm_header->pgm_checksum = 0; + void* data = STATE(skb)->pgm_data + 1; + if (sock->use_pgmcc) { + struct pgm_opt_length* opt_len = data; + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_PGMCC_DATA | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)); + struct pgm_opt_pgmcc_data* pgmcc_data = (struct pgm_opt_pgmcc_data*)(opt_header + 1); + struct pgm_opt6_pgmcc_data* pgmcc_data6 = (struct pgm_opt6_pgmcc_data*)(opt_header + 1); + + pgmcc_data->opt_tstamp = htonl (pgm_to_msecs (STATE(skb)->tstamp)); +/* acker nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->acker_nla, (char*)&pgmcc_data->opt_nla_afi); + if (AF_INET6 == sock->acker_nla.ss_family) + data = (char*)pgmcc_data6 + sizeof(struct pgm_opt6_pgmcc_data); + else + data = (char*)pgmcc_data + sizeof(struct pgm_opt_pgmcc_data); + } + const size_t pgm_header_len = (char*)data - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial (data, tsdu_length, 0); + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + +/* the transmit window MUST check the user count to ensure it does not + * attempt to send a repair-data packet based on in transit original data. + */ + + ssize_t sent; +retry_send: + +/* congestion control */ + if (sock->use_pgmcc && + sock->tokens < pgm_fp8 (1)) + { +// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Token limit reached.")); + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + return PGM_IO_STATUS_CONGESTION; /* peer expiration to re-elect ACKer */ + } + + sent = pgm_sendto (sock, + sock->is_controlled_odata, /* rate limited */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + if (sock->use_pgmcc) { + sock->tokens -= pgm_fp8 (1); + sock->ack_expiry = STATE(skb)->tstamp + sock->ack_expiry_ivl; + } + + if (PGM_LIKELY((size_t)sent == tpdu_length)) { + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += tsdu_length; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] ++; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); + } + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + +/* remove applications reference to skbuff */ + pgm_free_skb (STATE(skb)); + if (bytes_written) + *bytes_written = tsdu_length; + return PGM_IO_STATUS_NORMAL; +} + +/* send one PGM original data packet, callee owned memory. + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ + +static +int +send_odata_copy ( + pgm_sock_t* const restrict sock, + const void* restrict tsdu, + const uint16_t tsdu_length, + size_t* restrict bytes_written + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (tsdu_length <= sock->max_tsdu); + if (PGM_LIKELY(tsdu_length)) pgm_assert (NULL != tsdu); + + pgm_debug ("send_odata_copy (sock:%p tsdu:%p tsdu_length:%u bytes-written:%p)", + (void*)sock, tsdu, tsdu_length, (void*)bytes_written); + + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + const size_t tpdu_length = tsdu_length + pgm_pkt_offset (FALSE, pgmcc_family); + +/* continue if blocked mid-apdu, updating timestamp */ + if (sock->is_apdu_eagain) { + STATE(skb)->tstamp = pgm_time_update_now(); + goto retry_send; + } + + STATE(skb) = pgm_alloc_skb (sock->max_tpdu); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + pgm_skb_reserve (STATE(skb), pgm_pkt_offset (FALSE, pgmcc_family)); + pgm_skb_put (STATE(skb), tsdu_length); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = sock->use_pgmcc ? PGM_OPT_PRESENT : 0; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (tsdu_length); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + STATE(skb)->pgm_header->pgm_checksum = 0; + void* data = STATE(skb)->pgm_data + 1; + if (sock->use_pgmcc) { + struct pgm_opt_length* opt_len = data; + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_PGMCC_DATA | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + ((AF_INET6 == sock->acker_nla.ss_family) ? + sizeof(struct pgm_opt6_pgmcc_data) : + sizeof(struct pgm_opt_pgmcc_data)); + struct pgm_opt_pgmcc_data* pgmcc_data = (struct pgm_opt_pgmcc_data*)(opt_header + 1); +/* unused */ +// struct pgm_opt6_pgmcc_data* pgmcc_data6 = (struct pgm_opt6_pgmcc_data*)(opt_header + 1); + + pgmcc_data->opt_reserved = 0; + pgmcc_data->opt_tstamp = htonl (pgm_to_msecs (STATE(skb)->tstamp)); +/* acker nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->acker_nla, (char*)&pgmcc_data->opt_nla_afi); + data = (char*)opt_header + opt_header->opt_length; + } + const size_t pgm_header_len = (char*)data - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial_copy (tsdu, data, tsdu_length, 0); + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + + ssize_t sent; +retry_send: + +/* congestion control */ + if (sock->use_pgmcc && + sock->tokens < pgm_fp8 (1)) + { +// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Token limit reached.")); + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + return PGM_IO_STATUS_CONGESTION; + } + + sent = pgm_sendto (sock, + sock->is_controlled_odata, /* rate limited */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; + } + + if (sock->use_pgmcc) { + sock->tokens -= pgm_fp8 (1); + pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("PGMCC tokens-- (T:%u W:%u)"), + pgm_fp8tou (sock->tokens), pgm_fp8tou (sock->cwnd_size)); + sock->ack_expiry = STATE(skb)->tstamp + sock->ack_expiry_ivl; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + + if (PGM_LIKELY((size_t)sent == tpdu_length)) { + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += tsdu_length; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] ++; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); + } + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + +/* return data payload length sent */ + if (bytes_written) + *bytes_written = tsdu_length; + return PGM_IO_STATUS_NORMAL; +} + +/* send one PGM original data packet, callee owned scatter/gather io vector + * + * ⎢ DATA₀ ⎢ + * ⎢ DATA₁ ⎢ → send_odatav() → ⎢ TSDU₀ ⎢ → libc + * ⎢ ⋮ ⎢ + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ + +static +int +send_odatav ( + pgm_sock_t* const restrict sock, + const struct pgm_iovec* const restrict vector, + const unsigned count, /* number of items in vector */ + size_t* restrict bytes_written + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (count <= PGM_MAX_FRAGMENTS); + if (PGM_LIKELY(count)) pgm_assert (NULL != vector); + + pgm_debug ("send_odatav (sock:%p vector:%p count:%u bytes-written:%p)", + (const void*)sock, (const void*)vector, count, (const void*)bytes_written); + + if (PGM_UNLIKELY(0 == count)) + return send_odata_copy (sock, NULL, 0, bytes_written); + +/* continue if blocked on send */ + if (sock->is_apdu_eagain) + goto retry_send; + + STATE(tsdu_length) = 0; + for (unsigned i = 0; i < count; i++) + { +#ifdef TRANSPORT_DEBUG + if (PGM_LIKELY(vector[i].iov_len)) { + pgm_assert( vector[i].iov_base ); + } +#endif + STATE(tsdu_length) += vector[i].iov_len; + } + pgm_return_val_if_fail (STATE(tsdu_length) <= sock->max_tsdu, PGM_IO_STATUS_ERROR); + + STATE(skb) = pgm_alloc_skb (sock->max_tpdu); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + pgm_skb_reserve (STATE(skb), pgm_pkt_offset (FALSE, pgmcc_family)); + pgm_skb_put (STATE(skb), STATE(tsdu_length)); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->data; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = 0; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + STATE(skb)->pgm_header->pgm_checksum = 0; + const size_t pgm_header_len = (char*)(STATE(skb)->pgm_data + 1) - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + +/* unroll first iteration to make friendly branch prediction */ + char* dst = (char*)(STATE(skb)->pgm_data + 1); + STATE(unfolded_odata) = pgm_csum_partial_copy ((const char*)vector[0].iov_base, dst, vector[0].iov_len, 0); + +/* iterate over one or more vector elements to perform scatter/gather checksum & copy */ + for (unsigned i = 1; i < count; i++) { + dst += vector[i-1].iov_len; + const uint32_t unfolded_element = pgm_csum_partial_copy ((const char*)vector[i].iov_base, dst, vector[i].iov_len, 0); + STATE(unfolded_odata) = pgm_csum_block_add (STATE(unfolded_odata), unfolded_element, vector[i-1].iov_len); + } + + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + + ssize_t sent; + size_t tpdu_length; +retry_send: + pgm_assert ((char*)STATE(skb)->tail > (char*)STATE(skb)->head); + tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; + sent = pgm_sendto (sock, + sock->is_controlled_odata, /* rate limited */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + + if (PGM_LIKELY((size_t)sent == STATE(skb)->len)) { + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += STATE(tsdu_length); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] ++; + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); + } + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + +/* return data payload length sent */ + if (bytes_written) + *bytes_written = STATE(tsdu_length); + return PGM_IO_STATUS_NORMAL; +} + +/* send PGM original data, callee owned memory. if larger than maximum TPDU + * size will be fragmented. + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ + +static +int +send_apdu ( + pgm_sock_t* const restrict sock, + const void* restrict apdu, + const size_t apdu_length, + size_t* restrict bytes_written + ) +{ + size_t bytes_sent = 0; /* counted at IP layer */ + unsigned packets_sent = 0; /* IP packets */ + size_t data_bytes_sent = 0; + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + + pgm_assert (NULL != sock); + pgm_assert (NULL != apdu); + +/* continue if blocked mid-apdu */ + if (sock->is_apdu_eagain) + goto retry_send; + +/* if non-blocking calculate total wire size and check rate limit */ + STATE(is_rate_limited) = FALSE; + if (sock->is_nonblocking && sock->is_controlled_odata) + { + const size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); + size_t tpdu_length = 0; + size_t offset_ = 0; + do { + const uint16_t tsdu_length = MIN( source_max_tsdu (sock, TRUE), apdu_length - offset_ ); + tpdu_length += sock->iphdr_len + header_length + tsdu_length; + offset_ += tsdu_length; + } while (offset_ < apdu_length); + +/* calculation includes one iphdr length already */ + if (!pgm_rate_check (&sock->rate_control, + tpdu_length - sock->iphdr_len, + sock->is_nonblocking)) + { + sock->blocklen = tpdu_length; + return PGM_IO_STATUS_RATE_LIMITED; + } + STATE(is_rate_limited) = TRUE; + } + + STATE(data_bytes_offset) = 0; + STATE(first_sqn) = pgm_txw_next_lead(sock->window); + + do { +/* retrieve packet storage from transmit window */ + size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); + STATE(tsdu_length) = MIN( source_max_tsdu (sock, TRUE), apdu_length - STATE(data_bytes_offset) ); + + STATE(skb) = pgm_alloc_skb (sock->max_tpdu); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + pgm_skb_reserve (STATE(skb), header_length); + pgm_skb_put (STATE(skb), STATE(tsdu_length)); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = PGM_OPT_PRESENT; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + +/* OPT_LENGTH */ + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(STATE(skb)->pgm_data + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment) ); +/* OPT_FRAGMENT */ + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment); + STATE(skb)->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + STATE(skb)->pgm_opt_fragment->opt_reserved = 0; + STATE(skb)->pgm_opt_fragment->opt_sqn = htonl (STATE(first_sqn)); + STATE(skb)->pgm_opt_fragment->opt_frag_off = htonl (STATE(data_bytes_offset)); + STATE(skb)->pgm_opt_fragment->opt_frag_len = htonl (apdu_length); + +/* TODO: the assembly checksum & copy routine is faster than memcpy & pgm_cksum on >= opteron hardware */ + STATE(skb)->pgm_header->pgm_checksum = 0; + const size_t pgm_header_len = (char*)(STATE(skb)->pgm_opt_fragment + 1) - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial_copy ((const char*)apdu + STATE(data_bytes_offset), STATE(skb)->pgm_opt_fragment + 1, STATE(tsdu_length), 0); + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + + ssize_t sent; + size_t tpdu_length; +retry_send: + pgm_assert ((char*)STATE(skb)->tail > (char*)STATE(skb)->head); + tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; + sent = pgm_sendto (sock, + !STATE(is_rate_limited), /* rate limit on blocking */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + goto blocked; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + if (PGM_LIKELY((size_t)sent == tpdu_length)) { + bytes_sent += tpdu_length + sock->iphdr_len; /* as counted at IP layer */ + packets_sent++; /* IP packets */ + data_bytes_sent += STATE(tsdu_length); + } + + STATE(data_bytes_offset) += STATE(tsdu_length); + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + + } while ( STATE(data_bytes_offset) < apdu_length); + pgm_assert( STATE(data_bytes_offset) == apdu_length ); + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + if (bytes_written) + *bytes_written = apdu_length; + return PGM_IO_STATUS_NORMAL; + +blocked: + if (bytes_sent) { + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + } + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; +} + +/* Send one APDU, whether it fits within one TPDU or more. + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ +int +pgm_send ( + pgm_sock_t* const restrict sock, + const void* restrict apdu, + const size_t apdu_length, + size_t* restrict bytes_written + ) +{ + pgm_debug ("pgm_send (sock:%p apdu:%p apdu-length:%zu bytes-written:%p)", + (void*)sock, apdu, apdu_length, (void*)bytes_written); + +/* parameters */ + pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); + if (PGM_LIKELY(apdu_length)) pgm_return_val_if_fail (NULL != apdu, PGM_IO_STATUS_ERROR); + +/* shutdown */ + if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + +/* state */ + if (PGM_UNLIKELY(!sock->is_bound || + sock->is_destroyed || + apdu_length > sock->max_apdu)) + { + pgm_rwlock_reader_unlock (&sock->lock); + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + } + +/* source */ + pgm_mutex_lock (&sock->source_mutex); + +/* pass on non-fragment calls */ + if (apdu_length <= sock->max_tsdu) + { + const int status = send_odata_copy (sock, apdu, apdu_length, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + + const int status = send_apdu (sock, apdu, apdu_length, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; +} + +/* send PGM original data, callee owned scatter/gather IO vector. if larger than maximum TPDU + * size will be fragmented. + * + * is_one_apdu = true: + * + * ⎢ DATA₀ ⎢ + * ⎢ DATA₁ ⎢ → pgm_sendv() → ⎢ ⋯ TSDU₁ TSDU₀ ⎢ → libc + * ⎢ ⋮ ⎢ + * + * is_one_apdu = false: + * + * ⎢ APDU₀ ⎢ ⎢ ⋯ TSDU₁,₀ TSDU₀,₀ ⎢ + * ⎢ APDU₁ ⎢ → pgm_sendv() → ⎢ ⋯ TSDU₁,₁ TSDU₀,₁ ⎢ → libc + * ⎢ ⋮ ⎢ ⎢ ⋮ ⋮ ⎢ + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ + +int +pgm_sendv ( + pgm_sock_t* const restrict sock, + const struct pgm_iovec* const restrict vector, + const unsigned count, /* number of items in vector */ + const bool is_one_apdu, /* true = vector = apdu, false = vector::iov_base = apdu */ + size_t* restrict bytes_written + ) +{ + pgm_debug ("pgm_sendv (sock:%p vector:%p count:%u is-one-apdu:%s bytes-written:%p)", + (const void*)sock, + (const void*)vector, + count, + is_one_apdu ? "TRUE" : "FALSE", + (const void*)bytes_written); + + pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); + pgm_return_val_if_fail (count <= PGM_MAX_FRAGMENTS, PGM_IO_STATUS_ERROR); + if (PGM_LIKELY(count)) pgm_return_val_if_fail (NULL != vector, PGM_IO_STATUS_ERROR); + if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + if (PGM_UNLIKELY(!sock->is_bound || + sock->is_destroyed)) + { + pgm_rwlock_reader_unlock (&sock->lock); + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + } + + pgm_mutex_lock (&sock->source_mutex); + +/* pass on zero length as cannot count vector lengths */ + if (PGM_UNLIKELY(0 == count)) + { + const int status = send_odata_copy (sock, NULL, count, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + + size_t bytes_sent = 0; + unsigned packets_sent = 0; + size_t data_bytes_sent = 0; + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + +/* continue if blocked mid-apdu */ + if (sock->is_apdu_eagain) { + if (is_one_apdu) { + if (STATE(apdu_length) <= sock->max_tsdu) + { + const int status = send_odatav (sock, vector, count, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + else + goto retry_one_apdu_send; + } else { + goto retry_send; + } + } + +/* calculate (total) APDU length */ + STATE(apdu_length) = 0; + for (unsigned i = 0; i < count; i++) + { +#ifdef TRANSPORT_DEBUG + if (PGM_LIKELY(vector[i].iov_len)) { + pgm_assert( vector[i].iov_base ); + } +#endif + if (!is_one_apdu && + vector[i].iov_len > sock->max_apdu) + { + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + } + STATE(apdu_length) += vector[i].iov_len; + } + +/* pass on non-fragment calls */ + if (is_one_apdu) { + if (STATE(apdu_length) <= sock->max_tsdu) { + const int status = send_odatav (sock, vector, count, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } else if (STATE(apdu_length) > sock->max_apdu) { + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + } + } + +/* if non-blocking calculate total wire size and check rate limit */ + STATE(is_rate_limited) = FALSE; + if (sock->is_nonblocking && sock->is_controlled_odata) + { + const size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); + size_t tpdu_length = 0; + size_t offset_ = 0; + do { + const uint16_t tsdu_length = MIN( source_max_tsdu (sock, TRUE), STATE(apdu_length) - offset_ ); + tpdu_length += sock->iphdr_len + header_length + tsdu_length; + offset_ += tsdu_length; + } while (offset_ < STATE(apdu_length)); + +/* calculation includes one iphdr length already */ + if (!pgm_rate_check (&sock->rate_control, + tpdu_length - sock->iphdr_len, + sock->is_nonblocking)) + { + sock->blocklen = tpdu_length; + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_RATE_LIMITED; + } + STATE(is_rate_limited) = TRUE; + } + +/* non-fragmented packets can be forwarded onto basic send() */ + if (!is_one_apdu) + { + for (STATE(data_pkt_offset) = 0; STATE(data_pkt_offset) < count; STATE(data_pkt_offset)++) + { + size_t wrote_bytes; + int status; +retry_send: + status = send_apdu (sock, + vector[STATE(data_pkt_offset)].iov_base, + vector[STATE(data_pkt_offset)].iov_len, + &wrote_bytes); + switch (status) { + case PGM_IO_STATUS_NORMAL: + break; + case PGM_IO_STATUS_WOULD_BLOCK: + case PGM_IO_STATUS_RATE_LIMITED: + sock->is_apdu_eagain = TRUE; + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + case PGM_IO_STATUS_ERROR: + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + default: + pgm_assert_not_reached(); + } + data_bytes_sent += wrote_bytes; + } + + sock->is_apdu_eagain = FALSE; + if (bytes_written) + *bytes_written = data_bytes_sent; + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_NORMAL; + } + + STATE(data_bytes_offset) = 0; + STATE(vector_index) = 0; + STATE(vector_offset) = 0; + + STATE(first_sqn) = pgm_txw_next_lead(sock->window); + + do { +/* retrieve packet storage from transmit window */ + size_t header_length = pgm_pkt_offset (TRUE, pgmcc_family); + STATE(tsdu_length) = MIN( source_max_tsdu (sock, TRUE), STATE(apdu_length) - STATE(data_bytes_offset) ); + STATE(skb) = pgm_alloc_skb (sock->max_tpdu); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + pgm_skb_reserve (STATE(skb), header_length); + pgm_skb_put (STATE(skb), STATE(tsdu_length)); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = PGM_OPT_PRESENT; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + +/* OPT_LENGTH */ + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(STATE(skb)->pgm_data + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment) ); +/* OPT_FRAGMENT */ + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment); + STATE(skb)->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + STATE(skb)->pgm_opt_fragment->opt_reserved = 0; + STATE(skb)->pgm_opt_fragment->opt_sqn = htonl (STATE(first_sqn)); + STATE(skb)->pgm_opt_fragment->opt_frag_off = htonl (STATE(data_bytes_offset)); + STATE(skb)->pgm_opt_fragment->opt_frag_len = htonl (STATE(apdu_length)); + +/* checksum & copy */ + STATE(skb)->pgm_header->pgm_checksum = 0; + const size_t pgm_header_len = (char*)(STATE(skb)->pgm_opt_fragment + 1) - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + +/* iterate over one or more vector elements to perform scatter/gather checksum & copy + * + * STATE(vector_index) - index into application scatter/gather vector + * STATE(vector_offset) - current offset into current vector element + * STATE(unfolded_odata)- checksum accumulator + */ + const char* src = (const char*)vector[STATE(vector_index)].iov_base + STATE(vector_offset); + char* dst = (char*)(STATE(skb)->pgm_opt_fragment + 1); + size_t src_length = vector[STATE(vector_index)].iov_len - STATE(vector_offset); + size_t dst_length = 0; + size_t copy_length = MIN( STATE(tsdu_length), src_length ); + STATE(unfolded_odata) = pgm_csum_partial_copy (src, dst, copy_length, 0); + + for(;;) + { + if (copy_length == src_length) { +/* application packet complete */ + STATE(vector_index)++; + STATE(vector_offset) = 0; + } else { +/* data still remaining */ + STATE(vector_offset) += copy_length; + } + + dst_length += copy_length; + +/* sock packet complete */ + if (dst_length == STATE(tsdu_length)) + break; + + src = (const char*)vector[STATE(vector_index)].iov_base + STATE(vector_offset); + dst += copy_length; + src_length = vector[STATE(vector_index)].iov_len - STATE(vector_offset); + copy_length = MIN( STATE(tsdu_length) - dst_length, src_length ); + const uint32_t unfolded_element = pgm_csum_partial_copy (src, dst, copy_length, 0); + STATE(unfolded_odata) = pgm_csum_block_add (STATE(unfolded_odata), unfolded_element, dst_length); + } + + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + + ssize_t sent; + size_t tpdu_length; +retry_one_apdu_send: + tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; + sent = pgm_sendto (sock, + !STATE(is_rate_limited), /* rate limited on blocking */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + goto blocked; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + if (PGM_LIKELY((size_t)sent == tpdu_length)) { + bytes_sent += tpdu_length + sock->iphdr_len; /* as counted at IP layer */ + packets_sent++; /* IP packets */ + data_bytes_sent += STATE(tsdu_length); + } + + STATE(data_bytes_offset) += STATE(tsdu_length); + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + + } while ( STATE(data_bytes_offset) < STATE(apdu_length) ); + pgm_assert( STATE(data_bytes_offset) == STATE(apdu_length) ); + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + if (bytes_written) + *bytes_written = STATE(apdu_length); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_NORMAL; + +blocked: + if (bytes_sent) { + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + } + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; +} + +/* send PGM original data, transmit window owned scatter/gather IO vector. + * + * ⎢ TSDU₀ ⎢ + * ⎢ TSDU₁ ⎢ → pgm_send_skbv() → ⎢ ⋯ TSDU₁ TSDU₀ ⎢ → libc + * ⎢ ⋮ ⎢ + * + * on success, returns PGM_IO_STATUS_NORMAL, on block for non-blocking sockets + * returns PGM_IO_STATUS_WOULD_BLOCK, returns PGM_IO_STATUS_RATE_LIMITED if + * packet size exceeds the current rate limit. + */ + +int +pgm_send_skbv ( + pgm_sock_t* const restrict sock, + struct pgm_sk_buff_t** const restrict vector, /* array of skb pointers vs. array of skbs */ + const unsigned count, + const bool is_one_apdu, /* true: vector = apdu, false: vector::iov_base = apdu */ + size_t* restrict bytes_written + ) +{ + pgm_debug ("pgm_send_skbv (sock:%p vector:%p count:%u is-one-apdu:%s bytes-written:%p)", + (const void*)sock, + (const void*)vector, + count, + is_one_apdu ? "TRUE" : "FALSE", + (const void*)bytes_written); + + pgm_return_val_if_fail (NULL != sock, PGM_IO_STATUS_ERROR); + pgm_return_val_if_fail (count <= PGM_MAX_FRAGMENTS, PGM_IO_STATUS_ERROR); + if (PGM_LIKELY(count)) pgm_return_val_if_fail (NULL != vector, PGM_IO_STATUS_ERROR); + if (PGM_UNLIKELY(!pgm_rwlock_reader_trylock (&sock->lock))) + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + if (PGM_UNLIKELY(!sock->is_bound || + sock->is_destroyed)) + { + pgm_rwlock_reader_unlock (&sock->lock); + pgm_return_val_if_reached (PGM_IO_STATUS_ERROR); + } + + pgm_mutex_lock (&sock->source_mutex); + +/* pass on zero length as cannot count vector lengths */ + if (PGM_UNLIKELY(0 == count)) + { + const int status = send_odata_copy (sock, NULL, count, bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + else if (1 == count) + { + const int status = send_odata (sock, vector[0], bytes_written); + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return status; + } + + size_t bytes_sent = 0; + unsigned packets_sent = 0; + size_t data_bytes_sent = 0; + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + +/* continue if blocked mid-apdu */ + if (sock->is_apdu_eagain) + goto retry_send; + + STATE(is_rate_limited) = FALSE; + if (sock->is_nonblocking && sock->is_controlled_odata) + { + size_t total_tpdu_length = 0; + for (unsigned i = 0; i < count; i++) + total_tpdu_length += sock->iphdr_len + pgm_pkt_offset (is_one_apdu, pgmcc_family) + vector[i]->len; + +/* calculation includes one iphdr length already */ + if (!pgm_rate_check (&sock->rate_control, + total_tpdu_length - sock->iphdr_len, + sock->is_nonblocking)) + { + sock->blocklen = total_tpdu_length; + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_RATE_LIMITED; + } + STATE(is_rate_limited) = TRUE; + } + + if (is_one_apdu) + { + STATE(apdu_length) = 0; + STATE(first_sqn) = pgm_txw_next_lead(sock->window); + for (unsigned i = 0; i < count; i++) + { + if (PGM_UNLIKELY(vector[i]->len > sock->max_tsdu_fragment)) { + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_ERROR; + } + STATE(apdu_length) += vector[i]->len; + } + if (PGM_UNLIKELY(STATE(apdu_length) > sock->max_apdu)) { + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_ERROR; + } + } + + for (STATE(vector_index) = 0; STATE(vector_index) < count; STATE(vector_index)++) + { + STATE(tsdu_length) = vector[STATE(vector_index)]->len; + + STATE(skb) = pgm_skb_get(vector[STATE(vector_index)]); + STATE(skb)->sock = sock; + STATE(skb)->tstamp = pgm_time_update_now(); + + STATE(skb)->pgm_header = (struct pgm_header*)STATE(skb)->head; + STATE(skb)->pgm_data = (struct pgm_data*)(STATE(skb)->pgm_header + 1); + memcpy (STATE(skb)->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + STATE(skb)->pgm_header->pgm_sport = sock->tsi.sport; + STATE(skb)->pgm_header->pgm_dport = sock->dport; + STATE(skb)->pgm_header->pgm_type = PGM_ODATA; + STATE(skb)->pgm_header->pgm_options = is_one_apdu ? PGM_OPT_PRESENT : 0; + STATE(skb)->pgm_header->pgm_tsdu_length = htons (STATE(tsdu_length)); + +/* ODATA */ + STATE(skb)->pgm_data->data_sqn = htonl (pgm_txw_next_lead(sock->window)); + STATE(skb)->pgm_data->data_trail = htonl (pgm_txw_trail(sock->window)); + + if (is_one_apdu) + { +/* OPT_LENGTH */ + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(STATE(skb)->pgm_data + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment) ); +/* OPT_FRAGMENT */ + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment); + STATE(skb)->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + STATE(skb)->pgm_opt_fragment->opt_reserved = 0; + STATE(skb)->pgm_opt_fragment->opt_sqn = htonl (STATE(first_sqn)); + STATE(skb)->pgm_opt_fragment->opt_frag_off = htonl (STATE(data_bytes_offset)); + STATE(skb)->pgm_opt_fragment->opt_frag_len = htonl (STATE(apdu_length)); + + pgm_assert (STATE(skb)->data == (STATE(skb)->pgm_opt_fragment + 1)); + } + else + { + pgm_assert (STATE(skb)->data == (STATE(skb)->pgm_data + 1)); + } + +/* TODO: the assembly checksum & copy routine is faster than memcpy & pgm_cksum on >= opteron hardware */ + STATE(skb)->pgm_header->pgm_checksum = 0; + pgm_assert ((char*)STATE(skb)->data > (char*)STATE(skb)->pgm_header); + const size_t pgm_header_len = (char*)STATE(skb)->data - (char*)STATE(skb)->pgm_header; + const uint32_t unfolded_header = pgm_csum_partial (STATE(skb)->pgm_header, pgm_header_len, 0); + STATE(unfolded_odata) = pgm_csum_partial ((char*)STATE(skb)->data, STATE(tsdu_length), 0); + STATE(skb)->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, STATE(unfolded_odata), pgm_header_len)); + +/* add to transmit window, skb::data set to payload */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, STATE(skb)); + pgm_spinlock_unlock (&sock->txw_spinlock); + ssize_t sent; + size_t tpdu_length; +retry_send: + pgm_assert ((char*)STATE(skb)->tail > (char*)STATE(skb)->head); + tpdu_length = (char*)STATE(skb)->tail - (char*)STATE(skb)->head; + sent = pgm_sendto (sock, + !STATE(is_rate_limited), /* rate limited on blocking */ + FALSE, /* regular socket */ + STATE(skb)->head, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + if (sent < 0 && (EAGAIN == errno || ENOBUFS == errno)) { + sock->is_apdu_eagain = TRUE; + sock->blocklen = tpdu_length; + goto blocked; + } + +/* save unfolded odata for retransmissions */ + pgm_txw_set_unfolded_checksum (STATE(skb), STATE(unfolded_odata)); + + if (PGM_LIKELY((size_t)sent == tpdu_length)) { + bytes_sent += tpdu_length + sock->iphdr_len; /* as counted at IP layer */ + packets_sent++; /* IP packets */ + data_bytes_sent += STATE(tsdu_length); + } + + pgm_free_skb (STATE(skb)); + STATE(data_bytes_offset) += STATE(tsdu_length); + +/* check for end of transmission group */ + if (sock->use_proactive_parity) { + const uint32_t odata_sqn = ntohl (STATE(skb)->pgm_data->data_sqn); + const uint32_t tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + if (!((odata_sqn + 1) & ~tg_sqn_mask)) + pgm_schedule_proactive_nak (sock, odata_sqn & tg_sqn_mask); + } + + } +#ifdef TRANSPORT_DEBUG + if (is_one_apdu) + { + pgm_assert( STATE(data_bytes_offset) == STATE(apdu_length) ); + } +#endif + + sock->is_apdu_eagain = FALSE; + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + if (bytes_written) + *bytes_written = data_bytes_sent; + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + return PGM_IO_STATUS_NORMAL; + +blocked: + if (bytes_sent) { + reset_heartbeat_spm (sock, STATE(skb)->tstamp); + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], bytes_sent); + sock->cumulative_stats[PGM_PC_SOURCE_DATA_MSGS_SENT] += packets_sent; + sock->cumulative_stats[PGM_PC_SOURCE_DATA_BYTES_SENT] += data_bytes_sent; + } + pgm_mutex_unlock (&sock->source_mutex); + pgm_rwlock_reader_unlock (&sock->lock); + if (EAGAIN == errno) { + if (sock->use_pgmcc) + pgm_notify_clear (&sock->ack_notify); + return PGM_IO_STATUS_WOULD_BLOCK; + } + return PGM_IO_STATUS_RATE_LIMITED; +} + +/* cleanup resuming send state helper + */ +#undef STATE + +/* send repair packet. + * + * on success, TRUE is returned. on error, FALSE is returned. + */ + +static +bool +send_rdata ( + pgm_sock_t* restrict sock, + struct pgm_sk_buff_t* restrict skb + ) +{ +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (NULL != skb); + pgm_assert ((char*)skb->tail > (char*)skb->head); + + const size_t tpdu_length = (char*)skb->tail - (char*)skb->head; + +/* update previous odata/rdata contents */ + struct pgm_header* header = skb->pgm_header; + struct pgm_data* rdata = skb->pgm_data; + header->pgm_type = PGM_RDATA; +/* RDATA */ + rdata->data_trail = htonl (pgm_txw_trail(sock->window)); + + header->pgm_checksum = 0; + const size_t pgm_header_len = tpdu_length - ntohs(header->pgm_tsdu_length); + uint32_t unfolded_header = pgm_csum_partial (header, pgm_header_len, 0); + uint32_t unfolded_odata = pgm_csum_partial (skb->data, ntohs(header->pgm_tsdu_length), 0); + header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, unfolded_odata, pgm_header_len)); + +/* congestion control */ + if (sock->use_pgmcc && + sock->tokens < pgm_fp8 (1)) + { +// pgm_trace (PGM_LOG_ROLE_CONGESTION_CONTROL,_("Token limit reached.")); + sock->blocklen = tpdu_length; + return FALSE; + } + + const ssize_t sent = pgm_sendto (sock, + sock->is_controlled_rdata, /* rate limited */ + TRUE, /* with router alert */ + header, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + + if (sent < 0 && EAGAIN == errno) { + sock->blocklen = tpdu_length; + return FALSE; + } + + const pgm_time_t now = pgm_time_update_now(); + + if (sock->use_pgmcc) { + sock->tokens -= pgm_fp8 (1); + sock->ack_expiry = now + sock->ack_expiry_ivl; + } + +/* re-set spm timer: we are already in the timer thread, no need to prod timers + */ + pgm_mutex_lock (&sock->timer_mutex); + sock->spm_heartbeat_state = 1; + sock->next_heartbeat_spm = now + sock->spm_heartbeat_interval[sock->spm_heartbeat_state++]; + pgm_mutex_unlock (&sock->timer_mutex); + + pgm_txw_inc_retransmit_count (skb); + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_BYTES_RETRANSMITTED] += ntohs(header->pgm_tsdu_length); + sock->cumulative_stats[PGM_PC_SOURCE_SELECTIVE_MSGS_RETRANSMITTED]++; /* impossible to determine APDU count */ + pgm_atomic_add32 (&sock->cumulative_stats[PGM_PC_SOURCE_BYTES_SENT], tpdu_length + sock->iphdr_len); + return TRUE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/source.c.rej b/3rdparty/openpgm-svn-r1135/pgm/source.c.rej new file mode 100644 index 0000000..515f7ec --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/source.c.rej @@ -0,0 +1,17 @@ +*************** +*** 2295,2301 **** + header->pgm_checksum = 0; + const size_t pgm_header_len = tpdu_length - ntohs(header->pgm_tsdu_length); + uint32_t unfolded_header = pgm_csum_partial (header, pgm_header_len, 0); +- uint32_t unfolded_odata = pgm_txw_get_unfolded_checksum (skb); + header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, unfolded_odata, pgm_header_len)); + + /* congestion control */ +--- 2295,2301 ---- + header->pgm_checksum = 0; + const size_t pgm_header_len = tpdu_length - ntohs(header->pgm_tsdu_length); + uint32_t unfolded_header = pgm_csum_partial (header, pgm_header_len, 0); ++ uint32_t unfolded_odata = pgm_csum_partial (skb->data, ntohs(header->pgm_tsdu_length), 0); + header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, unfolded_odata, pgm_header_len)); + + /* congestion control */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/source_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/source_unittest.c new file mode 100644 index 0000000..d34f165 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/source_unittest.c @@ -0,0 +1,1248 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for PGM source transport. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* mock state */ + +#define TEST_NETWORK "" +#define TEST_PORT 7500 +#define TEST_MAX_TPDU 1500 +#define TEST_TXW_SQNS 32 +#define TEST_RXW_SQNS 32 +#define TEST_HOPS 16 +#define TEST_SPM_AMBIENT ( pgm_secs(30) ) +#define TEST_SPM_HEARTBEAT_INIT { pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(100), pgm_msecs(1300), pgm_secs(7), pgm_secs(16), pgm_secs(25), pgm_secs(30) } +#define TEST_PEER_EXPIRY ( pgm_secs(300) ) +#define TEST_SPMR_EXPIRY ( pgm_msecs(250) ) +#define TEST_NAK_BO_IVL ( pgm_msecs(50) ) +#define TEST_NAK_RPT_IVL ( pgm_secs(2) ) +#define TEST_NAK_RDATA_IVL ( pgm_secs(2) ) +#define TEST_NAK_DATA_RETRIES 5 +#define TEST_NAK_NCF_RETRIES 2 + +static gboolean mock_is_valid_spmr = TRUE; +static gboolean mock_is_valid_ack = TRUE; +static gboolean mock_is_valid_nak = TRUE; +static gboolean mock_is_valid_nnak = TRUE; + + +#define pgm_txw_get_unfolded_checksum mock_pgm_txw_get_unfolded_checksum +#define pgm_txw_set_unfolded_checksum mock_pgm_txw_set_unfolded_checksum +#define pgm_txw_inc_retransmit_count mock_pgm_txw_inc_retransmit_count +#define pgm_txw_add mock_pgm_txw_add +#define pgm_txw_peek mock_pgm_txw_peek +#define pgm_txw_retransmit_push mock_pgm_txw_retransmit_push +#define pgm_txw_retransmit_try_peek mock_pgm_txw_retransmit_try_peek +#define pgm_txw_retransmit_remove_head mock_pgm_txw_retransmit_remove_head +#define pgm_rs_encode mock_pgm_rs_encode +#define pgm_rate_check mock_pgm_rate_check +#define pgm_verify_spmr mock_pgm_verify_spmr +#define pgm_verify_ack mock_pgm_verify_ack +#define pgm_verify_nak mock_pgm_verify_nak +#define pgm_verify_nnak mock_pgm_verify_nnak +#define pgm_compat_csum_partial mock_pgm_compat_csum_partial +#define pgm_compat_csum_partial_copy mock_pgm_compat_csum_partial_copy +#define pgm_csum_block_add mock_pgm_csum_block_add +#define pgm_csum_fold mock_pgm_csum_fold +#define pgm_sendto_hops mock_pgm_sendto_hops +#define pgm_time_update_now mock_pgm_time_update_now +#define pgm_setsockopt mock_pgm_setsockopt + + +#define SOURCE_DEBUG +#include "source.c" + + +static +void +mock_setup (void) +{ + if (!g_thread_supported ()) g_thread_init (NULL); +} + +static +struct pgm_sock_t* +generate_sock (void) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, g_htons(1000) }; + struct pgm_sock_t* sock = g_new0 (struct pgm_sock_t, 1); + memcpy (&sock->tsi, &tsi, sizeof(pgm_tsi_t)); + ((struct sockaddr*)&sock->send_addr)->sa_family = AF_INET; + ((struct sockaddr_in*)&sock->send_addr)->sin_addr.s_addr = inet_addr ("127.0.0.2"); + ((struct sockaddr*)&sock->send_gsr.gsr_group)->sa_family = AF_INET; + ((struct sockaddr_in*)&sock->send_gsr.gsr_group)->sin_addr.s_addr = inet_addr ("239.192.0.1"); + sock->dport = g_htons(TEST_PORT); + sock->window = g_malloc0 (sizeof(pgm_txw_t)); + sock->txw_sqns = TEST_TXW_SQNS; + sock->max_tpdu = TEST_MAX_TPDU; + sock->max_tsdu = TEST_MAX_TPDU - sizeof(struct pgm_ip) - pgm_pkt_offset (FALSE, FALSE); + sock->max_tsdu_fragment = TEST_MAX_TPDU - sizeof(struct pgm_ip) - pgm_pkt_offset (TRUE, FALSE); + sock->max_apdu = MIN(TEST_TXW_SQNS, PGM_MAX_FRAGMENTS) * sock->max_tsdu_fragment; + sock->iphdr_len = sizeof(struct pgm_ip); + sock->spm_heartbeat_interval = g_malloc0 (sizeof(guint) * (2+2)); + sock->spm_heartbeat_interval[0] = pgm_secs(1); + pgm_spinlock_init (&sock->txw_spinlock); + sock->is_bound = FALSE; + sock->is_destroyed = FALSE; + return sock; +} + +static +struct pgm_sk_buff_t* +generate_skb (void) +{ + const char source[] = "i am not a string"; + struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); + pgm_skb_reserve (skb, pgm_pkt_offset (FALSE, FALSE)); + pgm_skb_put (skb, sizeof(source)); + memcpy (skb->data, source, sizeof(source)); + return skb; +} + +static +struct pgm_sk_buff_t* +generate_fragment_skb (void) +{ + const char source[] = "i am not a string"; + struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); + pgm_skb_reserve (skb, pgm_pkt_offset (TRUE, FALSE)); + pgm_skb_put (skb, sizeof(source)); + memcpy (skb->data, source, sizeof(source)); + return skb; +} + +static +struct pgm_sk_buff_t* +generate_odata (void) +{ + const char source[] = "i am not a string"; + const guint16 header_length = sizeof(struct pgm_header) + sizeof(struct pgm_data); + struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); + pgm_skb_reserve (skb, header_length); + memset (skb->head, 0, header_length); + skb->pgm_header = (struct pgm_header*)skb->head; + skb->pgm_data = (struct pgm_data*)(skb->pgm_header + 1); + skb->pgm_header->pgm_type = PGM_ODATA; + skb->pgm_header->pgm_tsdu_length = g_htons (sizeof(source)); + memcpy (skb->data, source, sizeof(source)); + pgm_skb_put (skb, sizeof(source)); +/* reverse pull */ + skb->len += (guint8*)skb->data - (guint8*)skb->head; + skb->data = skb->head; + return skb; +} + +static +pgm_peer_t* +generate_peer (void) +{ + pgm_peer_t* peer = g_malloc0 (sizeof(pgm_peer_t)); + return peer; +} + +static +struct pgm_sk_buff_t* +generate_spmr (void) +{ + struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); + const guint16 header_length = sizeof(struct pgm_header); + pgm_skb_reserve (skb, header_length); + memset (skb->head, 0, header_length); + skb->pgm_header = (struct pgm_header*)skb->head; + skb->pgm_header->pgm_type = PGM_SPMR; + pgm_skb_put (skb, header_length); + return skb; +} + +static +struct pgm_sk_buff_t* +generate_single_nak (void) +{ + struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); + const guint16 header_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); + pgm_skb_reserve (skb, sizeof(struct pgm_header)); + memset (skb->head, 0, header_length); + skb->pgm_header = (struct pgm_header*)skb->head; + skb->pgm_header->pgm_type = PGM_NAK; + struct pgm_nak* nak = (struct pgm_nak*)(skb->pgm_header + 1); + struct sockaddr_in nla = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr("127.0.0.2") + }; + pgm_sockaddr_to_nla ((struct sockaddr*)&nla, (char*)&nak->nak_src_nla_afi); + struct sockaddr_in group = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr("239.192.0.1") + }; + pgm_sockaddr_to_nla ((struct sockaddr*)&group, (char*)&nak->nak_grp_nla_afi); + pgm_skb_put (skb, header_length); + return skb; +} + +static +struct pgm_sk_buff_t* +generate_single_nnak (void) +{ + struct pgm_sk_buff_t* skb = generate_single_nak (); + skb->pgm_header->pgm_type = PGM_NNAK; + return skb; +} + +static +struct pgm_sk_buff_t* +generate_parity_nak (void) +{ + struct pgm_sk_buff_t* skb = generate_single_nak (); + skb->pgm_header->pgm_options = PGM_OPT_PARITY; + return skb; +} + +static +struct pgm_sk_buff_t* +generate_nak_list (void) +{ + struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU); + const guint16 header_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak) + + sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + + ( 62 * sizeof(guint32) ); + pgm_skb_reserve (skb, sizeof(struct pgm_header)); + memset (skb->head, 0, header_length); + skb->pgm_header = (struct pgm_header*)skb->head; + skb->pgm_header->pgm_type = PGM_NAK; + skb->pgm_header->pgm_options = PGM_OPT_PRESENT | PGM_OPT_NETWORK; + struct pgm_nak *nak = (struct pgm_nak*)(skb->pgm_header + 1); + struct sockaddr_in nla = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr("127.0.0.2") + }; + pgm_sockaddr_to_nla ((struct sockaddr*)&nla, (char*)&nak->nak_src_nla_afi); + struct sockaddr_in group = { + .sin_family = AF_INET, + .sin_addr.s_addr = inet_addr("239.192.0.1") + }; + pgm_sockaddr_to_nla ((struct sockaddr*)&group, (char*)&nak->nak_grp_nla_afi); + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(nak + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = g_htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( 62 * sizeof(guint32) ) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + + ( 62 * sizeof(guint32) ); + struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); + for (unsigned i = 1; i < 63; i++) { + opt_nak_list->opt_sqn[i-1] = g_htonl (i); + } + pgm_skb_put (skb, header_length); + return skb; +} + +static +struct pgm_sk_buff_t* +generate_parity_nak_list (void) +{ + struct pgm_sk_buff_t* skb = generate_nak_list (); + skb->pgm_header->pgm_options = PGM_OPT_PARITY | PGM_OPT_PRESENT | PGM_OPT_NETWORK; + return skb; +} + +void +mock_pgm_txw_add ( + pgm_txw_t* const window, + struct pgm_sk_buff_t* const skb + ) +{ + g_debug ("mock_pgm_txw_add (window:%p skb:%p)", + (gpointer)window, (gpointer)skb); +} + +struct pgm_sk_buff_t* +mock_pgm_txw_peek ( + const pgm_txw_t* const window, + const uint32_t sequence + ) +{ + g_debug ("mock_pgm_txw_peek (window:%p sequence:%" G_GUINT32_FORMAT ")", + (gpointer)window, sequence); + return NULL; +} + +bool +mock_pgm_txw_retransmit_push ( + pgm_txw_t* const window, + const uint32_t sequence, + const bool is_parity, + const uint8_t tg_sqn_shift + ) +{ + g_debug ("mock_pgm_txw_retransmit_push (window:%p sequence:%" G_GUINT32_FORMAT " is-parity:%s tg-sqn-shift:%d)", + (gpointer)window, + sequence, + is_parity ? "YES" : "NO", + tg_sqn_shift); + return TRUE; +} + +void +mock_pgm_txw_set_unfolded_checksum ( + struct pgm_sk_buff_t*const skb, + const uint32_t csum + ) +{ +} + +uint32_t +pgm_txw_get_unfolded_checksum ( + const struct pgm_sk_buff_t*const skb + ) +{ + return 0; +} + +void +mock_pgm_txw_inc_retransmit_count ( + struct pgm_sk_buff_t*const skb + ) +{ +} + +struct pgm_sk_buff_t* +mock_pgm_txw_retransmit_try_peek ( + pgm_txw_t* const window + ) +{ + g_debug ("mock_pgm_txw_retransmit_try_peek (window:%p)", + (gpointer)window); + return generate_odata (); +} + +void +mock_pgm_txw_retransmit_remove_head ( + pgm_txw_t* const window + ) +{ + g_debug ("mock_pgm_txw_retransmit_remove_head (window:%p)", + (gpointer)window); +} + +void +mock_pgm_rs_encode ( + pgm_rs_t* rs, + const pgm_gf8_t** src, + uint8_t offset, + pgm_gf8_t* dst, + uint16_t len + ) +{ + g_debug ("mock_pgm_rs_encode (rs:%p src:%p offset:%u dst:%p len:%" G_GSIZE_FORMAT ")", + rs, src, offset, dst, len); +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_rate_check ( + pgm_rate_t* bucket, + const size_t data_size, + const bool is_nonblocking + ) +{ + g_debug ("mock_pgm_rate_check (bucket:%p data-size:%u is-nonblocking:%s)", + bucket, data_size, is_nonblocking ? "TRUE" : "FALSE"); + return TRUE; +} + +bool +mock_pgm_verify_spmr ( + const struct pgm_sk_buff_t* const skb + ) +{ + return mock_is_valid_spmr; +} + +bool +mock_pgm_verify_ack ( + const struct pgm_sk_buff_t* const skb + ) +{ + return mock_is_valid_ack; +} + +bool +mock_pgm_verify_nak ( + const struct pgm_sk_buff_t* const skb + ) +{ + return mock_is_valid_nak; +} + +bool +mock_pgm_verify_nnak ( + const struct pgm_sk_buff_t* const skb + ) +{ + return mock_is_valid_nnak; +} + +uint32_t +mock_pgm_compat_csum_partial ( + const void* addr, + uint16_t len, + uint32_t csum + ) +{ + return 0x0; +} + +uint32_t +mock_pgm_compat_csum_partial_copy ( + const void* src, + void* dst, + uint16_t len, + uint32_t csum + ) +{ + return 0x0; +} + +uint32_t +mock_pgm_csum_block_add ( + uint32_t csum, + uint32_t csum2, + uint16_t offset + ) +{ + return 0x0; +} + +uint16_t +mock_pgm_csum_fold ( + uint32_t csum + ) +{ + return 0x0; +} + +PGM_GNUC_INTERNAL +ssize_t +mock_pgm_sendto_hops ( + pgm_sock_t* sock, + bool use_rate_limit, + bool use_router_alert, + int level, + const void* buf, + size_t len, + const struct sockaddr* to, + socklen_t tolen + ) +{ + char saddr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop (to, saddr, sizeof(saddr)); + g_debug ("mock_pgm_sendto (sock:%p use-rate-limit:%s use-router-alert:%s level:%d buf:%p len:%d to:%s tolen:%d)", + (gpointer)sock, + use_rate_limit ? "YES" : "NO", + use_router_alert ? "YES" : "NO", + level, + buf, + len, + saddr, + tolen); + return len; +} + +/** time module */ +static pgm_time_t _mock_pgm_time_update_now (void); +pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; + +static +pgm_time_t +_mock_pgm_time_update_now (void) +{ + return 0x1; +} + +/** socket module */ +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return can_fragment ? ( sizeof(struct pgm_header) + + sizeof(struct pgm_data) + + sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment) ) + : ( sizeof(struct pgm_header) + sizeof(struct pgm_data) ); +} + +bool +mock_pgm_setsockopt ( + pgm_sock_t* const sock, + const int level, + const int optname, + const void* optval, + const socklen_t optlen + ) +{ + if (NULL == sock) + return FALSE; + return TRUE; +} + + +/* mock functions for external references */ + + +/* target: + * PGMIOStatus + * pgm_send ( + * pgm_sock_t* sock, + * gconstpointer apdu, + * gsize apdu_length, + * gsize* bytes_written + * ) + */ + +START_TEST (test_send_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_bound = TRUE; + const gsize apdu_length = 100; + guint8 buffer[ apdu_length ]; + gsize bytes_written; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_send (sock, buffer, apdu_length, &bytes_written), "send not normal"); + fail_unless ((gssize)apdu_length == bytes_written, "send underrun"); +} +END_TEST + +/* large apdu */ +START_TEST (test_send_pass_002) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_bound = TRUE; + const gsize apdu_length = 16000; + guint8 buffer[ apdu_length ]; + gsize bytes_written; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_send (sock, buffer, apdu_length, &bytes_written), "send not normal"); + fail_unless ((gssize)apdu_length == bytes_written, "send underrun"); +} +END_TEST + +START_TEST (test_send_fail_001) +{ + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + const gsize apdu_length = 100; + gsize bytes_written; + fail_unless (PGM_IO_STATUS_ERROR == pgm_send (NULL, buffer, apdu_length, &bytes_written), "send not error"); +} +END_TEST + +/* target: + * PGMIOStatus + * pgm_sendv ( + * pgm_sock_t* sock, + * const struct pgmiovec* vector, + * guint count, + * gboolean is_one_apdu, + * gsize* bytes_written + * ) + */ + +START_TEST (test_sendv_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_bound = TRUE; + const gsize apdu_length = 100; + guint8 buffer[ apdu_length ]; + struct pgm_iovec vector[] = { { .iov_base = buffer, .iov_len = apdu_length } }; + gsize bytes_written; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_sendv (sock, vector, 1, TRUE, &bytes_written), "send not normal"); + fail_unless ((gssize)apdu_length == bytes_written, "send underrun"); +} +END_TEST + +/* large apdu */ +START_TEST (test_sendv_pass_002) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_bound = TRUE; + const gsize apdu_length = 16000; + guint8 buffer[ apdu_length ]; + struct pgm_iovec vector[] = { { .iov_base = buffer, .iov_len = apdu_length } }; + gsize bytes_written; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_sendv (sock, vector, 1, TRUE, &bytes_written), "send not normal"); + fail_unless ((gssize)apdu_length == bytes_written, "send underrun"); +} +END_TEST + +/* multipart apdu */ +START_TEST (test_sendv_pass_003) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_bound = TRUE; + const gsize apdu_length = 16000; + guint8 buffer[ apdu_length ]; + struct pgm_iovec vector[ 16 ]; + for (unsigned i = 0; i < G_N_ELEMENTS(vector); i++) { + vector[i].iov_base = &buffer[ (i * apdu_length) / G_N_ELEMENTS(vector) ]; + vector[i].iov_len = apdu_length / G_N_ELEMENTS(vector); + } + gsize bytes_written; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_sendv (sock, vector, G_N_ELEMENTS(vector), TRUE, &bytes_written), "send not normal"); + fail_unless ((gssize)apdu_length == bytes_written, "send underrun"); +} +END_TEST + +/* multiple apdus */ +START_TEST (test_sendv_pass_004) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_bound = TRUE; + const gsize apdu_length = 16000; + struct pgm_iovec vector[ 16 ]; + for (unsigned i = 0; i < G_N_ELEMENTS(vector); i++) { + vector[i].iov_base = g_malloc0 (apdu_length); + vector[i].iov_len = apdu_length; + } + gsize bytes_written; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_sendv (sock, vector, G_N_ELEMENTS(vector), FALSE, &bytes_written), "send not normal"); + fail_unless ((gssize)(apdu_length * G_N_ELEMENTS(vector)) == bytes_written, "send underrun"); +} +END_TEST + +START_TEST (test_sendv_fail_001) +{ + guint8 buffer[ TEST_TXW_SQNS * TEST_MAX_TPDU ]; + const gsize tsdu_length = 100; + struct pgm_iovec vector[] = { { .iov_base = buffer, .iov_len = tsdu_length } }; + gsize bytes_written; + fail_unless (PGM_IO_STATUS_ERROR == pgm_sendv (NULL, vector, 1, TRUE, &bytes_written), "send not error"); +} +END_TEST + +/* target: + * PGMIOStatus + * pgm_send_skbv ( + * pgm_sock_t* sock, + * struct pgm_sk_buff_t* vector[], + * guint count, + * gboolean is_one_apdu, + * gsize* bytes_written + * ) + */ + +START_TEST (test_send_skbv_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_bound = TRUE; + struct pgm_sk_buff_t* skb = NULL; + skb = generate_skb (); + fail_if (NULL == skb, "generate_skb failed"); + gsize apdu_length = (gsize)skb->len; + gsize bytes_written; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_send_skbv (sock, &skb, 1, TRUE, &bytes_written), "send not normal"); + fail_unless (apdu_length == bytes_written, "send underrun"); +} +END_TEST + +/* multipart apdu */ +START_TEST (test_send_skbv_pass_002) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_bound = TRUE; + struct pgm_sk_buff_t* skb[16]; + for (unsigned i = 0; i < G_N_ELEMENTS(skb); i++) { + skb[i] = generate_fragment_skb (); + fail_if (NULL == skb[i], "generate_fragment_skb failed"); + } + gsize apdu_length = (gsize)skb[0]->len * G_N_ELEMENTS(skb); + gsize bytes_written; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_send_skbv (sock, skb, G_N_ELEMENTS(skb), TRUE, &bytes_written), "send not normal"); + fail_unless (apdu_length == bytes_written, "send underrun"); +} +END_TEST + +/* multiple apdus */ +START_TEST (test_send_skbv_pass_003) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->is_bound = TRUE; + struct pgm_sk_buff_t* skb[16]; + for (unsigned i = 0; i < G_N_ELEMENTS(skb); i++) { + skb[i] = generate_skb (); + fail_if (NULL == skb[i], "generate_skb failed"); + } + gsize bytes_written; + fail_unless (PGM_IO_STATUS_NORMAL == pgm_send_skbv (sock, skb, G_N_ELEMENTS(skb), FALSE, &bytes_written), "send not normal"); + fail_unless ((gssize)(skb[0]->len * G_N_ELEMENTS(skb)) == bytes_written, "send underrun"); +} +END_TEST + +START_TEST (test_send_skbv_fail_001) +{ + struct pgm_sk_buff_t* skb = pgm_alloc_skb (TEST_MAX_TPDU), *skbv[] = { skb }; + fail_if (NULL == skb, "alloc_skb failed"); +/* reserve PGM header */ + pgm_skb_put (skb, pgm_pkt_offset (TRUE, FALSE)); + const gsize tsdu_length = 100; + gsize bytes_written; + fail_unless (PGM_IO_STATUS_ERROR == pgm_send_skbv (NULL, skbv, 1, TRUE, &bytes_written), "send not error"); +} +END_TEST + +/* target: + * gboolean + * pgm_send_spm ( + * pgm_sock_t* sock, + * int flags + * ) + */ + +START_TEST (test_send_spm_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + fail_unless (TRUE == pgm_send_spm (sock, 0), "send_spm failed"); +} +END_TEST + +START_TEST (test_send_spm_fail_001) +{ + pgm_send_spm (NULL, 0); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_on_deferred_nak ( + * pgm_sock_t* sock + * ) + */ + +START_TEST (test_on_deferred_nak_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + pgm_on_deferred_nak (sock); +} +END_TEST + +START_TEST (test_on_deferred_nak_fail_001) +{ + pgm_on_deferred_nak (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * gboolean + * pgm_on_spmr ( + * pgm_sock_t* sock, + * pgm_peer_t* peer, + * struct pgm_sk_buff_t* skb + * ) + */ + +/* peer spmr */ +START_TEST (test_on_spmr_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + pgm_peer_t* peer = generate_peer (); + fail_if (NULL == peer, "generate_peer failed"); + struct pgm_sk_buff_t* skb = generate_spmr (); + fail_if (NULL == skb, "generate_spmr failed"); + skb->sock = sock; + fail_unless (TRUE == pgm_on_spmr (sock, peer, skb), "on_spmr failed"); +} +END_TEST + +/* source spmr */ +START_TEST (test_on_spmr_pass_002) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + struct pgm_sk_buff_t* skb = generate_spmr (); + fail_if (NULL == skb, "generate_spmr failed"); + skb->sock = sock; + fail_unless (TRUE == pgm_on_spmr (sock, NULL, skb), "on_spmr failed"); +} +END_TEST + +/* invalid spmr */ +START_TEST (test_on_spmr_fail_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + pgm_peer_t* peer = generate_peer (); + fail_if (NULL == peer, "generate_peer failed"); + struct pgm_sk_buff_t* skb = generate_spmr (); + fail_if (NULL == skb, "generate_spmr failed"); + skb->sock = sock; + mock_is_valid_spmr = FALSE; + fail_unless (FALSE == pgm_on_spmr (sock, peer, skb), "on_spmr failed"); +} +END_TEST + +START_TEST (test_on_spmr_fail_002) +{ + pgm_on_spmr (NULL, NULL, NULL); + fail ("reached"); +} +END_TEST + +/* target: + * gboolean + * pgm_on_nak ( + * pgm_sock_t* sock, + * struct pgm_sk_buff_t* skb + * ) + */ + +/* single nak */ +START_TEST (test_on_nak_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + struct pgm_sk_buff_t* skb = generate_single_nak (); + fail_if (NULL == skb, "generate_single_nak failed"); + skb->sock = sock; + fail_unless (TRUE == pgm_on_nak (sock, skb), "on_nak failed"); +} +END_TEST + +/* nak list */ +START_TEST (test_on_nak_pass_002) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + struct pgm_sk_buff_t* skb = generate_nak_list (); + fail_if (NULL == skb, "generate_nak_list failed"); + skb->sock = sock; + fail_unless (TRUE == pgm_on_nak (sock, skb), "on_nak failed"); +} +END_TEST + +/* single parity nak */ +START_TEST (test_on_nak_pass_003) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->use_ondemand_parity = TRUE; + struct pgm_sk_buff_t* skb = generate_parity_nak (); + fail_if (NULL == skb, "generate_parity_nak failed"); + skb->sock = sock; + fail_unless (TRUE == pgm_on_nak (sock, skb), "on_nak failed"); +} +END_TEST + +/* parity nak list */ +START_TEST (test_on_nak_pass_004) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->use_ondemand_parity = TRUE; + struct pgm_sk_buff_t* skb = generate_parity_nak_list (); + fail_if (NULL == skb, "generate_parity_nak_list failed"); + skb->sock = sock; + fail_unless (TRUE == pgm_on_nak (sock, skb), "on_nak failed"); +} +END_TEST + +START_TEST (test_on_nak_fail_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + struct pgm_sk_buff_t* skb = generate_single_nak (); + fail_if (NULL == skb, "generate_single_nak failed"); + skb->sock = sock; + mock_is_valid_nak = FALSE; + fail_unless (FALSE == pgm_on_nak (sock, skb), "on_nak failed"); +} +END_TEST + +START_TEST (test_on_nak_fail_002) +{ + pgm_on_nak (NULL, NULL); + fail ("reached"); +} +END_TEST + +/* target: + * gboolean + * pgm_on_nnak ( + * pgm_sock_t* sock, + * struct pgm_sk_buff_t* skb + * ) + */ + +START_TEST (test_on_nnak_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + struct pgm_sk_buff_t* skb = generate_single_nnak (); + fail_if (NULL == skb, "generate_single_nnak failed"); + skb->sock = sock; + fail_unless (TRUE == pgm_on_nnak (sock, skb), "on_nnak failed"); +} +END_TEST + +START_TEST (test_on_nnak_fail_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + struct pgm_sk_buff_t* skb = generate_single_nnak (); + fail_if (NULL == skb, "generate_single_nnak failed"); + skb->sock = sock; + mock_is_valid_nnak = FALSE; + fail_unless (FALSE == pgm_on_nnak (sock, skb), "on_nnak failed"); +} +END_TEST + +START_TEST (test_on_nnak_fail_002) +{ + pgm_on_nnak (NULL, NULL); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_AMBIENT_SPM, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_ambient_spm_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_AMBIENT_SPM; + const int ambient_spm = pgm_msecs(1000); + const void* optval = &ambient_spm; + const socklen_t optlen = sizeof(ambient_spm); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_ambient_spm failed"); +} +END_TEST + +START_TEST (test_set_ambient_spm_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_AMBIENT_SPM; + const int ambient_spm = pgm_msecs(1000); + const void* optval = &ambient_spm; + const socklen_t optlen = sizeof(ambient_spm); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_ambient_spm failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_HEARTBEAT_SPM, + * const void* optval, + * const socklen_t optlen = sizeof(int) * n + * ) + */ + +START_TEST (test_set_heartbeat_spm_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_HEARTBEAT_SPM; + const int intervals[] = { 1, 2, 3, 4, 5 }; + const void* optval = &intervals; + const socklen_t optlen = sizeof(intervals); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_heartbeat_spm failed"); +} +END_TEST + +START_TEST (test_set_heartbeat_spm_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_HEARTBEAT_SPM; + const int intervals[] = { 1, 2, 3, 4, 5 }; + const void* optval = &intervals; + const socklen_t optlen = sizeof(intervals); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_heartbeat_spm failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_TXW_SQNS, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_txw_sqns_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_TXW_SQNS; + const int txw_sqns = 100; + const void* optval = &txw_sqns; + const socklen_t optlen = sizeof(txw_sqns); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_txw_sqns failed"); +} +END_TEST + +START_TEST (test_set_txw_sqns_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_TXW_SQNS; + const int txw_sqns = 100; + const void* optval = &txw_sqns; + const socklen_t optlen = sizeof(txw_sqns); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_txw_sqns failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_TXW_SECS, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_txw_secs_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_TXW_SECS; + const int txw_secs = pgm_secs(10); + const void* optval = &txw_secs; + const socklen_t optlen = sizeof(txw_secs); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_txw_secs failed"); +} +END_TEST + +START_TEST (test_set_txw_secs_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_TXW_SECS; + const int txw_secs = pgm_secs(10); + const void* optval = &txw_secs; + const socklen_t optlen = sizeof(txw_secs); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_txw_secs failed"); +} +END_TEST + +/* target: + * bool + * pgm_setsockopt ( + * pgm_sock_t* const sock, + * const int level = IPPROTO_PGM, + * const int optname = PGM_TXW_MAX_RTE, + * const void* optval, + * const socklen_t optlen = sizeof(int) + * ) + */ + +START_TEST (test_set_txw_max_rte_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + const int level = IPPROTO_PGM; + const int optname = PGM_TXW_MAX_RTE; + const int txw_max_rte = 100*1000; + const void* optval = &txw_max_rte; + const socklen_t optlen = sizeof(txw_max_rte); + fail_unless (TRUE == pgm_setsockopt (sock, level, optname, optval, optlen), "set_txw_max_rte failed"); +} +END_TEST + +START_TEST (test_set_txw_max_rte_fail_001) +{ + const int level = IPPROTO_PGM; + const int optname = PGM_TXW_MAX_RTE; + const int txw_max_rte = 100*1000; + const void* optval = &txw_max_rte; + const socklen_t optlen = sizeof(txw_max_rte); + fail_unless (FALSE == pgm_setsockopt (NULL, level, optname, optval, optlen), "set_txw_max_rte failed"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_send = tcase_create ("send"); + suite_add_tcase (s, tc_send); + tcase_add_checked_fixture (tc_send, mock_setup, NULL); + tcase_add_test (tc_send, test_send_pass_001); + tcase_add_test (tc_send, test_send_pass_002); + tcase_add_test (tc_send, test_send_fail_001); + + TCase* tc_sendv = tcase_create ("sendv"); + suite_add_tcase (s, tc_sendv); + tcase_add_checked_fixture (tc_sendv, mock_setup, NULL); + tcase_add_test (tc_sendv, test_sendv_pass_001); + tcase_add_test (tc_sendv, test_sendv_pass_002); + tcase_add_test (tc_sendv, test_sendv_pass_003); + tcase_add_test (tc_sendv, test_sendv_pass_004); + tcase_add_test (tc_sendv, test_sendv_fail_001); + + TCase* tc_send_skbv = tcase_create ("send-skbv"); + suite_add_tcase (s, tc_send_skbv); + tcase_add_checked_fixture (tc_send_skbv, mock_setup, NULL); + tcase_add_test (tc_send_skbv, test_send_skbv_pass_001); + tcase_add_test (tc_send_skbv, test_send_skbv_pass_002); + tcase_add_test (tc_send_skbv, test_send_skbv_fail_001); + + TCase* tc_send_spm = tcase_create ("send-spm"); + suite_add_tcase (s, tc_send_spm); + tcase_add_checked_fixture (tc_send_spm, mock_setup, NULL); + tcase_add_test (tc_send_spm, test_send_spm_pass_001); + tcase_add_test_raise_signal (tc_send_spm, test_send_spm_fail_001, SIGABRT); + + TCase* tc_on_deferred_nak = tcase_create ("on-deferred-nak"); + suite_add_tcase (s, tc_on_deferred_nak); + tcase_add_checked_fixture (tc_on_deferred_nak, mock_setup, NULL); + tcase_add_test (tc_on_deferred_nak, test_on_deferred_nak_pass_001); + tcase_add_test_raise_signal (tc_on_deferred_nak, test_on_deferred_nak_fail_001, SIGABRT); + + TCase* tc_on_spmr = tcase_create ("on-spmr"); + suite_add_tcase (s, tc_on_spmr); + tcase_add_checked_fixture (tc_on_spmr, mock_setup, NULL); + tcase_add_test (tc_on_spmr, test_on_spmr_pass_001); + tcase_add_test (tc_on_spmr, test_on_spmr_pass_002); + tcase_add_test (tc_on_spmr, test_on_spmr_fail_001); + tcase_add_test_raise_signal (tc_on_spmr, test_on_spmr_fail_002, SIGABRT); + + TCase* tc_on_nak = tcase_create ("on-nak"); + suite_add_tcase (s, tc_on_nak); + tcase_add_checked_fixture (tc_on_nak, mock_setup, NULL); + tcase_add_test (tc_on_nak, test_on_nak_pass_001); + tcase_add_test (tc_on_nak, test_on_nak_pass_002); + tcase_add_test (tc_on_nak, test_on_nak_pass_003); + tcase_add_test (tc_on_nak, test_on_nak_pass_004); + tcase_add_test (tc_on_nak, test_on_nak_fail_001); + tcase_add_test_raise_signal (tc_on_nak, test_on_nak_fail_002, SIGABRT); + + TCase* tc_on_nnak = tcase_create ("on-nnak"); + suite_add_tcase (s, tc_on_nnak); + tcase_add_checked_fixture (tc_on_nnak, mock_setup, NULL); + tcase_add_test (tc_on_nnak, test_on_nnak_pass_001); + tcase_add_test (tc_on_nnak, test_on_nnak_fail_001); + tcase_add_test_raise_signal (tc_on_nnak, test_on_nnak_fail_002, SIGABRT); + + TCase* tc_set_ambient_spm = tcase_create ("set-ambient-spm"); + suite_add_tcase (s, tc_set_ambient_spm); + tcase_add_checked_fixture (tc_set_ambient_spm, mock_setup, NULL); + tcase_add_test (tc_set_ambient_spm, test_set_ambient_spm_pass_001); + tcase_add_test (tc_set_ambient_spm, test_set_ambient_spm_fail_001); + + TCase* tc_set_heartbeat_spm = tcase_create ("set-heartbeat-spm"); + suite_add_tcase (s, tc_set_heartbeat_spm); + tcase_add_checked_fixture (tc_set_heartbeat_spm, mock_setup, NULL); + tcase_add_test (tc_set_heartbeat_spm, test_set_heartbeat_spm_pass_001); + tcase_add_test (tc_set_heartbeat_spm, test_set_heartbeat_spm_fail_001); + + TCase* tc_set_txw_sqns = tcase_create ("set-txw-sqns"); + suite_add_tcase (s, tc_set_txw_sqns); + tcase_add_checked_fixture (tc_set_txw_sqns, mock_setup, NULL); + tcase_add_test (tc_set_txw_sqns, test_set_txw_sqns_pass_001); + tcase_add_test (tc_set_txw_sqns, test_set_txw_sqns_fail_001); + + TCase* tc_set_txw_secs = tcase_create ("set-txw-secs"); + suite_add_tcase (s, tc_set_txw_secs); + tcase_add_checked_fixture (tc_set_txw_secs, mock_setup, NULL); + tcase_add_test (tc_set_txw_secs, test_set_txw_secs_pass_001); + tcase_add_test (tc_set_txw_secs, test_set_txw_secs_fail_001); + + TCase* tc_set_txw_max_rte = tcase_create ("set-txw-max-rte"); + suite_add_tcase (s, tc_set_txw_max_rte); + tcase_add_checked_fixture (tc_set_txw_max_rte, mock_setup, NULL); + tcase_add_test (tc_set_txw_max_rte, test_set_txw_max_rte_pass_001); + tcase_add_test (tc_set_txw_max_rte, test_set_txw_max_rte_fail_001); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/string.c b/3rdparty/openpgm-svn-r1135/pgm/string.c new file mode 100644 index 0000000..f8f8e33 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/string.c @@ -0,0 +1,486 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * portable string manipulation functions. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if defined(CONFIG_HAVE_VASPRINTF) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +#endif +#include +#include +#include /* _GNU_SOURCE for vasprintf */ +#include +#include + + +//#define STRING_DEBUG + +/* Return copy of string, must be freed with pgm_free(). + */ + +char* +pgm_strdup ( + const char* str + ) +{ + char* new_str; + size_t length; + + if (PGM_LIKELY (NULL != str)) + { + length = strlen (str) + 1; + new_str = malloc (length); + memcpy (new_str, str, length); + } + else + new_str = NULL; + + return new_str; +} + +/* Calculates the maximum space needed to store the output of the sprintf() function. + */ + +int +pgm_printf_string_upper_bound ( + const char* format, + va_list args + ) +{ + char c; + return vsnprintf (&c, 1, format, args) + 1; +} + +/* memory must be freed with free() + */ + +int +pgm_vasprintf ( + char** restrict string, + const char* restrict format, + va_list args + ) +{ + pgm_return_val_if_fail (string != NULL, -1); +#ifdef CONFIG_HAVE_VASPRINTF + const int len = vasprintf (string, format, args); + if (len < 0) + *string = NULL; +#else + va_list args2; + va_copy (args2, args); + *string = malloc (pgm_printf_string_upper_bound (format, args)); +/* NB: must be able to handle NULL args, fails on GCC */ + const int len = vsprintf (*string, format, args); + va_end (args2); +#endif + return len; +} + +char* +pgm_strdup_vprintf ( + const char* format, + va_list args + ) +{ + char *string = NULL; + pgm_vasprintf (&string, format, args); + return string; +} + +static +char* +pgm_stpcpy ( + char* restrict dest, + const char* restrict src + ) +{ + pgm_return_val_if_fail (dest != NULL, NULL); + pgm_return_val_if_fail (src != NULL, NULL); +#ifdef CONFIG_HAVE_STPCPY + return stpcpy (dest, src); +#else + char *d = dest; + const char *s = src; + do { + *d++ = *s; + } while (*s++ != '\0'); + return d - 1; +#endif +} + +char* +pgm_strconcat ( + const char* string1, + ... + ) +{ + size_t l; + va_list args; + char* s; + char* concat; + char* ptr; + + if (!string1) + return NULL; + + l = 1 + strlen (string1); + va_start (args, string1); + s = va_arg (args, char*); + while (s) { + l += strlen (s); + s = va_arg (args, char*); + } + va_end (args); + + concat = malloc (l); + ptr = concat; + + ptr = pgm_stpcpy (ptr, string1); + va_start (args, string1); + s = va_arg (args, char*); + while (s) { + ptr = pgm_stpcpy (ptr, s); + s = va_arg (args, char*); + } + va_end (args); + + return concat; +} + +/* Split a string with delimiter, result must be freed with pgm_strfreev(). + */ + +char** +pgm_strsplit ( + const char* restrict string, + const char* restrict delimiter, + int max_tokens + ) +{ + pgm_slist_t *string_list = NULL, *slist; + char **str_array, *s; + unsigned n = 0; + const char *remainder; + + pgm_return_val_if_fail (string != NULL, NULL); + pgm_return_val_if_fail (delimiter != NULL, NULL); + pgm_return_val_if_fail (delimiter[0] != '\0', NULL); + + if (max_tokens < 1) + max_tokens = INT_MAX; + + remainder = string; + s = strstr (remainder, delimiter); + if (s) + { + const size_t delimiter_len = strlen (delimiter); + + while (--max_tokens && s) + { + const size_t len = s - remainder; + char *new_string = malloc (len + 1); + strncpy (new_string, remainder, len); + new_string[len] = 0; + string_list = pgm_slist_prepend (string_list, new_string); + n++; + remainder = s + delimiter_len; + s = strstr (remainder, delimiter); + } + } + if (*string) + { + n++; + string_list = pgm_slist_prepend (string_list, pgm_strdup (remainder)); + } + + str_array = pgm_new (char*, n + 1); + str_array[n--] = NULL; + for (slist = string_list; slist; slist = slist->next) + str_array[n--] = slist->data; + + pgm_slist_free (string_list); + + return str_array; +} + +/* Free a NULL-terminated array of strings, such as created by pgm_strsplit + */ + +void +pgm_strfreev ( + char** str_array + ) +{ + if (PGM_LIKELY (NULL != str_array)) + { + for (unsigned i = 0; str_array[i] != NULL; i++) + free (str_array[i]); + + pgm_free (str_array); + } +} + +/* resize dynamic string + */ + +static +void +pgm_string_maybe_expand ( + pgm_string_t* string, + size_t len + ) +{ + if ((string->len + len) >= string->allocated_len) + { + string->allocated_len = pgm_nearest_power (1, string->len + len + 1); + string->str = pgm_realloc (string->str, string->allocated_len); + } +} + +/* val may not be a part of string + */ + +static +pgm_string_t* +pgm_string_insert_len ( + pgm_string_t* restrict string, + ssize_t pos, + const char* restrict val, + ssize_t len + ) +{ + pgm_return_val_if_fail (NULL != string, NULL); + pgm_return_val_if_fail (NULL != val, string); + + if (len < 0) + len = strlen (val); + + if (pos < 0) + pos = string->len; + else + pgm_return_val_if_fail ((size_t)pos <= string->len, string); + + pgm_string_maybe_expand (string, len); + + if ((size_t)pos < string->len) + memmove (string->str + pos + len, string->str + pos, string->len - pos); + + if (len == 1) + string->str[pos] = *val; + else + memcpy (string->str + pos, val, len); + string->len += len; + string->str[string->len] = 0; + return string; +} + +static +pgm_string_t* +pgm_string_insert_c ( + pgm_string_t* string, + ssize_t pos, + char c + ) +{ + pgm_return_val_if_fail (NULL != string, NULL); + + if (pos < 0) + pos = string->len; + else + pgm_return_val_if_fail ((size_t)pos <= string->len, string); + + pgm_string_maybe_expand (string, 1); + + if ((size_t)pos < string->len) + memmove (string->str + pos + 1, string->str + pos, string->len - pos); + + string->str[pos] = c; + string->len ++; + string->str[string->len] = '\0'; + return string; +} + +static +pgm_string_t* +pgm_string_append_len ( + pgm_string_t* restrict string, + const char* restrict val, + size_t len + ) +{ + pgm_return_val_if_fail (NULL != string, NULL); + pgm_return_val_if_fail (NULL != val, string); + + return pgm_string_insert_len (string, -1, val, len); +} + +/* create new dynamic string + */ + +static +pgm_string_t* +pgm_string_sized_new ( + size_t init_size + ) +{ + pgm_string_t* string = pgm_new (pgm_string_t, 1); + string->allocated_len = 0; + string->len = 0; + string->str = NULL; + pgm_string_maybe_expand (string, MAX(init_size, 2)); + string->str[0] = '\0'; + return string; +} + +pgm_string_t* +pgm_string_new ( + const char* init + ) +{ + pgm_string_t* string; + + if (NULL == init || '\0' == *init) + string = pgm_string_sized_new (2); + else + { + const size_t len = strlen (init); + string = pgm_string_sized_new (len + 2); + pgm_string_append_len (string, init, len); + } + return string; +} + +/* free dynamic string, optionally just the wrapper object + */ + +char* +pgm_string_free ( + pgm_string_t* string, + bool free_segment + ) +{ + char* segment; + + pgm_return_val_if_fail (NULL != string, NULL); + + if (free_segment) { + pgm_free (string->str); + segment = NULL; + } else + segment = string->str; + + pgm_free (string); + return segment; +} + +static +pgm_string_t* +pgm_string_truncate ( + pgm_string_t* restrict string, + size_t len + ) +{ + pgm_return_val_if_fail (NULL != string, NULL); + + string->len = MIN (len, string->len); + string->str[ string->len ] = '\0'; + + return string; +} + +pgm_string_t* +pgm_string_append ( + pgm_string_t* restrict string, + const char* restrict val + ) +{ + pgm_return_val_if_fail (NULL != string, NULL); + pgm_return_val_if_fail (NULL != val, string); + + return pgm_string_insert_len (string, -1, val, -1); +} + +pgm_string_t* +pgm_string_append_c ( + pgm_string_t* string, + char c + ) +{ + pgm_return_val_if_fail (NULL != string, NULL); + + return pgm_string_insert_c (string, -1, c); +} + +static void pgm_string_append_vprintf (pgm_string_t*restrict, const char*restrict, va_list) PGM_GNUC_PRINTF(2, 0); + +static +void +pgm_string_append_vprintf ( + pgm_string_t* restrict string, + const char* restrict format, + va_list args + ) +{ + char *buf; + int len; + + pgm_return_if_fail (NULL != string); + pgm_return_if_fail (NULL != format); + + len = pgm_vasprintf (&buf, format, args); + if (len >= 0) { + pgm_string_maybe_expand (string, len); + memcpy (string->str + string->len, buf, len + 1); + string->len += len; + free (buf); + } +} + +void +pgm_string_printf ( + pgm_string_t* restrict string, + const char* restrict format, + ... + ) +{ + va_list args; + + pgm_string_truncate (string, 0); + + va_start (args, format); + pgm_string_append_vprintf (string, format, args); + va_end (args); +} + +void +pgm_string_append_printf ( + pgm_string_t* restrict string, + const char* restrict format, + ... + ) +{ + va_list args; + + va_start (args, format); + pgm_string_append_vprintf (string, format, args); + va_end (args); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/string.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/string.c.c89.patch new file mode 100644 index 0000000..8dd3d78 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/string.c.c89.patch @@ -0,0 +1,39 @@ +65a66,68 +> #ifdef _MSC_VER +> return _vscprintf (format, args) + 1; +> #else +67a71 +> #endif +80a85 +> { +81a87 +> { +85a92,94 +> # ifdef _MSC_VER +> va_list args2 = args; +> # else +87a97 +> # endif +89a100 +> { +93a105,106 +> } +> } +118a132 +> { +124a139 +> } +198a214,216 +> #ifdef _MSC_VER +> strncpy_s (new_string, len + 1, remainder, len); +> #else +199a218 +> #endif +233c252,254 +< for (unsigned i = 0; str_array[i] != NULL; i++) +--- +> { +> unsigned i; +> for (i = 0; str_array[i] != NULL; i++) +234a256 +> } diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/PGM/Test.pm b/3rdparty/openpgm-svn-r1135/pgm/test/PGM/Test.pm new file mode 100644 index 0000000..cb2ee6d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/PGM/Test.pm @@ -0,0 +1,394 @@ +package PGM::Test; + +use strict; +our($VERSION); +use Carp; +use IO::File; +use IPC::Open2; +use Net::SSH qw(sshopen2); +use Sys::Hostname; +use POSIX ":sys_wait_h"; +use JSON; + +$VERSION = '1.00'; + +=head1 NAME + +PGM::Test - PGM test module + +=head1 SYNOPSIS + + $test = PGM::Test->new(); + +=cut + +my $json = new JSON; + +sub new { + my $class = shift; + my $self = {}; + my %params = @_; + + $self->{tag} = exists $params{tag} ? $params{tag} : confess "tag parameter is required"; + $self->{host} = exists $params{host} ? $params{host} : confess "host parameter is required"; + $self->{cmd} = exists $params{cmd} ? $params{cmd} : confess "cmd parameter is required"; + + $self->{in} = IO::File->new(); + $self->{out} = IO::File->new(); + $self->{pid} = undef; + + bless $self, $class; + return $self; +} + +sub connect { + my $self = shift; + my $host = hostname; + + if ($self->{host} =~ /^(localhost|127\.1|127\.0\.0\.1|$host)$/) + { + print "$self->{tag}: opening local connection\n"; + $self->{pid} = open2 ($self->{in}, + $self->{out}, + "uname -a && sudo $self->{cmd}") + or croak "open2 failed $!"; + } + else + { + print "$self->{tag}: opening SSH connection to $self->{host} ...\n"; + $self->{pid} = sshopen2 ($self->{host}, + $self->{in}, + $self->{out}, + "uname -a && sudo $self->{cmd}") + or croak "SSH failed: $!"; + } + + print "$self->{tag}: connected.\n"; + $self->wait_for_ready; +} + +sub disconnect { + my($self,$quiet) = @_; + my $out = $self->{out}; + + print "$self->{tag}: sending quit command ...\n"; + eval { + local($SIG{ALRM}) = sub { die "alarm\n"; }; + alarm 10; + print $out "quit\n"; + while (readline($self->{in})) { + chomp; + print "$self->{tag} [$_]\n" if (!$quiet); + } + alarm 0; + }; + if ($@) { + print "$self->{tag}: alarm raised on quit command.\n"; + } else { + print "$self->{tag}: eof.\n"; + } + + print "$self->{tag}: closing SSH connection ...\n"; + close ($self->{in}); + close ($self->{out}); + print "$self->{tag}: closed.\n"; +} + +sub DESTROY { + my $self = shift; + + if ($self->{pid}) { + print "$self->{tag}: waiting child to terminate ...\n"; + eval { + local($SIG{ALRM}) = sub { die "alarm\n"; }; + alarm 10; + waitpid $self->{pid}, 0; + alarm 0; + }; + if ($@) { + die unless $@ eq "alarm\n"; + local($SIG{CHLD}) = 'IGNORE'; + print "$self->{tag}: killing child ...\n"; + kill 'INT' => $self->{pid}; + print "$self->{tag}: killed.\n"; + } else { + print "$self->{tag}: terminated.\n"; + } + } +} + +sub wait_for_ready { + my $self = shift; + + while (readline($self->{in})) { + chomp; + print "$self->{tag} [$_]\n"; + last if /^READY/; + } +} + +sub wait_for_block { + my $self = shift; + my $fh = $self->{in}; + my $b = ''; + my $state = 0; + + while (<$fh>) { + chomp(); + my $l = $_; + if ($state == 0) { + if ($l =~ /^{$/) { + $state = 1; + } else { + print "$self->{tag} [$l]\n"; + } + } + + if ($state == 1) { + $b .= $l; + + if ($l =~ /^}$/) { + $state = 0; + return $b; + } + } + } +} + +sub wait_for_spm { + my $self = shift; + my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; + my $obj = undef; + + eval { + local $SIG{ALRM} = sub { die "alarm\n"; }; + alarm $timeout; + for (;;) { + my $block = $self->wait_for_block; + $obj = $json->jsonToObj($block); + last if ($obj->{PGM}->{type} =~ /SPM$/); + } + alarm 0; + }; + if ($@) { + die unless $@ eq "alarm\n"; + confess "$self->{tag}: alarm raised waiting for spm.\n"; + } + + return $obj; +} + +sub wait_for_spmr { + my $self = shift; + my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; + my $obj = undef; + + eval { + local $SIG{ALRM} = sub { die "alarm\n"; }; + alarm $timeout; + for (;;) { + my $block = $self->wait_for_block; + $obj = $json->jsonToObj($block); + last if ($obj->{PGM}->{type} =~ /SPMR/); + } + alarm 0; + }; + if ($@) { + die unless $@ eq "alarm\n"; + confess "$self->{tag}: alarm raised waiting for spmr.\n"; + } + + return $obj; +} + +sub die_on_spmr { + my $self = shift; + my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; + my $obj = undef; + + eval { + local $SIG{ALRM} = sub { die "alarm\n"; }; + alarm $timeout; + for (;;) { + my $block = $self->wait_for_block; + $obj = $json->jsonToObj($block); + last if ($obj->{PGM}->{type} =~ /SPMR/); + } + alarm 0; + }; + if ($@) { + die unless $@ eq "alarm\n"; + return $obj; + } + + confess "$self->{tag}: spmr received during blackout.\n"; +} + +# data to {app} +sub wait_for_data { + my $self = shift; + my $fh = $self->{in}; + my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; + my $data = undef; + + eval { + local $SIG{ALRM} = sub { die "alarm\n"; }; + alarm $timeout; + while (<$fh>) { + chomp; + if (/^DATA: (.+)$/) { + $data = $1; + last; + } + print "$self->{tag} [$_]\n"; + } + alarm 0; + }; + if ($@) { + die unless $@ eq "alarm\n"; + confess "$self->{tag}: alarm raised waiting for data.\n"; + } + + return $data; +} + +sub wait_for_odata { + my $self = shift; + my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; + my $obj = undef; + + eval { + local $SIG{ALRM} = sub { die "alarm\n"; }; + alarm $timeout; + for (;;) { + my $block = $self->wait_for_block; + $obj = $json->jsonToObj($block); + last if ($obj->{PGM}->{type} =~ /ODATA/); + } + alarm 0; + }; + if ($@) { + die unless $@ eq "alarm\n"; + confess "$self->{tag}: alarm raised waiting for odata.\n"; + } + + return $obj; +} + +sub wait_for_rdata { + my $self = shift; + my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; + my $obj = undef; + + eval { + local $SIG{ALRM} = sub { die "alarm\n"; }; + alarm $timeout; + for (;;) { + my $block = $self->wait_for_block; + $obj = $json->jsonToObj($block); + last if ($obj->{PGM}->{type} =~ /RDATA/); + } + alarm 0; + }; + if ($@) { + die unless $@ eq "alarm\n"; + confess "$self->{tag}: alarm raised waiting for rdata.\n"; + } + + return $obj; +} + +sub die_on_nak { + my $self = shift; + my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; + my $obj = undef; + + eval { + local $SIG{ALRM} = sub { die "alarm\n"; }; + alarm $timeout; + for (;;) { + my $block = $self->wait_for_block; + $obj = $json->jsonToObj($block); + last if ($obj->{PGM}->{type} =~ /NAK/); + } + alarm 0; + }; + if ($@) { + die unless $@ eq "alarm\n"; + return $obj; + } + + confess "$self->{tag}: nak received during blackout.\n"; +} + +sub wait_for_nak { + my $self = shift; + my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; + my $obj = undef; + + eval { + local $SIG{ALRM} = sub { die "alarm\n"; }; + alarm $timeout; + for (;;) { + my $block = $self->wait_for_block; + $obj = $json->jsonToObj($block); + last if ($obj->{PGM}->{type} =~ /NAK/); + } + alarm 0; + }; + if ($@) { + die unless $@ eq "alarm\n"; + confess "$self->{tag}: alarm raised waiting for nak.\n"; + } + + return $obj; +} + +sub wait_for_ncf { + my $self = shift; + my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; + my $obj = undef; + + eval { + local $SIG{ALRM} = sub { die "alarm\n"; }; + alarm $timeout; + for (;;) { + my $block = $self->wait_for_block; + $obj = $json->jsonToObj($block); + last if ($obj->{PGM}->{type} =~ /NCF/); + } + alarm 0; + }; + if ($@) { + die unless $@ eq "alarm\n"; + confess "$self->{tag}: alarm raised waiting for ncf.\n"; + } + + return $obj; +} + +sub print { + my $self = shift; + my $timeout = ref($_[0]) ? $_[0]->{'timeout'} : 10; + my $out = $self->{out}; + + print "$self->{tag}> @_"; + eval { + local($SIG{ALRM}) = sub { die "alarm\n"; }; + alarm $timeout; + print $out "@_"; + $self->wait_for_ready; + alarm 0; + }; + if ($@) { + die unless $@ eq "alarm\n"; + confess "$self->{tag}: alarm raised.\n"; + } +} + +sub say { + my $self = shift; + $self->print ("@_\n"); +} + +1; diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/SConscript b/3rdparty/openpgm-svn-r1135/pgm/test/SConscript new file mode 100644 index 0000000..7ca9926 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/SConscript @@ -0,0 +1,15 @@ +# -*- mode: python -*- +# OpenPGM build script +# $Id$ + +Import('env') +e = env.Clone(); +e.MergeFlags(env['GLIB_FLAGS']); +e.Append(LIBS = ['libpgm', 'libpgmex']); +e.Append(CCFLAGS = '-DGETTEXT_PACKAGE=\'"pgm"\''); + +e.Program(['monitor.c', 'dump-json.c']) +e.Program(['app.c', 'async.c']) +e.Program(['sim.c', 'dump-json.c', 'async.c']) + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/ambient_spm.pl b/3rdparty/openpgm-svn-r1135/pgm/test/ambient_spm.pl new file mode 100755 index 0000000..90de632 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/ambient_spm.pl @@ -0,0 +1,87 @@ +#!/usr/bin/perl +# ambient_spm.pl +# 5.1.4. Ambient SPMs + +use strict; +use PGM::Test; +use IO::Handle; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +pipe(FROM_PARENT, TO_CHILD) or die "pipe: $!"; +FROM_PARENT->autoflush(1); + +$mon->connect; +$app->connect; + +sub close_ssh { + close FROM_PARENT; close TO_CHILD; + $mon = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +if (my $pid = fork) { +# parent + close FROM_PARENT; + + print "mon: wait for odata ...\n"; + $mon->wait_for_odata; + print "mon: odata received.\n"; + print "mon: wait for spm ...\n"; + $mon->wait_for_spm ({ 'timeout' => 45 }); + print "mon: received spm.\n"; + + print TO_CHILD "die\n"; + + close TO_CHILD; + waitpid($pid,0); +} else { +# child + die "cannot fork: $!" unless defined $pid; + close TO_CHILD; + print "app: loop sending data.\n"; + vec(my $rin, fileno(FROM_PARENT), 1) = 1; + my $rout = undef; + +# hide stdout + open(OLDOUT, ">&STDOUT"); + open(STDOUT, ">/dev/null") or die "Can't redirect stdout: $!"; + +# send every ~50ms + while (! select($rout = $rin, undef, undef, 0.05)) + { + $app->say ("send ao ringo"); + } + +# restore stdout + close(STDOUT) or die "Can't close STDOUT: $!"; + open(STDOUT, ">&OLDOUT") or die "Can't restore stdout: $!"; + close(OLDOUT) or die "Can't close OLDOUT: $!"; + + print "app: loop finished.\n"; + close FROM_PARENT; + exit; +} + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/apdu.pl b/3rdparty/openpgm-svn-r1135/pgm/test/apdu.pl new file mode 100755 index 0000000..b26a3f2 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/apdu.pl @@ -0,0 +1,58 @@ +#!/usr/bin/perl +# apdu.pl +# 6.1. Data Reception + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("set network $config{app}{network}"); +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +$sim->say ("set network $config{sim}{network}"); +$sim->say ("create ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish APDU.\n"; +$sim->say ("send ao ringo x 1000"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: received data [$data].\n"; + +my $ref_data = "ringo" x 1000; +die "incoming data corrupt\n" unless ($data == $ref_data); + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/apdu_parity.pl b/3rdparty/openpgm-svn-r1135/pgm/test/apdu_parity.pl new file mode 100755 index 0000000..eb4cf27 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/apdu_parity.pl @@ -0,0 +1,59 @@ +#!/usr/bin/perl +# apdu_parity.pl +# 6.1. Data Reception + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$sim->connect; +$app->connect; + +sub close_ssh { + $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$app->say ("create ao"); +##$app->say ("set ao FEC RS(255,4)"); +$app->say ("bind ao"); +$app->say ("listen ao"); + +$sim->say ("create ao"); +$sim->say ("set ao FEC RS(255,4)"); +$sim->say ("bind ao"); + +print "sim: publish APDU.\n"; +$sim->say ("send brokn ao ringo x 1200"); + +print "sim: insert parity NAK from app.\n"; + +#print "sim: wait for NAK.\n"; +#my $nak = $sim->wait_for_nak; +#die "Selective NAK received, parityPacket=false\n" unless $nak->{PGM}->{options}->{parityPacket}; +#print "Parity NAK received.\n"; + +print "sim: insert parity RDATA from sim.\n"; + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: received data [$data].\n"; + +my $ref_data = "ringo" x 1200; +die "incoming data corrupt\n" unless ($data == $ref_data); + +print "test completed successfully.\n"; + +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/app.c b/3rdparty/openpgm-svn-r1135/pgm/test/app.c new file mode 100644 index 0000000..ea6a2b7 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/app.c @@ -0,0 +1,1068 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM conformance test application. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "async.h" + + +/* typedefs */ + +struct idle_source { + GSource source; + guint64 expiration; +}; + +struct app_session { + char* name; + pgm_sock_t* sock; + pgm_async_t* async; +}; + +/* globals */ +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "app" + +static int g_port = 7500; +static const char* g_network = ";239.192.0.1"; + +static guint g_max_tpdu = 1500; +static guint g_sqns = 100 * 1000; + +static GHashTable* g_sessions = NULL; +static GMainLoop* g_loop = NULL; +static GIOChannel* g_stdin_channel = NULL; + + +static void on_signal (int, gpointer); +static gboolean on_startup (gpointer); +static gboolean on_mark (gpointer); +static void destroy_session (gpointer, gpointer, gpointer); +static int on_data (gpointer, guint, gpointer); +static gboolean on_stdin_data (GIOChannel*, GIOCondition, gpointer); + + +G_GNUC_NORETURN static +void +usage (const char* bin) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + exit (1); +} + +int +main ( + int argc, + char *argv[] + ) +{ + pgm_error_t* err = NULL; + +/* pre-initialise PGM messages module to add hook for GLib logging */ + pgm_messages_init(); + log_init (); + g_message ("app"); + + if (!pgm_init (&err)) { + g_error ("Unable to start PGM engine: %s", (err && err->message) ? err->message : "(null)"); + pgm_error_free (err); + pgm_messages_shutdown(); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:h")) != -1) + { + switch (c) { + case 'n': g_network = optarg; break; + case 's': g_port = atoi (optarg); break; + + case 'h': + case '?': + pgm_messages_shutdown(); + usage (binary_name); + } + } + + g_loop = g_main_loop_new (NULL, FALSE); + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); + signal (SIGHUP, SIG_IGN); + pgm_signal_install (SIGINT, on_signal, g_loop); + pgm_signal_install (SIGTERM, on_signal, g_loop); + +/* delayed startup */ + g_message ("scheduling startup."); + g_timeout_add (0, (GSourceFunc)on_startup, NULL); + +/* dispatch loop */ + g_message ("entering main event loop ... "); + g_main_loop_run (g_loop); + + g_message ("event loop terminated, cleaning up."); + +/* cleanup */ + g_main_loop_unref(g_loop); + g_loop = NULL; + + if (g_sessions) { + g_message ("destroying sessions."); + g_hash_table_foreach_remove (g_sessions, (GHRFunc)destroy_session, NULL); + g_hash_table_unref (g_sessions); + g_sessions = NULL; + } + + if (g_stdin_channel) { + puts ("unbinding stdin."); + g_io_channel_unref (g_stdin_channel); + g_stdin_channel = NULL; + } + + g_message ("PGM engine shutdown."); + pgm_shutdown(); + g_message ("finished."); + pgm_messages_shutdown(); + return EXIT_SUCCESS; +} + +static +void +destroy_session ( + gpointer key, /* session name */ + gpointer value, /* transport_session object */ + G_GNUC_UNUSED gpointer user_data + ) +{ + struct app_session* sess = (struct app_session*)value; + + g_message ("closing socket \"%s\"", (char*)key); + pgm_close (sess->sock, TRUE); + sess->sock = NULL; + + if (sess->async) { + g_message ("destroying asynchronous session on \"%s\"", (char*)key); + pgm_async_destroy (sess->async); + sess->async = NULL; + } + + g_free (sess->name); + sess->name = NULL; + g_free (sess); +} + +static +void +on_signal ( + int signum, + gpointer user_data + ) +{ + GMainLoop* loop = (GMainLoop*)user_data; + g_message ("on_signal (signum:%d user-data:%p)", signum, user_data); + g_main_loop_quit (loop); +} + +static +gboolean +on_startup ( + G_GNUC_UNUSED gpointer data + ) +{ + g_message ("startup."); + + g_sessions = g_hash_table_new (g_str_hash, g_str_equal); + +/* add stdin to event manager */ + g_stdin_channel = g_io_channel_unix_new (fileno(stdin)); + printf ("binding stdin with encoding %s.\n", g_io_channel_get_encoding(g_stdin_channel)); + + g_io_add_watch (g_stdin_channel, G_IO_IN | G_IO_PRI, on_stdin_data, NULL); + +/* period timer to indicate some form of life */ +// TODO: Gnome 2.14: replace with g_timeout_add_seconds() + g_timeout_add(10 * 1000, (GSourceFunc)on_mark, NULL); + + puts ("READY"); + fflush (stdout); + return FALSE; +} + +static +int +on_data ( + gpointer data, + G_GNUC_UNUSED guint len, + G_GNUC_UNUSED gpointer user_data + ) +{ + printf ("DATA: %s\n", (char*)data); + fflush (stdout); + return 0; +} + +static +void +session_create ( + char* session_name + ) +{ + pgm_error_t* pgm_err = NULL; + +/* check for duplicate */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess != NULL) { + printf ("FAILED: duplicate session name '%s'\n", session_name); + return; + } + +/* create new and fill in bits */ + sess = g_new0(struct app_session, 1); + sess->name = g_memdup (session_name, strlen(session_name)+1); + + if (!pgm_socket (&sess->sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err)) { + printf ("FAILED: pgm_socket(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + pgm_error_free (pgm_err); + goto err_free; + } + +/* success */ + g_hash_table_insert (g_sessions, sess->name, sess); + printf ("created new session \"%s\"\n", sess->name); + puts ("READY"); + + return; + +err_free: + g_free(sess->name); + g_free(sess); +} + +static +void +session_set_nak_bo_ivl ( + char* session_name, + guint milliseconds + ) +{ +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + if (pgm_msecs (milliseconds) > INT_MAX) { + puts ("FAILED: value out of bounds"); + return; + } + + const int nak_bo_ivl = pgm_msecs (milliseconds); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl))) + printf ("FAILED: set NAK_BO_IVL = %dms\n", milliseconds); + else + puts ("READY"); +} + +static +void +session_set_nak_rpt_ivl ( + char* session_name, + guint milliseconds + ) +{ +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + if (pgm_msecs (milliseconds) > INT_MAX) { + puts ("FAILED: value out of bounds"); + return; + } + + const int nak_rpt_ivl = pgm_msecs (milliseconds); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl))) + printf ("FAILED: set NAK_RPT_IVL = %dms\n", milliseconds); + else + puts ("READY"); +} + +static +void +session_set_nak_rdata_ivl ( + char* session_name, + guint milliseconds + ) +{ +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + if (pgm_msecs (milliseconds) > INT_MAX) { + puts ("FAILED: value out of bounds"); + return; + } + + const int nak_rdata_ivl = pgm_msecs (milliseconds); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl))) + printf ("FAILED: set NAK_RDATA_IVL = %dms\n", milliseconds); + else + puts ("READY"); +} + +static +void +session_set_nak_ncf_retries ( + char* session_name, + guint retry_count + ) +{ +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + if (retry_count > INT_MAX) { + puts ("FAILED: value out of bounds"); + return; + } + + const int nak_ncf_retries = retry_count; + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries))) + printf ("FAILED: set NAK_NCF_RETRIES = %d\n", retry_count); + else + puts ("READY"); +} + +static +void +session_set_nak_data_retries ( + char* session_name, + guint retry_count + ) +{ +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + if (retry_count > INT_MAX) { + puts ("FAILED: value out of bounds"); + return; + } + + const int nak_data_retries = retry_count; + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries))) + printf ("FAILED: set NAK_DATA_RETRIES = %d\n", retry_count); + else + puts ("READY"); +} + +static +void +session_set_txw_max_rte ( + char* session_name, + guint bitrate + ) +{ +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + if (bitrate > INT_MAX) { + puts ("FAILED: value out of bounds"); + return; + } + + const int txw_max_rte = bitrate; + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_TXW_MAX_RTE, &txw_max_rte, sizeof(txw_max_rte))) + printf ("FAILED: set TXW_MAX_RTE = %d\n", bitrate); + else + puts ("READY"); +} + +static +void +session_set_fec ( + char* session_name, + guint block_size, + guint group_size + ) +{ +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + if (block_size > UINT8_MAX || + group_size > UINT8_MAX) + { + puts ("FAILED: value out of bounds"); + return; + } + + const struct pgm_fecinfo_t fecinfo = { + .block_size = block_size, + .proactive_packets = 0, + .group_size = group_size, + .ondemand_parity_enabled = TRUE, + .var_pktlen_enabled = TRUE + }; + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_USE_FEC, &fecinfo, sizeof(fecinfo))) + printf ("FAILED: set FEC = RS(%d, %d)\n", block_size, group_size); + else + puts ("READY"); +} + +static +void +session_bind ( + char* session_name + ) +{ + pgm_error_t* pgm_err = NULL; + +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist))) + puts ("FAILED: disable IP_ROUTER_ALERT"); + +/* set PGM parameters */ + const int send_and_receive = 0, + active = 0, + mtu = g_max_tpdu, + txw_sqns = g_sqns, + rxw_sqns = g_sqns, + ambient_spm = pgm_secs (30), + heartbeat_spm[] = { pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (1300), + pgm_secs (7), + pgm_secs (16), + pgm_secs (25), + pgm_secs (30) }, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + g_assert (G_N_ELEMENTS(heartbeat_spm) > 0); + + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_SEND_ONLY, &send_and_receive, sizeof(send_and_receive))) + puts ("FAILED: set bi-directional transport"); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_RECV_ONLY, &send_and_receive, sizeof(send_and_receive))) + puts ("FAILED: set bi-directional transport"); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_PASSIVE, &active, sizeof(active))) + puts ("FAILED: set active transport"); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_MTU, &mtu, sizeof(mtu))) + printf ("FAILED: set MAX_TPDU = %d bytes\n", mtu); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_TXW_SQNS, &txw_sqns, sizeof(txw_sqns))) + printf ("FAILED: set TXW_SQNS = %d\n", txw_sqns); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_RXW_SQNS, &rxw_sqns, sizeof(rxw_sqns))) + printf ("FAILED: set RXW_SQNS = %d\n", rxw_sqns); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm))) + printf ("FAILED: set AMBIENT_SPM = %ds\n", (int)pgm_to_secs (ambient_spm)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm))) + { + char buffer[1024]; + sprintf (buffer, "%d", heartbeat_spm[0]); + for (unsigned i = 1; i < G_N_ELEMENTS(heartbeat_spm); i++) { + char t[1024]; + sprintf (t, ", %d", heartbeat_spm[i]); + strcat (buffer, t); + } + printf ("FAILED: set HEARTBEAT_SPM = { %s }\n", buffer); + } + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry))) + printf ("FAILED: set PEER_EXPIRY = %ds\n",(int) pgm_to_secs (peer_expiry)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry))) + printf ("FAILED: set SPMR_EXPIRY = %dms\n", (int)pgm_to_msecs (spmr_expiry)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl))) + printf ("FAILED: set NAK_BO_IVL = %dms\n", (int)pgm_to_msecs (nak_bo_ivl)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl))) + printf ("FAILED: set NAK_RPT_IVL = %dms\n", (int)pgm_to_msecs (nak_rpt_ivl)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl))) + printf ("FAILED: set NAK_RDATA_IVL = %dms\n", (int)pgm_to_msecs (nak_rdata_ivl)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries))) + printf ("FAILED: set NAK_DATA_RETRIES = %d\n", nak_data_retries); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries))) + printf ("FAILED: set NAK_NCF_RETRIES = %d\n", nak_ncf_retries); + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = g_port; + addr.sa_addr.sport = 0; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + printf ("FAILED: pgm_gsi_create_from_hostname(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + } + +{ + char buffer[1024]; + pgm_tsi_print_r (&addr.sa_addr, buffer, sizeof(buffer)); + printf ("pgm_bind (sock:%p addr:{port:%d tsi:%s} err:%p)\n", + (gpointer)sess->sock, + addr.sa_port, buffer, + (gpointer)&pgm_err); +} + if (!pgm_bind (sess->sock, &addr, sizeof(addr), &pgm_err)) { + printf ("FAILED: pgm_bind(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + pgm_error_free (pgm_err); + } else + puts ("READY"); +} + +static +void +session_connect ( + char* session_name + ) +{ + struct pgm_addrinfo_t hints = { + .ai_family = AF_INET + }, *res = NULL; + pgm_error_t* pgm_err = NULL; + +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + if (!pgm_getaddrinfo (g_network, &hints, &res, &pgm_err)) { + printf ("FAILED: pgm_getaddrinfo(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + pgm_error_free (pgm_err); + return; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req))) + { + char group[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&res->ai_recv_addrs[i].gsr_group, sizeof(struct sockaddr_in), + group, sizeof(group), + NULL, 0, + NI_NUMERICHOST); + printf ("FAILED: join group (#%u %s)\n", (unsigned)res->ai_recv_addrs[i].gsr_interface, group); + } + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req))) + { + char group[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, sizeof(struct sockaddr_in), + group, sizeof(group), + NULL, 0, + NI_NUMERICHOST); + printf ("FAILED: send group (#%u %s)\n", (unsigned)res->ai_send_addrs[0].gsr_interface, group); + } + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int non_blocking = 1, + no_multicast_loop = 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &no_multicast_loop, sizeof(no_multicast_loop))) + puts ("FAILED: disable multicast loop"); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops))) + printf ("FAILED: set TTL = %d\n", multicast_hops); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp))) + printf ("FAILED: set TOS = 0x%x\n", dscp); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NOBLOCK, &non_blocking, sizeof(non_blocking))) + puts ("FAILED: set non-blocking sockets"); + + if (!pgm_connect (sess->sock, &pgm_err)) { + printf ("FAILED: pgm_connect(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + } else + puts ("READY"); +} + +static +void +session_send ( + char* session_name, + char* string + ) +{ +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + +/* send message */ + int status; + gsize stringlen = strlen(string) + 1; + int n_fds = 1; + struct pollfd fds[ n_fds ]; + struct timeval tv; + int timeout; +again: +printf ("pgm_send (sock:%p string:\"%s\" stringlen:%" G_GSIZE_FORMAT " NULL)\n", (gpointer)sess->sock, string, stringlen); + status = pgm_send (sess->sock, string, stringlen, NULL); + switch (status) { + case PGM_IO_STATUS_NORMAL: + puts ("READY"); + break; + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (sess->sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (sess->sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } +/* fall through */ + case PGM_IO_STATUS_WOULD_BLOCK: +block: + timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + memset (fds, 0, sizeof(fds)); + pgm_poll_info (sess->sock, fds, &n_fds, POLLOUT); + poll (fds, n_fds, timeout /* ms */); + goto again; + default: + puts ("FAILED: pgm_send()"); + break; + } +} + +static +void +session_listen ( + char* session_name + ) +{ + GError* err = NULL; + +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + +/* listen */ +printf ("pgm_async_create (async:%p sock:%p err:%p)\n", (gpointer)&sess->async, (gpointer)sess->sock, (gpointer)&err); + if (!pgm_async_create (&sess->async, sess->sock, &err)) { + printf ("FAILED: pgm_async_create(): %s", err->message); + g_error_free (err); + return; + } + pgm_async_add_watch (sess->async, on_data, sess); + puts ("READY"); +} + +static +void +session_destroy ( + char* session_name + ) +{ +/* check that session exists */ + struct app_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + +/* remove from hash table */ + g_hash_table_remove (g_sessions, session_name); + +/* stop any async thread */ + if (sess->async) { + pgm_async_destroy (sess->async); + sess->async = NULL; + } + + pgm_close (sess->sock, TRUE); + sess->sock = NULL; + g_free (sess->name); + sess->name = NULL; + g_free (sess); + + puts ("READY"); +} + +/* process input commands from stdin/fd + */ + +static +gboolean +on_stdin_data ( + GIOChannel* source, + G_GNUC_UNUSED GIOCondition condition, + G_GNUC_UNUSED gpointer data + ) +{ + gchar* str = NULL; + gsize len = 0; + gsize term = 0; + GError* err = NULL; + + g_io_channel_read_line (source, &str, &len, &term, &err); + if (len > 0) { + if (term) str[term] = 0; + +/* quit */ + if (strcmp(str, "quit") == 0) + { + g_main_loop_quit(g_loop); + goto out; + } + + regex_t preg; + regmatch_t pmatch[10]; + +/* create socket */ + const char *re = "^create[[:space:]]+([[:alnum:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + session_create (name); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* set NAK_BO_IVL */ + re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+NAK_BO_IVL[[:space:]]+([0-9]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + char *p = str + pmatch[2].rm_so; + guint nak_bo_ivl = strtol (p, &p, 10); + + session_set_nak_bo_ivl (name, nak_bo_ivl); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* set NAK_RPT_IVL */ + re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+NAK_RPT_IVL[[:space:]]+([0-9]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + char *p = str + pmatch[2].rm_so; + guint nak_rpt_ivl = strtol (p, &p, 10); + + session_set_nak_rpt_ivl (name, nak_rpt_ivl); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* set NAK_RDATA_IVL */ + re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+NAK_RDATA_IVL[[:space:]]+([0-9]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + char *p = str + pmatch[2].rm_so; + guint nak_rdata_ivl = strtol (p, &p, 10); + + session_set_nak_rdata_ivl (name, nak_rdata_ivl); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* set NAK_NCF_RETRIES */ + re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+NAK_NCF_RETRIES[[:space:]]+([0-9]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + char *p = str + pmatch[2].rm_so; + guint nak_ncf_retries = strtol (p, &p, 10); + + session_set_nak_ncf_retries (name, nak_ncf_retries); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* set NAK_DATA_RETRIES */ + re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+NAK_DATA_RETRIES[[:space:]]+([0-9]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + char *p = str + pmatch[2].rm_so; + guint nak_data_retries = strtol (p, &p, 10); + + session_set_nak_data_retries (name, nak_data_retries); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* set TXW_MAX_RTE */ + re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+TXW_MAX_RTE[[:space:]]+([0-9]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + char *p = str + pmatch[2].rm_so; + guint txw_max_rte = strtol (p, &p, 10); + + session_set_txw_max_rte (name, txw_max_rte); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* enable Reed-Solomon Forward Error Correction */ + re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+FEC[[:space:]]+RS[[:space:]]*\\([[:space:]]*([0-9]+)[[:space:]]*,[[:space:]]*([0-9]+)[[:space:]]*\\)$"; + regcomp (&preg, re, REG_EXTENDED); + + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + char *p = str + pmatch[2].rm_so; + *(str + pmatch[2].rm_eo) = 0; + guint n = strtol (p, &p, 10); + p = str + pmatch[3].rm_so; + *(str + pmatch[3].rm_eo) = 0; + guint k = strtol (p, &p, 10); + session_set_fec (name, n, k); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* bind socket */ + re = "^bind[[:space:]]+([[:alnum:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + session_bind (name); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* connect socket */ + re = "^connect[[:space:]]+([[:alnum:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + session_connect (name); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* send packet */ + re = "^send[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + char *string = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); + string[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; + + session_send (name, string); + + g_free (name); + g_free (string); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* listen */ + re = "^listen[[:space:]]+([[:alnum:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + session_listen (name); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* destroy transport */ + re = "^destroy[[:space:]]+([[:alnum:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + session_destroy (name); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* set PGM network */ + re = "^set[[:space:]]+network[[:space:]]+([[:print:]]*;[[:print:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char* pgm_network = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + pgm_network[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + g_network = pgm_network; + puts ("READY"); + + regfree (&preg); + goto out; + } + regfree (&preg); + + printf ("unknown command: %s\n", str); + } + +out: + fflush (stdout); + g_free (str); + return TRUE; +} + +/* idle log notification + */ + +static +gboolean +on_mark ( + G_GNUC_UNUSED gpointer data + ) +{ + g_message ("-- MARK --"); + return TRUE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/async.c b/3rdparty/openpgm-svn-r1135/pgm/test/async.c new file mode 100644 index 0000000..3be1458 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/async.c @@ -0,0 +1,579 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Asynchronous queue for receiving packets in a separate managed thread. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include "async.h" + + +//#define ASYNC_DEBUG + +#ifndef ASYNC_DEBUG +# define g_trace(...) while (0) +#else +#include +# define g_trace(...) g_debug(__VA_ARGS__) +#endif + + +/* globals */ + + +/* global locals */ + +typedef struct pgm_event_t pgm_event_t; + +struct pgm_event_t { + gpointer data; + guint len; +}; + + +/* external: Glib event loop GSource of pgm contiguous data */ +struct pgm_watch_t { + GSource source; + GPollFD pollfd; + pgm_async_t* async; +}; + +typedef struct pgm_watch_t pgm_watch_t; + + +static gboolean pgm_src_prepare (GSource*, gint*); +static gboolean pgm_src_check (GSource*); +static gboolean pgm_src_dispatch (GSource*, GSourceFunc, gpointer); + +static GSourceFuncs g_pgm_watch_funcs = { + .prepare = pgm_src_prepare, + .check = pgm_src_check, + .dispatch = pgm_src_dispatch, + .finalize = NULL, + .closure_callback = NULL +}; + + +static inline gpointer pgm_event_alloc (pgm_async_t* const) G_GNUC_MALLOC; +static PGMAsyncError pgm_async_error_from_errno (const gint); + + +static inline +gpointer +pgm_event_alloc ( + pgm_async_t* const async + ) +{ + g_return_val_if_fail (async != NULL, NULL); + return g_slice_alloc (sizeof(pgm_event_t)); +} + +/* release event memory for custom async queue dispatch handlers + */ + +static inline +void +pgm_event_unref ( + pgm_async_t* const async, + pgm_event_t* const event + ) +{ + g_return_if_fail (async != NULL); + g_return_if_fail (event != NULL); + g_slice_free1 (sizeof(pgm_event_t), event); +} + +/* internal receiver thread, sits in a loop processing incoming packets + */ + +static +gpointer +pgm_receiver_thread ( + gpointer data + ) +{ + g_assert (NULL != data); + + pgm_async_t* async = (pgm_async_t*)data; + g_async_queue_ref (async->commit_queue); + +/* incoming message buffer */ + struct pgm_msgv_t msgv; + gsize bytes_read = 0; + struct timeval tv; + + do { +/* blocking read */ + const int status = pgm_recvmsg (async->sock, &msgv, 0, &bytes_read, NULL); + switch (status) { + case PGM_IO_STATUS_NORMAL: + { +/* queue a copy to receiver */ + pgm_event_t* event = pgm_event_alloc (async); + event->data = bytes_read > 0 ? g_malloc (bytes_read) : NULL; + event->len = bytes_read; + gpointer dst = event->data; + guint i = 0; + while (bytes_read) { + const struct pgm_sk_buff_t* skb = msgv.msgv_skb[i++]; + g_assert (NULL != skb); + g_assert (skb->len > 0); + g_assert (skb->len <= bytes_read); + memcpy (dst, skb->data, skb->len); + dst = (char*)dst + skb->len; + bytes_read -= skb->len; + } +/* prod pipe on edge */ + g_async_queue_lock (async->commit_queue); + g_async_queue_push_unlocked (async->commit_queue, event); + if (g_async_queue_length_unlocked (async->commit_queue) == 1) + pgm_notify_send (&async->commit_notify); + g_async_queue_unlock (async->commit_queue); + break; + } + + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (async->sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (async->sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } +/* fall through */ + case PGM_IO_STATUS_WOULD_BLOCK: +block: + { +#ifdef CONFIG_HAVE_POLL + const int timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + int n_fds = 3; + struct pollfd fds[1+n_fds]; + memset (fds, 0, sizeof(fds)); + fds[0].fd = pgm_notify_get_fd (&async->destroy_notify); + fds[0].events = POLLIN; + if (-1 == pgm_poll_info (async->sock, &fds[1], &n_fds, POLLIN)) { + g_trace ("poll_info returned errno=%i",errno); + goto cleanup; + } + const int ready = poll (fds, 1 + n_fds, timeout); +#else /* HAVE_SELECT */ + fd_set readfds; + int fd = pgm_notify_get_fd (&async->destroy_notify), n_fds = 1 + fd; + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + if (-1 == pgm_select_info (async->sock, &readfds, NULL, &n_fds)) { + g_trace ("select_info returned errno=%i",errno); + goto cleanup; + } + const int ready = select (n_fds, &readfds, NULL, NULL, PGM_IO_STATUS_RATE_LIMITED == status ? &tv : NULL); +#endif + if (-1 == ready) { + g_trace ("block returned errno=%i",errno); + goto cleanup; + } +#ifdef CONFIG_HAVE_POLL + if (ready > 0 && fds[0].revents) +#else + if (ready > 0 && FD_ISSET(fd, &readfds)) +#endif + goto cleanup; + break; + } + + case PGM_IO_STATUS_ERROR: + case PGM_IO_STATUS_EOF: + goto cleanup; + + case PGM_IO_STATUS_RESET: + { + int is_abort_on_reset; + socklen_t optlen = sizeof (is_abort_on_reset); + pgm_getsockopt (async->sock, IPPROTO_PGM, PGM_ABORT_ON_RESET, &is_abort_on_reset, &optlen); + if (is_abort_on_reset) + goto cleanup; + break; + } + +/* TODO: report to user */ + case PGM_IO_STATUS_FIN: + break; + + default: + g_assert_not_reached(); + } + } while (!async->is_destroyed); + +cleanup: + g_async_queue_unref (async->commit_queue); + return NULL; +} + +/* create asynchronous thread handler + * + * on success, 0 is returned. on error, -1 is returned, and errno set appropriately. + * on invalid parameters, -EINVAL is returned. + */ + +gboolean +pgm_async_create ( + pgm_async_t** async, + pgm_sock_t* const sock, + GError** error + ) +{ + pgm_async_t* new_async; + + g_return_val_if_fail (NULL != async, FALSE); + g_return_val_if_fail (NULL != sock, FALSE); + + g_trace ("create (async:%p sock:%p error:%p)", + (gpointer)async, (gpointer)sock, (gpointer)error); + + if (!g_thread_supported()) + g_thread_init (NULL); + + new_async = g_new0 (pgm_async_t, 1); + new_async->sock = sock; + if (0 != pgm_notify_init (&new_async->commit_notify) || + 0 != pgm_notify_init (&new_async->destroy_notify)) + { + g_set_error (error, + PGM_ASYNC_ERROR, + pgm_async_error_from_errno (errno), + _("Creating async notification channels: %s"), + g_strerror (errno)); + g_free (new_async); + return FALSE; + } + new_async->commit_queue = g_async_queue_new(); +/* setup new thread */ + new_async->thread = g_thread_create_full (pgm_receiver_thread, + new_async, + 0, + TRUE, + TRUE, + G_THREAD_PRIORITY_HIGH, + error); + if (NULL == new_async->thread) { + g_async_queue_unref (new_async->commit_queue); + pgm_notify_destroy (&new_async->commit_notify); + g_free (new_async); + return FALSE; + } + +/* return new object */ + *async = new_async; + return TRUE; +} + +/* tell async thread to stop, wait for it to stop, then cleanup. + * + * on success, 0 is returned. if async is invalid, -EINVAL is returned. + */ + +gboolean +pgm_async_destroy ( + pgm_async_t* const async + ) +{ + g_return_val_if_fail (NULL != async, FALSE); + g_return_val_if_fail (!async->is_destroyed, FALSE); + + async->is_destroyed = TRUE; + pgm_notify_send (&async->destroy_notify); + if (async->thread) + g_thread_join (async->thread); + if (async->commit_queue) { + g_async_queue_unref (async->commit_queue); + async->commit_queue = NULL; + } + pgm_notify_destroy (&async->destroy_notify); + pgm_notify_destroy (&async->commit_notify); + g_free (async); + return TRUE; +} + +/* queue to GSource and GMainLoop */ + +GSource* +pgm_async_create_watch ( + pgm_async_t* async + ) +{ + g_return_val_if_fail (async != NULL, NULL); + + GSource *source = g_source_new (&g_pgm_watch_funcs, sizeof(pgm_watch_t)); + pgm_watch_t *watch = (pgm_watch_t*)source; + + watch->async = async; + watch->pollfd.fd = pgm_async_get_fd (async); + watch->pollfd.events = G_IO_IN; + + g_source_add_poll (source, &watch->pollfd); + + return source; +} + +/* pgm transport attaches to the callees context: the default context instead of + * any internal contexts. + */ + +int +pgm_async_add_watch_full ( + pgm_async_t* async, + gint priority, + pgm_eventfn_t function, + gpointer user_data, + GDestroyNotify notify + ) +{ + g_return_val_if_fail (async != NULL, -EINVAL); + g_return_val_if_fail (function != NULL, -EINVAL); + + GSource* source = pgm_async_create_watch (async); + + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority (source, priority); + + g_source_set_callback (source, (GSourceFunc)function, user_data, notify); + + guint id = g_source_attach (source, NULL); + g_source_unref (source); + + return id; +} + +int +pgm_async_add_watch ( + pgm_async_t* async, + pgm_eventfn_t function, + gpointer user_data + ) +{ + return pgm_async_add_watch_full (async, G_PRIORITY_HIGH, function, user_data, NULL); +} + +/* returns TRUE if source has data ready, i.e. async queue is not empty + * + * called before event loop poll() + */ + +static +gboolean +pgm_src_prepare ( + GSource* source, + gint* timeout + ) +{ + pgm_watch_t* watch = (pgm_watch_t*)source; + +/* infinite timeout */ + *timeout = -1; + + return ( g_async_queue_length(watch->async->commit_queue) > 0 ); +} + +/* called after event loop poll() + * + * return TRUE if ready to dispatch. + */ + +static +gboolean +pgm_src_check ( + GSource* source + ) +{ + pgm_watch_t* watch = (pgm_watch_t*)source; + + return ( g_async_queue_length(watch->async->commit_queue) > 0 ); +} + +/* called when TRUE returned from prepare or check + */ + +static gboolean +pgm_src_dispatch ( + GSource* source, + GSourceFunc callback, + gpointer user_data + ) +{ + g_trace ("pgm_src_dispatch (source:%p callback:() user-data:%p)", + (gpointer)source, user_data); + + const pgm_eventfn_t function = (pgm_eventfn_t)callback; + pgm_watch_t* watch = (pgm_watch_t*)source; + pgm_async_t* async = watch->async; + +/* empty pipe */ + pgm_notify_read (&async->commit_notify); + +/* purge only one message from the asynchronous queue */ + pgm_event_t* event = g_async_queue_try_pop (async->commit_queue); + if (event) + { +/* important that callback occurs out of lock to allow PGM layer to add more messages */ + (*function) (event->data, event->len, user_data); + +/* return memory to receive window */ + if (event->len) g_free (event->data); + pgm_event_unref (async, event); + } + + return TRUE; +} + +/* synchronous reading from the queue. + * + * returns GIOStatus with success, error, again, or eof. + */ + +GIOStatus +pgm_async_recv ( + pgm_async_t* const async, + gpointer data, + const gsize len, + gsize* const bytes_read, + const int flags, /* MSG_DONTWAIT for non-blocking */ + GError** error + ) +{ + g_return_val_if_fail (NULL != async, G_IO_STATUS_ERROR); + if (len) g_return_val_if_fail (NULL != data, G_IO_STATUS_ERROR); + + g_trace ("pgm_async_recv (async:%p data:%p len:%" G_GSIZE_FORMAT" bytes-read:%p flags:%d error:%p)", + (gpointer)async, data, len, (gpointer)bytes_read, flags, (gpointer)error); + + pgm_event_t* event = NULL; + g_async_queue_lock (async->commit_queue); + if (g_async_queue_length_unlocked (async->commit_queue) == 0) + { + g_async_queue_unlock (async->commit_queue); + if (flags & MSG_DONTWAIT || async->is_nonblocking) + return G_IO_STATUS_AGAIN; +#ifdef CONFIG_HAVE_POLL + struct pollfd fds[1]; + int ready; + do { + memset (fds, 0, sizeof(fds)); + fds[0].fd = pgm_notify_get_fd (&async->commit_notify); + fds[0].events = POLLIN; + ready = poll (fds, G_N_ELEMENTS(fds), -1); + if (-1 == ready || async->is_destroyed) /* errno = EINTR */ + return G_IO_STATUS_ERROR; + } while (ready <= 0); +#else + fd_set readfds; + int n_fds, ready, fd = pgm_notify_get_fd (&async->commit_notify); + do { + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + n_fds = fd + 1; + ready = select (n_fds, &readfds, NULL, NULL, NULL); + if (-1 == ready || async->is_destroyed) /* errno = EINTR */ + return G_IO_STATUS_ERROR; + } while (ready <= 0); +#endif + pgm_notify_read (&async->commit_notify); + g_async_queue_lock (async->commit_queue); + } + event = g_async_queue_pop_unlocked (async->commit_queue); + g_async_queue_unlock (async->commit_queue); + +/* pass data back to callee */ + if (event->len > len) { + *bytes_read = len; + memcpy (data, event->data, *bytes_read); + g_set_error (error, + PGM_ASYNC_ERROR, + PGM_ASYNC_ERROR_OVERFLOW, + _("Message too large to be stored in buffer.")); + pgm_event_unref (async, event); + return G_IO_STATUS_ERROR; + } + + if (bytes_read) + *bytes_read = event->len; + memcpy (data, event->data, event->len); + +/* cleanup */ + if (event->len) g_free (event->data); + pgm_event_unref (async, event); + return G_IO_STATUS_NORMAL; +} + +gboolean +pgm_async_set_nonblocking ( + pgm_async_t* const async, + const gboolean nonblocking + ) +{ + g_return_val_if_fail (NULL != async, FALSE); + async->is_nonblocking = nonblocking; + return TRUE; +} + +GQuark +pgm_async_error_quark (void) +{ + return g_quark_from_static_string ("pgm-async-error-quark"); +} + +static +PGMAsyncError +pgm_async_error_from_errno ( + const gint err_no + ) +{ + switch (err_no) { +#ifdef EFAULT + case EFAULT: + return PGM_ASYNC_ERROR_FAULT; + break; +#endif + +#ifdef EMFILE + case EMFILE: + return PGM_ASYNC_ERROR_MFILE; + break; +#endif + +#ifdef ENFILE + case ENFILE: + return PGM_ASYNC_ERROR_NFILE; + break; +#endif + + default : + return PGM_ASYNC_ERROR_FAILED; + break; + } +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/async.h b/3rdparty/openpgm-svn-r1135/pgm/test/async.h new file mode 100644 index 0000000..d801abd --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/async.h @@ -0,0 +1,76 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * Asynchronous receive thread helper + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_ASYNC_H__ +#define __PGM_ASYNC_H__ + +#include +#include +#include + + +#define PGM_ASYNC_ERROR pgm_async_error_quark () + +typedef enum +{ + /* Derived from errno */ + PGM_ASYNC_ERROR_FAULT, + PGM_ASYNC_ERROR_MFILE, + PGM_ASYNC_ERROR_NFILE, + PGM_ASYNC_ERROR_OVERFLOW, + PGM_ASYNC_ERROR_FAILED +} PGMAsyncError; + +typedef struct pgm_async_t pgm_async_t; + +struct pgm_async_t { + pgm_sock_t* sock; + GThread* thread; + GAsyncQueue* commit_queue; + pgm_notify_t commit_notify; + pgm_notify_t destroy_notify; + gboolean is_destroyed; + gboolean is_nonblocking; +}; + +typedef int (*pgm_eventfn_t)(gpointer, guint, gpointer); + + +G_BEGIN_DECLS + +int pgm_async_create (pgm_async_t**, pgm_sock_t* const, GError**); +int pgm_async_destroy (pgm_async_t* const); +GIOStatus pgm_async_recv (pgm_async_t* const, gpointer, const gsize, gsize* const, const int, GError**); +gboolean pgm_async_set_nonblocking (pgm_async_t* const, const gboolean); +GSource* pgm_async_create_watch (pgm_async_t* const) G_GNUC_WARN_UNUSED_RESULT; +int pgm_async_add_watch_full (pgm_async_t*, gint, pgm_eventfn_t, gpointer, GDestroyNotify); +int pgm_async_add_watch (pgm_async_t*, pgm_eventfn_t, gpointer); +GQuark pgm_async_error_quark (void); + +static inline int pgm_async_get_fd (pgm_async_t* async) +{ + g_return_val_if_fail (async != NULL, -EINVAL); + return pgm_notify_get_fd (&async->commit_notify); +} + +G_END_DECLS + +#endif /* __PGM_ASYNC_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/dump-json.c b/3rdparty/openpgm-svn-r1135/pgm/test/dump-json.c new file mode 100644 index 0000000..adbc217 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/dump-json.c @@ -0,0 +1,1292 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * JSON packet dump. + * + * Copyright (c) 2006-2008 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "dump-json.h" + + +/* globals */ + +#define OPTIONS_TOTAL_LEN(x) *(guint16*)( ((char*)(x)) + sizeof(guint16) ) + + +int verify_ip_header (struct pgm_ip*, guint); +void print_ip_header (struct pgm_ip*); +int verify_pgm_header (struct pgm_header*, guint); +void print_pgm_header (struct pgm_header*); +int verify_spm (struct pgm_header*, char*, guint); +void print_spm (struct pgm_header*, char*); +int verify_poll (struct pgm_header*, char*, guint); +void print_poll (struct pgm_header*, char*); +int verify_polr (struct pgm_header*, char*, guint); +void print_polr (struct pgm_header*, char*); +int verify_odata (struct pgm_header*, char*, guint); +void print_odata (struct pgm_header*, char*); +int verify_rdata (struct pgm_header*, char*, guint); +void print_rdata (struct pgm_header*, char*); +static int generic_verify_nak (const char*, struct pgm_header*, char*, guint); +static void generic_print_nak (const char*, struct pgm_header*, char*); +int verify_nak (struct pgm_header*, char*, guint); +void print_nak (struct pgm_header*, char*); +int verify_nnak (struct pgm_header*, char*, guint); +void print_nnak (struct pgm_header*, char*); +int verify_ncf (struct pgm_header*, char*, guint); +void print_ncf (struct pgm_header*, char*); +int verify_spmr (struct pgm_header*, char*, guint); +void print_spmr (struct pgm_header*, char*); +int verify_options (char*, guint); +void print_options (char*); + + +int +monitor_packet ( + char* data, + guint len + ) +{ + static int count = 0; + + puts ("{"); + printf ("\t\"id\": %i,\n", ++count); + + int retval = 0; + + struct pgm_ip* ip = (struct pgm_ip*)data; + if (verify_ip_header (ip, len) < 0) { + puts ("\t\"valid\": false"); + retval = -1; + goto out; + } + + struct pgm_header* pgm = (struct pgm_header*)(data + (ip->ip_hl * 4)); + guint pgm_len = len - (ip->ip_hl * 4); + if (verify_pgm_header (pgm, pgm_len) < 0) { + puts ("\t\"valid\": false"); + retval = -1; + goto out; + } + + char* pgm_data = (char*)(pgm + 1); + guint pgm_data_len = pgm_len - sizeof(struct pgm_header); + switch (pgm->pgm_type) { + case PGM_SPM: retval = verify_spm (pgm, pgm_data, pgm_data_len); break; + case PGM_POLL: retval = verify_poll (pgm, pgm_data, pgm_data_len); break; + case PGM_POLR: retval = verify_polr (pgm, pgm_data, pgm_data_len); break; + case PGM_ODATA: retval = verify_odata (pgm, pgm_data, pgm_data_len); break; + case PGM_RDATA: retval = verify_rdata (pgm, pgm_data, pgm_data_len); break; + case PGM_NAK: retval = verify_nak (pgm, pgm_data, pgm_data_len); break; + case PGM_NNAK: retval = verify_nnak (pgm, pgm_data, pgm_data_len); break; + case PGM_NCF: retval = verify_ncf (pgm, pgm_data, pgm_data_len); break; + case PGM_SPMR: retval = verify_spmr (pgm, pgm_data, pgm_data_len); break; + } + + if (retval < 0) { + puts ("\t\"valid\": false"); + goto out; + } + +/* packet verified correct */ + puts ("\t\"valid\": true,"); + + print_ip_header (ip); + print_pgm_header (pgm); + + switch (pgm->pgm_type) { + case PGM_SPM: print_spm (pgm, pgm_data); break; + case PGM_POLL: print_poll (pgm, pgm_data); break; + case PGM_POLR: print_polr (pgm, pgm_data); break; + case PGM_ODATA: print_odata (pgm, pgm_data); break; + case PGM_RDATA: print_rdata (pgm, pgm_data); break; + case PGM_NAK: print_nak (pgm, pgm_data); break; + case PGM_NNAK: print_nnak (pgm, pgm_data); break; + case PGM_NCF: print_ncf (pgm, pgm_data); break; + case PGM_SPMR: print_spmr (pgm, pgm_data); break; + } + +out: + puts ("}"); + return retval; +} + + +int +verify_ip_header ( + struct pgm_ip* ip, + guint len + ) +{ +/* minimum size should be IP header plus PGM header */ + if (len < (sizeof(struct pgm_ip) + sizeof(struct pgm_header))) + { + printf ("\t\"message\": \"IP: packet size too small: %i bytes, expecting at least %" G_GSIZE_FORMAT " bytes.\",\n", len, sizeof(struct pgm_header)); + return -1; + } + +/* IP packet header: IPv4 + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Version| HL | ToS | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Fragment ID |R|D|M| Fragment Offset | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | TTL | Protocol | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source IP Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Destination IP Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | IP Options when present ... + * +-+-+-+-+-+-+-+-+-+-+-+-+ ... + * | Data ... + * +-+-+- ... + * + * IPv6: n/a + */ + +/* decode IP header */ + if (ip->ip_v != 4 && ip->ip_v != 6) { /* IP version, 4 or 6 */ + printf ("\t\"message\": \"IP: unknown IP version %i.\",\n", ip->ip_v); + return -1; + } + + guint ip_header_length = ip->ip_hl * 4; /* IP header length in 32bit octets */ + if (ip_header_length < sizeof(struct pgm_ip)) { + printf ("\t\"message\": \"IP: bad IP header length %i, should be at least %" G_GSIZE_FORMAT "lu bytes.\",\n", ip_header_length, sizeof(struct pgm_ip)); + return -1; + } + +/* ip_len can equal packet_length - ip_header_length in FreeBSD/NetBSD + * Stevens/Fenner/Rudolph, Unix Network Programming Vol.1, p.739 + * + * RFC3828 allows partial packets such that len < packet_length with UDP lite + */ + guint packet_length = g_ntohs(ip->ip_len); /* total packet length */ + if (len < packet_length) { /* redundant: often handled in kernel */ + printf ("\t\"message\": \"IP: truncated IP packet: header reports %i actual length %i bytes.\",\n", (int)len, (int)packet_length); + return -1; + } + +/* TCP Segmentation Offload (TSO) might have zero length here */ + if (packet_length < ip_header_length) { + printf ("\t\"message\": \"IP: header reports %i less than IP header length %i.\",\n", (int)packet_length, (int)ip_header_length); + return -1; + } + +/* packets that fail checksum will generally not be passed upstream except with rfc3828 + */ + int sum = pgm_inet_checksum((char*)ip, ip_header_length, 0); + if (sum != 0) { + int ip_sum = g_ntohs(ip->ip_sum); + printf ("\t\"message\": \"IP: IP header checksum incorrect: 0x%x.\",\n", ip_sum); + return -2; + } + + if (ip->ip_p != IPPROTO_PGM) { + printf ("\t\"message\": \"IP: packet IP protocol not PGM: %i.\",\n", ip->ip_p); + return -1; + } + +/* fragmentation offset, bit 0: 0, bit 1: do-not-fragment, bit 2: more-fragments */ + int offset = g_ntohs(ip->ip_off); + if ((offset & 0x1fff) != 0) { + printf ("\t\"message\": \"IP: fragmented IP packet, ignoring.\",\n"); + return -1; + } + + return 0; +} + +void +print_ip_header ( + struct pgm_ip* ip + ) +{ + puts ("\t\"IP\": {"); + printf ("\t\t\"version\": %i,\n", + ip->ip_v + ); + printf ("\t\t\"headerLength\": %i,\n", + ip->ip_hl + ); + printf ("\t\t\"ToS\": %i,\n", + ip->ip_tos & 0x3 + ); + printf ("\t\t\"length\": %i,\n", + g_ntohs(ip->ip_len) + ); + printf ("\t\t\"fragmentId\": %i,\n", + g_ntohs(ip->ip_id) + ); + printf ("\t\t\"DF\": %s,\n", + (g_ntohs(ip->ip_off) & 0x4000) ? "true" : "false" + ); + printf ("\t\t\"MF\": %s,\n", + (g_ntohs(ip->ip_off) & 0x2000) ? "true" : "false" + ); + printf ("\t\t\"fragmentOffset\": %i,\n", + g_ntohs(ip->ip_off) & 0x1fff + ); + printf ("\t\t\"TTL\": %i,\n", + ip->ip_ttl + ); + printf ("\t\t\"protocol\": %i,\n", + ip->ip_p + ); + printf ("\t\t\"sourceIp\": \"%s\",\n", + inet_ntoa(*(struct in_addr*)&ip->ip_src) + ); + printf ("\t\t\"destinationIp\": \"%s\",\n", + inet_ntoa(*(struct in_addr*)&ip->ip_dst) + ); + puts ("\t\t\"IpOptions\": {"); + puts ("\t\t}"); + puts ("\t},"); +} + +int +verify_pgm_header ( + struct pgm_header* pgm, + guint pgm_len + ) +{ + +/* PGM payload, header looks as follows: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source Port | Destination Port | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Options | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Global Source ID ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ... Global Source ID | TSDU Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type specific data ... + * +-+-+-+-+-+-+-+-+-+- ... + */ + if (pgm_len < sizeof(pgm)) { + printf ("\t\"message\": \"PGM: packet size less than PGM header: %i bytes.\",\n", pgm_len); + return -1; + } + + if (pgm->pgm_checksum) + { + int sum = pgm->pgm_checksum; + pgm->pgm_checksum = 0; + int pgm_sum = pgm_csum_fold (pgm_csum_partial ((const char*)pgm, pgm_len, 0)); + pgm->pgm_checksum = sum; + if (pgm_sum != sum) { + printf ("\t\"message\": \"PGM: PGM packet checksum incorrect, packet 0x%x calculated 0x%x.\",\n", sum, pgm_sum); + return -2; + } + } else { + if (pgm->pgm_type != PGM_ODATA && pgm->pgm_type != PGM_RDATA) { + printf ("\t\"message\": \"PGM: No PGM checksum value, mandatory for ODATA/RDATA.\",\n"); + return -1; + } + } + + if ( pgm->pgm_type != PGM_SPM && + pgm->pgm_type != PGM_POLL && + pgm->pgm_type != PGM_POLR && + pgm->pgm_type != PGM_ODATA && + pgm->pgm_type != PGM_RDATA && + pgm->pgm_type != PGM_NAK && + pgm->pgm_type != PGM_NNAK && + pgm->pgm_type != PGM_NCF && + pgm->pgm_type != PGM_SPMR ) + { + printf ("\t\"message\": \"PGM: Not a valid PGM packet type: %i.\",\n", pgm->pgm_type); + return -1; + } + + return 0; +} + +/* note: output trails tsdu length line to allow for comma + */ + +void +print_pgm_header ( + struct pgm_header* pgm + ) +{ + puts ("\t\"PGM\": {"); + printf ("\t\t\"sourcePort\": %i,\n", g_ntohs(pgm->pgm_sport)); + printf ("\t\t\"destinationPort\": %i,\n", g_ntohs(pgm->pgm_dport)); + printf ("\t\t\"type\": \"%s\",\n", pgm_type_string(pgm->pgm_type & 0xf)); + printf ("\t\t\"version\": %i,\n", (pgm->pgm_type & 0xc0) >> 6); + puts ("\t\t\"options\": {"); + printf ("\t\t\t\"networkSignificant\": %s,\n", (pgm->pgm_options & PGM_OPT_NETWORK) ? "true" : "false"); + printf ("\t\t\t\"parityPacket\": %s,\n", (pgm->pgm_options & PGM_OPT_PARITY) ? "true" : "false"); + printf ("\t\t\t\"variableLength\": %s\n", (pgm->pgm_options & PGM_OPT_VAR_PKTLEN) ? "true" : "false"); + puts ("\t\t},"); + printf ("\t\t\"checksum\": %i,\n", pgm->pgm_checksum); + printf ("\t\t\"gsi\": \"%i.%i.%i.%i.%i.%i\",\n", + pgm->pgm_gsi[0], + pgm->pgm_gsi[1], + pgm->pgm_gsi[2], + pgm->pgm_gsi[3], + pgm->pgm_gsi[4], + pgm->pgm_gsi[5]); + printf ("\t\t\"tsduLength\": %i", g_ntohs(pgm->pgm_tsdu_length)); +} + +/* 8.1. Source Path Messages (SPM) + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | SPM's Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Trailing Edge Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Leading Edge Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Path NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * NLA = Network Layer Address + * NLA AFI = NLA Address Family Indicator: rfc 1700 (ADDRESS FAMILY NUMBERS) + * => Path NLA = IP address of last network element + */ + +int +verify_spm ( + struct pgm_header* header, + char* data, + guint len + ) +{ + int retval = 0; + +/* truncated packet */ + if (len < sizeof(struct pgm_spm)) { + printf ("\t\"message\": \"SPM: packet length: %i less than minimum SPM length: %" G_GSIZE_FORMAT "lu bytes.\",\n", len, sizeof(struct pgm_spm)); + retval = -1; + goto out; + } + + struct pgm_spm* spm = (struct pgm_spm*)data; + char* opt_offset = (char*)(spm + 1); + guint opt_len = len - sizeof(spm); + + switch (g_ntohs(spm->spm_nla_afi)) { + case AFI_IP6: + if (len < sizeof(struct pgm_spm6)) { + printf ("\t\"message\": \"SPM: packet length: %i less than minimum IPv6 SPM length: %" G_GSIZE_FORMAT "lu bytes.\",\n", len, sizeof(struct pgm_spm6)); + retval = -1; + goto out; + } + opt_offset += sizeof(struct pgm_spm6) - sizeof(struct pgm_spm); + opt_len -= sizeof(struct pgm_spm6) - sizeof(struct pgm_spm); + + case AFI_IP: + break; + + default: + printf ("\t\"message\": \"SPM: invalid AFI of source NLA: %i.\",\n", g_ntohs(spm->spm_nla_afi)); + retval = -1; + goto out; + } + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT) + { + retval = verify_options (opt_offset, opt_len); + } + +out: + return retval; +} + +void +print_spm ( + struct pgm_header* header, + char* data + ) +{ + struct pgm_spm* spm = (struct pgm_spm*)data; + struct pgm_spm6* spm6 = (struct pgm_spm6*)data; + char* opt_offset = (char*)(spm + 1); + + puts (","); + printf ("\t\t\"spmSqn\": %i,\n", g_ntohl(spm->spm_sqn)); + printf ("\t\t\"spmTrail\": %i,\n", g_ntohl(spm->spm_trail)); + printf ("\t\t\"spmLead\": %i,\n", g_ntohl(spm->spm_lead)); + printf ("\t\t\"spmNlaAfi\": %i,\n", g_ntohs (spm->spm_nla_afi)); + + char s[INET6_ADDRSTRLEN]; + switch (g_ntohs(spm->spm_nla_afi)) { + case AFI_IP: + inet_ntop ( AF_INET, &spm->spm_nla, s, sizeof (s) ); + break; + + case AFI_IP6: + inet_ntop ( AF_INET6, &spm6->spm6_nla, s, sizeof (s) ); + opt_offset += sizeof(struct pgm_spm6) - sizeof(struct pgm_spm); + break; + } + + printf ("\t\t\"spmNla\": \"%s\"", s); + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT) + { + puts (","); + print_options (opt_offset); + } + + puts ("\n\t}"); +} + +/* 14.7.1. Poll Request + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLL's Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLL's Round | POLL's Sub-type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Path NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | POLL's Back-off Interval | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Random String | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Matching Bit-Mask | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Sent to ODATA multicast group with IP Router Alert option. + */ + +#define PGM_MIN_POLL_SIZE ( sizeof(struct pgm_poll) ) + +int +verify_poll ( + G_GNUC_UNUSED struct pgm_header* header, + G_GNUC_UNUSED char* data, + G_GNUC_UNUSED guint len + ) +{ + return -1; +} + +void +print_poll ( + G_GNUC_UNUSED struct pgm_header* header, + G_GNUC_UNUSED char* data + ) +{ +} + +/* 14.7.2. Poll Response + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLR's Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | POLR's Round | reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +int +verify_polr ( + G_GNUC_UNUSED struct pgm_header* header, + G_GNUC_UNUSED char* data, + G_GNUC_UNUSED guint len + ) +{ + return -1; +} + +void +print_polr ( + G_GNUC_UNUSED struct pgm_header* header, + G_GNUC_UNUSED char* data + ) +{ +} + +/* 8.2. Data Packet + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Data Packet Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Trailing Edge Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Data ... + * +-+-+- ... + */ + +int +verify_odata ( + struct pgm_header* header, + char* data, + guint len + ) +{ + int retval = 0; + + if (len < sizeof(struct pgm_data)) { + printf ("\t\"message\": \"ODATA: packet length: %i less than minimum ODATA length: %" G_GSIZE_FORMAT " bytes.\",\n", len, sizeof(struct pgm_data)); + retval = -1; + goto out; + } + + char* tsdu = data + sizeof(struct pgm_data); + guint tsdu_len = len - sizeof(struct pgm_data); + if (header->pgm_options & PGM_OPT_PRESENT) + { + retval = verify_options (tsdu, tsdu_len); + + guint opt_total_len = g_ntohs( OPTIONS_TOTAL_LEN(tsdu) ); + tsdu += opt_total_len; + tsdu_len -= opt_total_len; + } + + if (!retval && g_ntohs(header->pgm_tsdu_length) != tsdu_len) { + printf ("\t\"message\": \"ODATA: TSDU truncated expected %i, found %i bytes.\",\n", g_ntohs(header->pgm_tsdu_length), tsdu_len); + retval = -1; + } +out: + return retval; +} + +void +print_odata ( + struct pgm_header* header, + char* data + ) +{ + struct pgm_data* odata = (struct pgm_data*)data; + char* tsdu = data + sizeof(struct pgm_data); + + puts (","); + printf ("\t\t\"odSqn\": %lu,\n", (gulong)g_ntohl(odata->data_sqn)); + printf ("\t\t\"odTrail\": %lu,\n", (gulong)g_ntohl(odata->data_trail)); + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT) + { + print_options (tsdu); + tsdu += g_ntohs( OPTIONS_TOTAL_LEN(tsdu) ); + puts (","); + } + +/* data */ + printf ("\t\t\"data\": \""); + char* end = tsdu + g_ntohs (header->pgm_tsdu_length); + while (tsdu < end) { + if (isprint(*tsdu)) + putchar(*tsdu); + else + putchar('.'); + tsdu++; + } + + puts ("\""); + puts ("\t}"); +} + +/* 8.2. Repair Data + */ + +int +verify_rdata ( + struct pgm_header* header, + char* data, + guint len + ) +{ + int retval = 0; + + if (len < sizeof(struct pgm_data)) { + printf ("\t\"message\": \"RDATA: packet length: %i less than minimum RDATA length: %" G_GSIZE_FORMAT " bytes.\",\n", len, sizeof(struct pgm_data)); + retval = -1; + goto out; + } + + char* tsdu = data + sizeof(struct pgm_data); + guint tsdu_len = len - sizeof(struct pgm_data); + if (header->pgm_options & PGM_OPT_PRESENT) + { + retval = verify_options (tsdu, tsdu_len); + + guint opt_total_len = g_ntohs( OPTIONS_TOTAL_LEN(tsdu) ); + tsdu += opt_total_len; + tsdu_len -= opt_total_len; + } + + if (!retval && g_ntohs(header->pgm_tsdu_length) != tsdu_len) { + printf ("\t\"message\": \"RDATA: tsdu truncated expected %i, found %i bytes.\",\n", g_ntohs(header->pgm_tsdu_length), tsdu_len); + retval = -1; + } +out: + return retval; +} + +void +print_rdata ( + struct pgm_header* header, + char* data + ) +{ + struct pgm_data* rdata = (struct pgm_data*)data; + char* tsdu = data + sizeof(struct pgm_data); + + puts (","); + printf ("\t\t\"rdSqn\": %lu,\n", (gulong)g_ntohl(rdata->data_sqn)); + printf ("\t\t\"rdTrail\": %lu,\n", (gulong)g_ntohl(rdata->data_trail)); + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT) + { + print_options (tsdu); + tsdu += g_ntohs( OPTIONS_TOTAL_LEN(tsdu) ); + puts (","); + } + +/* data */ + printf ("\t\t\"data\": \""); + char* end = tsdu + g_ntohs (header->pgm_tsdu_length); + while (tsdu < end) { + if (isprint(*tsdu)) + putchar(*tsdu); + else + putchar('.'); + tsdu++; + } + + puts ("\""); + puts ("\t}"); +} + +/* 8.3. NAK + * + * Technically the AFI of the source and multicast group can be different + * but that would be very wibbly wobbly. One example is using a local DLR + * with a IPv4 address to reduce NAK cost for recovery on wide IPv6 + * distribution. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Requested Sequence Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | NLA AFI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Multicast Group NLA ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+ + * | Option Extensions when present ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... + */ + +int +verify_nak ( + struct pgm_header* header, + char* data, + guint len + ) +{ + return generic_verify_nak ("NAK", header, data, len); +} + +int +verify_ncf ( + struct pgm_header* header, + char* data, + guint len + ) +{ + return generic_verify_nak ("NCF", header, data, len); +} + +int +verify_nnak ( + struct pgm_header* header, + char* data, + guint len + ) +{ + return generic_verify_nak ("NNAK", header, data, len); +} + +static int +generic_verify_nak ( + const char* name, /* upper case */ + G_GNUC_UNUSED struct pgm_header* header, + char* data, + guint len + ) +{ + int retval = 0; + +/* truncated packet */ + if (len < sizeof(struct pgm_nak)) { + printf ("\t\"message\": \"%s: packet length: %i less than minimum %s length: %" G_GSIZE_FORMAT " bytes.\",\n", + name, len, name, sizeof(struct pgm_nak)); + retval = -1; + goto out; + } + + struct pgm_nak* nak = (struct pgm_nak*)data; + int nak_src_nla_afi = g_ntohs (nak->nak_src_nla_afi); + int nak_grp_nla_afi = -1; + +/* check source NLA: unicast address of the ODATA sender */ + switch (nak_src_nla_afi) { + case AFI_IP: + nak_grp_nla_afi = g_ntohs (nak->nak_grp_nla_afi); + break; + + case AFI_IP6: + nak_grp_nla_afi = g_ntohs (((struct pgm_nak6*)nak)->nak6_grp_nla_afi); + break; + + default: + printf ("\t\"message\": \"%s: invalid AFI of source NLA: %i.\",\n", + name, nak_src_nla_afi); + retval = -1; + goto out; + } + +/* check multicast group NLA */ + switch (nak_grp_nla_afi) { + case AFI_IP6: + switch (nak_src_nla_afi) { +/* IPv4 + IPv6 NLA */ + case AFI_IP: + if (len < ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) )) { + printf ("\t\"message\": \"%s: packet length: %i less than joint IPv4/6 %s length: %" G_GSIZE_FORMAT " bytes.\",\n", + name, len, name, ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) )); + retval = -1; + } + break; + +/* IPv6 + IPv6 NLA */ + case AFI_IP6: + if (len < sizeof(struct pgm_nak6)) { + printf ("\t\"message\": \"%s: packet length: %i less than IPv6 %s length: %" G_GSIZE_FORMAT " bytes.\",\n", + name, len, name, sizeof(struct pgm_nak6)); + retval = -1; + } + break; + } + break; + + case AFI_IP: + if (nak_src_nla_afi == AFI_IP6) { + if (len < ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) )) { + printf ("\t\"message\": \"%s: packet length: %i less than joint IPv6/4 %s length: %" G_GSIZE_FORMAT " bytes.\",\n", + name, len, name, ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) )); + retval = -1; + } + } + break; + + default: + printf ("\t\"message\": \"%s: invalid AFI of group NLA: %i.\",\n", + name, nak_grp_nla_afi); + retval = -1; + break; + } + +out: + return retval; +} + +void +print_nak ( + struct pgm_header* header, + char* data + ) +{ + generic_print_nak ("nak", header, data); +} + +void +print_ncf ( + struct pgm_header* header, + char* data + ) +{ + generic_print_nak ("ncf", header, data); +} + +void +print_nnak ( + struct pgm_header* header, + char* data + ) +{ + generic_print_nak ("nnak", header, data); +} + +static void +generic_print_nak ( + const char* name, /* lower case */ + struct pgm_header* header, + char* data + ) +{ + struct pgm_nak* nak = (struct pgm_nak*)data; + struct pgm_nak6* nak6 = (struct pgm_nak6*)data; + char* opt_offset = (char*)(nak + 1); + + puts (","); + printf ("\t\t\"%sSqn\": %lu,\n", name, (gulong)g_ntohl(nak->nak_sqn)); + + guint16 nak_src_nla_afi = g_ntohs (nak->nak_src_nla_afi); + guint16 nak_grp_nla_afi = 0; + char s[INET6_ADDRSTRLEN]; + + printf ("\t\t\"%sSourceNlaAfi\": %i,\n", name, nak_src_nla_afi); + +/* source nla */ + switch (nak_src_nla_afi) { + case AFI_IP: + inet_ntop ( AF_INET, &nak->nak_src_nla, s, sizeof(s) ); + nak_grp_nla_afi = g_ntohs (nak->nak_grp_nla_afi); + break; + + case AFI_IP6: + inet_ntop ( AF_INET6, &nak6->nak6_src_nla, s, sizeof(s) ); + nak_grp_nla_afi = g_ntohs (nak6->nak6_grp_nla_afi); + opt_offset += sizeof(struct in6_addr) - sizeof(struct in_addr); + break; + } + + printf ("\t\t\"%sSourceNla\": \"%s\",\n", name, s); + printf ("\t\t\"%sGroupNlaAfi\": %i,\n", name, nak_grp_nla_afi); + + switch (nak_grp_nla_afi) { + case AFI_IP6: + switch (nak_src_nla_afi) { +/* IPv4 + IPv6 NLA */ + case AFI_IP: + inet_ntop ( AF_INET6, &nak->nak_grp_nla, s, sizeof(s) ); + break; + +/* IPv6 + IPv6 NLA */ + case AFI_IP6: + inet_ntop ( AF_INET6, &nak6->nak6_grp_nla, s, sizeof(s) ); + break; + } + opt_offset += sizeof(struct in6_addr) - sizeof(struct in_addr); + break; + + case AFI_IP: + switch (nak_src_nla_afi) { +/* IPv4 + IPv4 NLA */ + case AFI_IP: + inet_ntop ( AF_INET, &nak->nak_grp_nla, s, sizeof(s) ); + break; + +/* IPv6 + IPv4 NLA */ + case AFI_IP6: + inet_ntop ( AF_INET, &nak6->nak6_grp_nla, s, sizeof(s) ); + break; + } + break; + } + + printf ("\t\t\"%sGroupNla\": \"%s\"", name, s); + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT) + { + puts (","); + print_options (opt_offset); + } + + puts ("\n\t}"); +} + + +/* 13.6. SPM Request + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Extensions when present ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... + */ + +int +verify_spmr ( + struct pgm_header* header, + char* data, + guint len + ) +{ + int retval = 0; + + char* opt_offset = data; + guint opt_len = len; + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT) + { + retval = verify_options (opt_offset, opt_len); + } + + return retval; +} + +void +print_spmr ( + struct pgm_header* header, + char* data + ) +{ + char* opt_offset = data; + +/* option extensions */ + if (header->pgm_options & PGM_OPT_PRESENT) + { + print_options (opt_offset); + puts (""); + } + + puts ("\t}"); +} + +/* Parse PGM options fields: + * + * assume at least two options, one the mandatory OPT_LENGTH + */ + +#define PGM_MIN_OPT_SIZE ( sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_length) ) + +int +verify_options ( + char* data, + guint len + ) +{ + int retval = 0; + + if (len < PGM_MIN_OPT_SIZE) { + printf ("\t\"message\": \"PGM options: packet size too small for options.\",\n"); + retval = -1; + goto out; + } + +/* OPT_LENGTH first */ + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)data; + if ((opt_len->opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) { + printf ("\t\"message\": \"PGM options: first option not OPT_LENGTH.\",\n"); + retval = -1; + goto out; + } + + if (opt_len->opt_length != sizeof(struct pgm_opt_length)) { + printf ("\t\"message\": \"PGM options: OPT_LENGTH incorrect option length: %i, expecting %" G_GSIZE_FORMAT " bytes.\",\n", opt_len->opt_length, sizeof(struct pgm_opt_length)); + retval = -1; + goto out; + } + + if (g_ntohs(opt_len->opt_total_length) < PGM_MIN_OPT_SIZE) { + printf ("\t\"message\": \"PGM options: OPT_LENGTH total length too short: %i bytes.\",\n", g_ntohs(opt_len->opt_total_length)); + retval = -1; + goto out; + } + + if (g_ntohs(opt_len->opt_total_length) > len) { + printf ("\t\"message\": \"PGM options: OPT_LENGTH total length longer than packet allows: %i bytes.\",\n", g_ntohs(opt_len->opt_total_length)); + retval = -1; + goto out; + } + +/* iterate through options (max 16) */ + guint count = 0; + guint total_length = g_ntohs(opt_len->opt_total_length); + + guint opt_counters[256]; + memset (&opt_counters, 0, sizeof(opt_counters)); + + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)data; + for (;;) { + total_length -= opt_header->opt_length; + if (total_length < sizeof(struct pgm_opt_header)) { + printf ("\t\"message\": \"PGM options: option #%i shorter than minimum option size.\",\n", count + 1); + retval = -1; + goto out; + } + opt_header = (struct pgm_opt_header*)( ((char*)opt_header) + opt_header->opt_length ); + if (((int)total_length - (int)opt_header->opt_length) < 0) { + printf ("\t\"message\": \"PGM options: option #%i shorter than embedded size.\",\n", count + 1); + retval = -1; + goto out; + } + + if (opt_counters[opt_header->opt_type]++) { + printf ("\t\"message\": \"PGM options: duplicate option %i.\",\n", opt_header->opt_type); + retval = -1; + goto out; + } + +/* check option types */ + switch (opt_header->opt_type & PGM_OPT_MASK) { + case PGM_OPT_FRAGMENT: + { + if (opt_header->opt_length != sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fragment)) { + printf ("\t\"message\": \"PGM options: OPT_FRAGMENT incorrect size: %i bytes.\",\n", opt_header->opt_length); + retval = -1; + goto out; + } + + struct pgm_opt_fragment* opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + if (g_ntohl(opt_fragment->opt_frag_off) > g_ntohl(opt_fragment->opt_frag_len)) { + printf ("\t\"message\": \"PGM options: fragment offset longer than original packet.\",\n"); + retval = -1; + goto out; + } + break; + } + + case PGM_OPT_NAK_LIST: + { + guint list_len = opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(guint8); + if (list_len & 1) { + printf ("\t\"message\": \"PGM options: OPT_NAK_LIST invalid odd length: %i bytes.\",\n", opt_header->opt_length); + retval = -1; + goto out; + } + + list_len /= 2; + if (list_len == 0) { + printf ("\t\"message\": \"PGM options: OPT_NAK_LIST empty.\",\n"); + retval = -1; + goto out; + } + + if (list_len > 62) { + printf ("\t\"message\": \"PGM options: OPT_NAK_LIST too long: %i sqns.\",\n", list_len); + retval = -1; + goto out; + } + break; + } + + case PGM_OPT_PARITY_PRM: + { + struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1); + if ((opt_parity_prm->opt_reserved & PGM_PARITY_PRM_MASK) == 0) { + printf ("\t\"message\": \"PGM options: neither pro-active or on-demand parity set in OPT_PARITY_PRM.\",\n"); + retval = -1; + goto out; + } + guint32 parity_prm_tgs = g_ntohl (opt_parity_prm->parity_prm_tgs); + if (parity_prm_tgs < 2 || parity_prm_tgs > 128) { + printf ("\t\"message\": \"PGM options: transmission group size out of bounds: %i.\",\n", parity_prm_tgs); + retval = -1; + goto out; + } + break; + } + + default: +/* unknown option, skip */ + break; + } +/* end option types */ + + if (opt_header->opt_type & PGM_OPT_END) { + break; + } + + if (count++ == 16) { + printf ("\t\"message\": \"PGM options: more than 16 options found.\",\n"); + retval = -1; + goto out; + } + } + +out: + return retval; +} + +static const char *opx_text[4] = { + "OPX_IGNORE", + "OPX_INVALIDATE", + "OPX_DISCARD", + "OPX_UNKNOWN" +}; + +void +print_options ( + char* data + ) +{ + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)data; + + puts ("\t\t\"pgmOptions\": ["); + puts ("\t\t\t{"); + printf ("\t\t\t\t\"length\": 0x%x,\n", opt_len->opt_length); + puts ("\t\t\t\t\"type\": \"OPT_LENGTH\","); + printf ("\t\t\t\t\"totalLength\": %i\n", g_ntohs (opt_len->opt_total_length)); + printf ("\t\t\t}"); + +/* iterate through options */ + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)data; + do { + opt_header = (struct pgm_opt_header*)( ((char*)opt_header) + opt_header->opt_length ); + + puts (","); + puts ("\t\t\t{"); + printf ("\t\t\t\t\"length\": 0x%x,\n", opt_header->opt_length); + + switch (opt_header->opt_type & PGM_OPT_MASK) { + case PGM_OPT_FRAGMENT: + { + struct pgm_opt_fragment* opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + printf ("\t\t\t\t\"type\": \"OPT_FRAGMENT%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); + printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); + printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); + printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_fragment->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); + printf ("\t\t\t\t\"firstSqn\": %i,\n", g_ntohl(opt_fragment->opt_sqn)); + printf ("\t\t\t\t\"fragmentOffset\": %i,\n", g_ntohl(opt_fragment->opt_frag_off)); + printf ("\t\t\t\t\"originalLength\": %i\n", g_ntohl(opt_fragment->opt_frag_len)); + break; + } + + case PGM_OPT_NAK_LIST: + { + struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); + char* end = (char*)opt_header + opt_header->opt_length; + printf ("\t\t\t\t\"type\": \"OPT_NAK_LIST%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); + printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); + printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); + printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_nak_list->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); + char sqns[1024] = ""; + guint i = 0; + do { + char sqn[1024]; + sprintf (sqn, "%s%i", (i>0)?", ":"", g_ntohl(opt_nak_list->opt_sqn[i])); + strcat (sqns, sqn); + i++; + } while ((char*)&opt_nak_list->opt_sqn[i] < end); + printf ("\t\t\t\t\"sqn\": [%s]\n", sqns); + break; + } + + case PGM_OPT_PARITY_PRM: + { + struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1); + printf ("\t\t\t\t\"type\": \"OPT_PARITY_PRM%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); + printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); + printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); + printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_parity_prm->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); + printf ("\t\t\t\t\"P-bit\": %s,\n", (opt_parity_prm->opt_reserved & PGM_PARITY_PRM_PRO) ? "true" : "false"); + printf ("\t\t\t\t\"O-bit\": %s,\n", (opt_parity_prm->opt_reserved & PGM_PARITY_PRM_OND) ? "true" : "false"); + printf ("\t\t\t\t\"transmissionGroupSize\": %i\n", g_ntohl(opt_parity_prm->parity_prm_tgs)); + break; + } + + case PGM_OPT_CURR_TGSIZE: + { + struct pgm_opt_curr_tgsize* opt_curr_tgsize = (struct pgm_opt_curr_tgsize*)(opt_header + 1); + printf ("\t\t\t\t\"type\": \"OPT_CURR_TGSIZE%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); + printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); + printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); + printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_curr_tgsize->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); + printf ("\t\t\t\t\"actualTransmissionGroupSize\": %i\n", g_ntohl(opt_curr_tgsize->prm_atgsize)); + break; + } + + case PGM_OPT_SYN: + { + struct pgm_opt_syn* opt_syn = (struct pgm_opt_syn*)(opt_header + 1); + printf ("\t\t\t\t\"type\": \"OPT_SYN%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); + printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); + printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); + printf ("\t\t\t\t\"U-bit\": %s\n", (opt_syn->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); + break; + } + + case PGM_OPT_FIN: + { + struct pgm_opt_fin* opt_fin = (struct pgm_opt_fin*)(opt_header + 1); + printf ("\t\t\t\t\"type\": \"OPT_FIN%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); + printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); + printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); + printf ("\t\t\t\t\"U-bit\": %s\n", (opt_fin->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); + break; + } + + default: + { + guint8 opt_reserved = *(guint8*)(opt_header + 1); + printf ("\t\t\t\t\"type\": \"0x%x%s\",\n", opt_header->opt_type & PGM_OPT_MASK, (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : ""); + printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false"); + printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]); + printf ("\t\t\t\t\"U-bit\": %s\n", (opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false"); + break; + } + } + printf ("\t\t\t}"); + + } while (!(opt_header->opt_type & PGM_OPT_END)); + + printf ("\n\t\t]"); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/dump-json.h b/3rdparty/openpgm-svn-r1135/pgm/test/dump-json.h new file mode 100644 index 0000000..6fa0f9d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/dump-json.h @@ -0,0 +1,33 @@ +/* vim:ts=8:sts=4:sw=4:noai:noexpandtab + * + * JSON packet dump. + * + * Copyright (c) 2006-2007 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PGM_DUMP_JSON_H__ +#define __PGM_DUMP_JSON_H__ + + +G_BEGIN_DECLS + +int monitor_packet (char*, guint); + + +G_END_DECLS + +#endif /* __PGM_DUMP_JSON_H__ */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/heartbeat_spm.pl b/3rdparty/openpgm-svn-r1135/pgm/test/heartbeat_spm.pl new file mode 100755 index 0000000..beb912e --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/heartbeat_spm.pl @@ -0,0 +1,58 @@ +#!/usr/bin/perl +# heartbeat_spm.pl +# 5.1.5. Heartbeat SPMs + +use strict; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$app->connect; + +sub close_ssh { + $mon = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +print "app: publish test data.\n"; +$app->say ("send ao ringo"); + +print "mon: wait for odata ...\n"; +$mon->wait_for_odata; +my $t0 = [gettimeofday]; + +for (1..4) # look for four consecutive heartbeat SPMs less than 5000ms apart +{ + print "mon: wait for spm ...\n"; + $mon->wait_for_spm ({ 'timeout' => 5 }); + my $tn = [gettimeofday]; + my $elapsed = tv_interval ( $t0, $tn ); + $t0 = $tn; + + print "mon: spm received after $elapsed seconds.\n"; +} + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/monitor.c b/3rdparty/openpgm-svn-r1135/pgm/test/monitor.c new file mode 100644 index 0000000..6569a55 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/monitor.c @@ -0,0 +1,349 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM link monitor. + * + * Copyright (c) 2006-2007 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "dump-json.h" + + +/* globals */ + +static const char* g_network = "239.192.0.1"; +static struct in_addr g_filter /* = { 0 } */; + +static GIOChannel* g_io_channel = NULL; +static GIOChannel* g_stdin_channel = NULL; +static GMainLoop* g_loop = NULL; + + +static void on_signal (int, gpointer); +static gboolean on_startup (gpointer); +static gboolean on_mark (gpointer); + +static gboolean on_io_data (GIOChannel*, GIOCondition, gpointer); +static gboolean on_io_error (GIOChannel*, GIOCondition, gpointer); + +static gboolean on_stdin_data (GIOChannel*, GIOCondition, gpointer); + +int +main ( + G_GNUC_UNUSED int argc, + G_GNUC_UNUSED char *argv[] + ) +{ +/* pre-initialise PGM messages module to add hook for GLib logging */ + pgm_messages_init(); + log_init (); + puts ("monitor"); + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); + signal (SIGHUP, SIG_IGN); + pgm_signal_install (SIGINT, on_signal, g_loop); + pgm_signal_install (SIGTERM, on_signal, g_loop); + + g_filter.s_addr = 0; + +/* delayed startup */ + puts ("scheduling startup."); + g_timeout_add(0, (GSourceFunc)on_startup, NULL); + +/* dispatch loop */ + g_loop = g_main_loop_new(NULL, FALSE); + + puts ("entering main event loop ... "); + g_main_loop_run(g_loop); + + puts ("event loop terminated, cleaning up."); + +/* cleanup */ + g_main_loop_unref(g_loop); + g_loop = NULL; + + if (g_io_channel) { + puts ("closing socket."); + + GError *err = NULL; + g_io_channel_shutdown (g_io_channel, FALSE, &err); + g_io_channel = NULL; + } + + if (g_stdin_channel) { + puts ("unbinding stdin."); + g_io_channel_unref (g_stdin_channel); + g_stdin_channel = NULL; + } + + puts ("finished."); + pgm_messages_shutdown(); + return 0; +} + +static void +on_signal ( + int signum, + gpointer user_data + ) +{ + GMainLoop* loop = (GMainLoop*)user_data; + g_message ("on_signal (signum:%d user-data:%p)", signum, user_data); + g_main_loop_quit (loop); +} + +static gboolean +on_startup ( + G_GNUC_UNUSED gpointer data + ) +{ + int e; + + puts ("startup."); + +/* find PGM protocol id */ +// TODO: fix valgrind errors + int ipproto_pgm = IPPROTO_PGM; +#if HAVE_GETPROTOBYNAME_R + char b[1024]; + struct protoent protobuf, *proto; + e = getprotobyname_r("pgm", &protobuf, b, sizeof(b), &proto); + if (e != -1 && proto != NULL) { + if (proto->p_proto != ipproto_pgm) { + printf("Setting PGM protocol number to %i from /etc/protocols.\n"); + ipproto_pgm = proto->p_proto; + } + } +#else + struct protoent *proto = getprotobyname("pgm"); + if (proto != NULL) { + if (proto->p_proto != ipproto_pgm) { + printf("Setting PGM protocol number to %i from /etc/protocols.\n", proto +->p_proto); + ipproto_pgm = proto->p_proto; + } + } +#endif + +/* open socket for snooping */ + puts ("opening raw socket."); + int sock = socket(PF_INET, SOCK_RAW, ipproto_pgm); + if (sock < 0) { + int _e = errno; + perror("on_startup() failed"); + + if (_e == EPERM && 0 != getuid()) { + puts ("PGM protocol requires this program to run as superuser."); + } + g_main_loop_quit(g_loop); + return FALSE; + } + +/* drop out of setuid 0 */ + if (0 == getuid()) { + puts ("dropping superuser privileges."); + setuid((gid_t)65534); + setgid((uid_t)65534); + } + + char _t = 1; + e = setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &_t, sizeof(_t)); + if (e < 0) { + perror("on_startup() failed"); + close(sock); + g_main_loop_quit(g_loop); + return FALSE; + } + +/* buffers */ + int buffer_size = 0; + socklen_t len = 0; + e = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buffer_size, &len); + if (e == 0) { + printf ("receive buffer set at %i bytes.\n", buffer_size); + } + e = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buffer_size, &len); + if (e == 0) { + printf ("send buffer set at %i bytes.\n", buffer_size); + } + +/* bind */ + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + e = bind(sock, (struct sockaddr*)&addr, sizeof(addr)); + if (e < 0) { + perror("on_startup() failed"); + close(sock); + g_main_loop_quit(g_loop); + return FALSE; + } + +/* multicast */ + struct ip_mreq mreq; + memset(&mreq, 0, sizeof(mreq)); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + printf ("listening on interface %s.\n", inet_ntoa(mreq.imr_interface)); + mreq.imr_multiaddr.s_addr = inet_addr(g_network); + printf ("subscription on multicast address %s.\n", inet_ntoa(mreq.imr_multiaddr)); + e = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + if (e < 0) { + perror("on_startup() failed"); + close(sock); + g_main_loop_quit(g_loop); + return FALSE; + } + +/* multicast loopback */ +/* multicast ttl */ + +/* add socket to event manager */ + g_io_channel = g_io_channel_unix_new (sock); + printf ("socket opened with encoding %s.\n", g_io_channel_get_encoding(g_io_channel)); + + /* guint event = */ g_io_add_watch (g_io_channel, G_IO_IN | G_IO_PRI, on_io_data, NULL); + /* guint event = */ g_io_add_watch (g_io_channel, G_IO_ERR | G_IO_HUP | G_IO_NVAL, on_io_error, NULL); + +/* add stdin to event manager */ + g_stdin_channel = g_io_channel_unix_new (fileno(stdin)); + printf ("binding stdin with encoding %s.\n", g_io_channel_get_encoding(g_stdin_channel)); + + g_io_add_watch (g_stdin_channel, G_IO_IN | G_IO_PRI, on_stdin_data, NULL); + +/* period timer to indicate some form of life */ +// TODO: Gnome 2.14: replace with g_timeout_add_seconds() + g_timeout_add(10 * 1000, (GSourceFunc)on_mark, NULL); + + puts ("READY"); + fflush (stdout); + return FALSE; +} + +static gboolean +on_mark ( + G_GNUC_UNUSED gpointer data + ) +{ + g_message ("-- MARK --"); + return TRUE; +} + +static gboolean +on_io_data ( + GIOChannel* source, + G_GNUC_UNUSED GIOCondition condition, + G_GNUC_UNUSED gpointer data + ) +{ + char buffer[4096]; + int fd = g_io_channel_unix_get_fd(source); + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + int len = recvfrom(fd, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&addr, &addr_len); + + if (g_filter.s_addr && g_filter.s_addr != addr.sin_addr.s_addr) { + return TRUE; + } + + printf ("%i bytes received from %s.\n", len, inet_ntoa(addr.sin_addr)); + + monitor_packet (buffer, len); + fflush (stdout); + + return TRUE; +} + +static gboolean +on_io_error ( + GIOChannel* source, + G_GNUC_UNUSED GIOCondition condition, + G_GNUC_UNUSED gpointer data + ) +{ + puts ("on_error."); + + GError *err; + g_io_channel_shutdown (source, FALSE, &err); + +/* remove event */ + return FALSE; +} + +/* process input commands from stdin/fd + */ + +static gboolean +on_stdin_data ( + GIOChannel* source, + G_GNUC_UNUSED GIOCondition condition, + G_GNUC_UNUSED gpointer data + ) +{ + gchar* str = NULL; + gsize len = 0; + gsize term = 0; + GError* err = NULL; + + g_io_channel_read_line (source, &str, &len, &term, &err); + if (len > 0) { + if (term) str[term] = 0; + + if (strcmp(str, "quit") == 0) { + g_main_loop_quit(g_loop); + } else if (strncmp(str, "filter ", strlen("filter ")) == 0) { + unsigned a, b, c, d; + int retval = sscanf(str, "filter %u.%u.%u.%u", &a, &b, &c, &d); + if (retval == 4) { + g_filter.s_addr = (d << 24) | (c << 16) | (b << 8) | a; + puts ("READY"); + } else { + printf ("invalid syntax for filter command."); + } + } else { + printf ("unknown command: %s\n", str); + } + } + + fflush (stdout); + g_free (str); + return TRUE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/nak.pl b/3rdparty/openpgm-svn-r1135/pgm/test/nak.pl new file mode 100755 index 0000000..bde24c0 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/nak.pl @@ -0,0 +1,68 @@ +#!/usr/bin/perl +# nak.pl +# 5.3. Repairs + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$sim->say ("create ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); +print "sim: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); # to process NAK requests + +print "app: publish test data.\n"; +$app->say ("send ao ringo"); +$app->say ("send ao ichigo"); +$app->say ("send ao momo"); + +my $odata = undef; +my $ocnt = 0; +for (1..3) { + print "mon: wait for odata ...\n"; + $odata = $mon->wait_for_odata; + $ocnt++; + print "mon: received $ocnt x odata.\n"; +} + +print "sim: send nak to app.\n"; +$sim->say ("net send nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 2"); + +print "mon: wait for rdata ...\n"; +$mon->wait_for_rdata; +print "mon: rdata received.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/nak_cancellation.pl b/3rdparty/openpgm-svn-r1135/pgm/test/nak_cancellation.pl new file mode 100755 index 0000000..9db12e9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/nak_cancellation.pl @@ -0,0 +1,163 @@ +#!/usr/bin/perl +# nak_cancellation.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use IO::Handle; +use JSON; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +pipe(FROM_PARENT, TO_CHILD) or die "pipe: $!"; +FROM_PARENT->autoflush(1); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + close FROM_PARENT; close TO_CHILD; + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("set ao NAK_BO_IVL 5000"); # increase to count for test system latency +$app->say ("set ao NAK_RPT_IVL 10000"); +$app->say ("set ao NAK_RDATA_IVL 10000"); +$app->say ("set ao NAK_NCF_RETRIES 15"); +$app->say ("set ao NAK_DATA_RETRIES 10"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +## capture GSI of test spp +$app->say ("send ao nashi"); +print "mon: wait for odata ...\n"; +my $odata = $mon->wait_for_odata; +print "mon: odata received.\n"; + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; +$sim->say ("net send spm ao 3200 90001 90000"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90001 ringo"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,003.\n"; +$sim->say ("net send odata ao 90003 90001 ichigo"); +my $t0 = [gettimeofday]; + +if (my $pid = fork) { +# parent + close FROM_PARENT; + + sleep 10; + + print "app: wait for data ...\n"; + my $data = $app->wait_for_data({ 'timeout' => 0 }); + print "app: data received [$data].\n"; + + print TO_CHILD "die\n"; + + close TO_CHILD; + waitpid($pid,0); +} else { +# child + die "cannot fork: $!" unless defined $pid; + close TO_CHILD; + + print "sim: loop waiting for NAKs ...\n"; + + my $fh = $sim->{in}; + vec(my $rin, fileno(FROM_PARENT), 1) = 1; + vec($rin, fileno($fh), 1) = 1; + my $rout = undef; + + my $b = ''; + my $state = 0; + my $json = new JSON; + my $io = IO::Handle->new_from_fd( fileno($fh), "r" ); + my $cnt = 0; + while (select($rout = $rin, undef, undef, undef)) + { + last if( vec($rout, fileno(FROM_PARENT), 1) ); + while (defined($_ = $io->getline)) + { + chomp; + my $l = $_; + if ($state == 0) { + if ($l =~ /{$/) { + $state = 1; + } else { + print "sim [$l]\n"; + last; + } + } + + if ($state == 1) { + $b .= $l; + + if ($l =~ /^}$/) { + $state = 0; + + my $obj = $json->jsonToObj($b); + if ($obj->{PGM}->{type} =~ /NAK/) { + $cnt++; + my $elapsed = tv_interval ( $t0, [gettimeofday] ); + print "sim: $cnt x NAK received in $elapsed seconds.\n"; + $sim->say ("net send ncf ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 90002"); + } + +# reset + $b = ''; + last; + } + } + } + last if ($io->eof); + } + + print "sim: loop finished.\n"; + close FROM_PARENT; + exit; +} + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/nak_list.pl b/3rdparty/openpgm-svn-r1135/pgm/test/nak_list.pl new file mode 100755 index 0000000..015db45 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/nak_list.pl @@ -0,0 +1,72 @@ +#!/usr/bin/perl +# nak_list.pl +# 9.3. NAK List Option - OPT_NAK_LIST + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$sim->say ("create ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); +print "sim: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +print "app: publish test data.\n"; +$app->say ("send ao ringo"); +$app->say ("send ao ichigo"); +$app->say ("send ao momo"); + +my $odata = undef; +my $ocnt = 0; +for (1..3) { + print "mon: wait for odata ...\n"; + $odata = $mon->wait_for_odata; + $ocnt++; + print "mon: received $ocnt x odata.\n"; +} + +print "sim: send nak to app.\n"; +$sim->say ("net send nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 0,1,2"); + +my $rcnt = 0; +for (1..3) { + print "mon: wait for rdata ...\n"; + $mon->wait_for_rdata; + $rcnt++; + print "mon: received $rcnt x rdata.\n"; +} + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/nak_parity.pl b/3rdparty/openpgm-svn-r1135/pgm/test/nak_parity.pl new file mode 100755 index 0000000..50f961b --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/nak_parity.pl @@ -0,0 +1,75 @@ +#!/usr/bin/perl +# nak_parity.pl +# 5.3. Repairs + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$sim->say ("create ao"); +$sim->say ("set ao FEC RS(255,4)"); +$sim->say ("bind ao"); +print "sim: ready.\n"; + +$app->say ("create ao"); +$app->say ("set ao FEC RS(255,4)"); +$app->say ("bind ao"); +$app->say ("listen ao"); # to process NAK requests + +print "app: publish test data.\n"; +$app->say ("send ao ringo"); +$app->say ("send ao ichigo"); +$app->say ("send ao momo"); +$app->say ("send ao budo"); +$app->say ("send ao nashi"); +$app->say ("send ao anzu"); +$app->say ("send ao kaki"); + +my $odata = undef; +my $ocnt = 0; +for (1..7) { + print "mon: wait for odata ...\n"; + $odata = $mon->wait_for_odata; + $ocnt++; + print "mon: received $ocnt x odata.\n"; +} + +print "sim: send nak to app (transmission group = 0, packet count = 1).\n"; +$sim->say ("net send parity nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 1"); + +print "mon: wait for rdata ...\n"; +my $rdata = $mon->wait_for_rdata; +print "mon: rdata received.\n"; + +die "Selective RDATA received, parityPacket=false\n" unless $rdata->{PGM}->{options}->{parityPacket}; +print "Parity RDATA received.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/nak_repeat.pl b/3rdparty/openpgm-svn-r1135/pgm/test/nak_repeat.pl new file mode 100755 index 0000000..7f3d80e --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/nak_repeat.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl +# nak_repeat.pl +# 5.3. Repairs + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$sim->say ("create ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); +print "sim: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); # to process NAK requests + +print "app: publish test data.\n"; +$app->say ("send ao " . ("ringo" x 200)); +$app->say ("send ao " . ("ichigo" x 200)); +$app->say ("send ao " . ("momo" x 200)); + +my $odata = undef; +my $ocnt = 0; +for (1..3) { + print "mon: wait for odata ...\n"; + $odata = $mon->wait_for_odata; + $ocnt++; + print "mon: received $ocnt x odata.\n"; +} + +for (1..1000) { + my $i = $_; + print "sim: $i# send nak to app.\n"; + $sim->say ("net send nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 2"); + + print "mon: $i# wait for rdata ...\n"; + $mon->wait_for_rdata; + print "mon: $i# rdata received.\n"; +} + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/ncf.pl b/3rdparty/openpgm-svn-r1135/pgm/test/ncf.pl new file mode 100755 index 0000000..128db2a --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/ncf.pl @@ -0,0 +1,68 @@ +#!/usr/bin/perl +# ncf.pl +# 5.2. Negative Acknowledgment Confirmation + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$sim->say ("create ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); +print "sim: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +print "app: publish test data.\n"; +$app->say ("send ao ringo"); +$app->say ("send ao ichigo"); +$app->say ("send ao momo"); + +my $odata = undef; +my $ocnt = 0; +for (1..3) { + print "mon: wait for odata ...\n"; + $odata = $mon->wait_for_odata; + $ocnt++; + print "mon: received $ocnt x odata.\n"; +} + +print "sim: send nak to app.\n"; +$sim->say ("net send nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 2"); + +print "mon: wait for ncf ...\n"; +$mon->wait_for_ncf; +print "mon: ncf received.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/ncf_cancellation.pl b/3rdparty/openpgm-svn-r1135/pgm/test/ncf_cancellation.pl new file mode 100755 index 0000000..fcfbf2b --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/ncf_cancellation.pl @@ -0,0 +1,149 @@ +#!/usr/bin/perl +# ncf_cancellation.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use IO::Handle; +use JSON; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +pipe(FROM_PARENT, TO_CHILD) or die "pipe: $!"; +FROM_PARENT->autoflush(1); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + close FROM_PARENT; close TO_CHILD; + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +## capture GSI of test spp +$app->say ("send ao nashi"); +print "mon: wait for odata ...\n"; +my $odata = $mon->wait_for_odata; +print "mon: odata received.\n"; + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; +$sim->say ("net send spm ao 3200 90001 90000"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90001 ringo"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,003.\n"; +$sim->say ("net send odata ao 90003 90001 ichigo"); +my $t0 = [gettimeofday]; + +if (my $pid = fork) { +# parent + close FROM_PARENT; + + print "app: wait for data ...\n"; + my $data = $app->wait_for_data({ 'timeout' => 0 }); + print "app: data received [$data].\n"; + + print TO_CHILD "die\n"; + + close TO_CHILD; + waitpid($pid,0); +} else { +# child + die "cannot fork: $!" unless defined $pid; + close TO_CHILD; + print "sim: loop waiting for NAKs ...\n"; + + my $fh = $sim->{in}; + vec(my $rin, fileno(FROM_PARENT), 1) = 1; + vec($rin, fileno($fh), 1) = 1; + my $rout = undef; + + my $b = ''; + my $state = 0; + my $json = new JSON; + my $io = IO::Handle->new_from_fd( fileno($fh), "r" ); + my $cnt = 0; + while (select($rout = $rin, undef, undef, undef)) + { + last if( vec($rout, fileno(FROM_PARENT), 1) ); + last unless (defined($_ = $io->getline)); + chomp; + my $l = $_; + if ($state == 0) { + if ($l =~ /{$/) { + $state = 1; + } else { + print "sim [$l]\n"; + } + } + + if ($state == 1) { + $b .= $l; + + if ($l =~ /^}$/) { + $state = 0; + + my $obj = $json->jsonToObj($b); + if ($obj->{PGM}->{type} =~ /NAK/) { + $cnt++; + my $elapsed = tv_interval ( $t0, [gettimeofday] ); + print "sim: $cnt x NAK received in $elapsed seconds.\n"; + } + +# reset + $b = ''; + } + } + } + + print "sim: loop finished.\n"; + close FROM_PARENT; + exit; +} + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/ncf_list.pl b/3rdparty/openpgm-svn-r1135/pgm/test/ncf_list.pl new file mode 100755 index 0000000..d3082e4 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/ncf_list.pl @@ -0,0 +1,74 @@ +#!/usr/bin/perl +# ncf_list.pl +# 9.3. NAK List Option - OPT_NAK_LIST + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$sim->say ("create ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); +print "sim: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +print "app: publish test data.\n"; +$app->say ("send ao ringo"); +$app->say ("send ao ichigo"); +$app->say ("send ao momo"); + +my $odata = undef; +my $ocnt = 0; +for (1..3) { + print "mon: wait for odata ...\n"; + $odata = $mon->wait_for_odata; + $ocnt++; + print "mon: received $ocnt x odata.\n"; +} + +print "sim: send nak to app.\n"; +$sim->say ("net send nak ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 1,2,3"); + +print "mon: wait for ncf ...\n"; +my $ncf = $mon->wait_for_ncf; +print "mon: ncf received.\n"; +die "ncfSqn != 1\n" unless $ncf->{PGM}->{ncfSqn} == 1; +die "NCF list incorrect\n" unless ( + $ncf->{PGM}->{pgmOptions}[1]->{sqn}[0] == 2 + && $ncf->{PGM}->{pgmOptions}[1]->{sqn}[1] == 3 + ); +print "mon: ncf list correct: $ncf->{PGM}->{ncfSqn} + [$ncf->{PGM}->{pgmOptions}[1]->{sqn}[0], $ncf->{PGM}->{pgmOptions}[1]->{sqn}[1]]\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/ncf_suppression.pl b/3rdparty/openpgm-svn-r1135/pgm/test/ncf_suppression.pl new file mode 100755 index 0000000..fbb3de7 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/ncf_suppression.pl @@ -0,0 +1,103 @@ +#!/usr/bin/perl +# ncf_suppression.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +## capture GSI of test spp +$app->say ("send ao nashi"); +print "mon: wait for odata ...\n"; +my $odata = $mon->wait_for_odata; +print "mon: odata received.\n"; + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; +$sim->say ("net send spm ao 3200 90001 90000"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90001 ringo"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +## first run through with regular NAK generation to get regular backoff interval +print "sim: publish ODATA sqn 90,003.\n"; +$sim->say ("net send odata ao 90003 90001 ichigo"); +my $t0 = [gettimeofday]; +print "sim: waiting for valid NAK.\n"; +$sim->wait_for_nak; +my $normal_backoff = tv_interval ( $t0, [gettimeofday] ); +print "sim: NAK received in $normal_backoff seconds.\n"; + +## cleanup by publishing repair data +print "sim: publish RDATA sqn 90,002.\n"; +$sim->say ("net send odata ao 90002 90001 momo"); +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +## second run with NAK suppression +$t0 = [gettimeofday]; +print "sim: publish ODATA sqn 90,005.\n"; +$sim->say ("net send odata ao 90005 90001 anzu"); +print "sim: publish NCF sqn 90,004.\n"; +$sim->say ("net send ncf ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 90004"); + +print "sim: waiting for valid NAK.\n"; +$sim->wait_for_nak; +my $suppressed_backoff = tv_interval ( $t0, [gettimeofday] ); +print "sim: NAK received in $suppressed_backoff seconds.\n"; + +die "NAK suppression failed.\n" unless ($suppressed_backoff > $normal_backoff); + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/odata.pl b/3rdparty/openpgm-svn-r1135/pgm/test/odata.pl new file mode 100755 index 0000000..8dd3580 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/odata.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl +# odata.pl +# 3.6.2.1. ODATA - Original Data + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$app->connect; + +sub close_ssh { + $mon = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); + +print "app: publish test data.\n"; +$app->say ("send ao ringo"); + +print "mon: wait for odata ...\n"; +$mon->wait_for_odata; +print "mon: received odata.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/odata_completion.pl b/3rdparty/openpgm-svn-r1135/pgm/test/odata_completion.pl new file mode 100755 index 0000000..655aeff --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/odata_completion.pl @@ -0,0 +1,89 @@ +#!/usr/bin/perl +# odata_completion.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +## capture GSI of test spp +$app->say ("send ao nashi"); +print "mon: wait for odata ...\n"; +my $odata = $mon->wait_for_odata; +print "mon: odata received.\n"; + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; +$sim->say ("net send spm ao 3200 90001 90000"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90001 ringo"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,003.\n"; +$sim->say ("net send odata ao 90003 90001 ichigo"); +print "sim: waiting for valid NAK.\n"; +$sim->wait_for_nak; +print "sim: NAK received.\n"; + +print "sim: publish ODATA sqn 90,002.\n"; +$sim->say ("net send odata ao 90002 90001 momo"); + +for (1..2) +{ + print "app: wait for data ...\n"; + my $data = $app->wait_for_data; + print "app: data received [$data].\n"; +} + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/odata_jump.pl b/3rdparty/openpgm-svn-r1135/pgm/test/odata_jump.pl new file mode 100755 index 0000000..748ff23 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/odata_jump.pl @@ -0,0 +1,73 @@ +#!/usr/bin/perl +# odata_jump.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; +$sim->say ("net send spm ao 3200 90001 90000"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90001 ringo"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,003.\n"; +$sim->say ("net send odata ao 90003 90001 ichigo"); + +print "sim: waiting for valid NAK.\n"; +$sim->wait_for_nak; +print "sim: NAK received.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/odata_jump_parity.pl b/3rdparty/openpgm-svn-r1135/pgm/test/odata_jump_parity.pl new file mode 100755 index 0000000..99179cc --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/odata_jump_parity.pl @@ -0,0 +1,83 @@ +#!/usr/bin/perl +# odata_jump_parity.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("listen ao"); + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); + +print "sim: publish SPM txw_trail 32,769 txw_lead 32,768 at spm_sqn 3200, advertise on-demand parity, k=4.\n"; +$sim->say ("net send spm ao 3200 32769 32768 on-demand 4"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 32,769.\n"; +$sim->say ("net send odata ao 32769 32769 ringo"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +# force window into next transmission group +print "sim: publish ODATA sqn 32,771.\n"; +$sim->say ("net send odata ao 32771 32769 ichigo"); +print "sim: publish ODATA sqn 32,772.\n"; +$sim->say ("net send odata ao 32772 32769 momo"); +print "sim: publish ODATA sqn 32,773.\n"; +$sim->say ("net send odata ao 32773 32769 yakitori"); +print "sim: publish ODATA sqn 32,774.\n"; +$sim->say ("net send odata ao 32774 32769 sasami"); +print "sim: publish ODATA sqn 32,775.\n"; +$sim->say ("net send odata ao 32775 32769 tebasaki"); + +print "sim: waiting for valid NAK.\n"; +my $nak = $sim->wait_for_nak; +print "sim: NAK received.\n"; + +die "Selective NAK received, parityPacket=false\n" unless $nak->{PGM}->{options}->{parityPacket}; +print "Parity NAK received.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/odata_number.pl b/3rdparty/openpgm-svn-r1135/pgm/test/odata_number.pl new file mode 100755 index 0000000..e48a7e1 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/odata_number.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl +# odata_number.pl +# 5.1.1. Maximum Cumulative Transmit Rate + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$app->connect; + +sub close_ssh { + $mon = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +print "app: send 1000 data packets ...\n"; +# hide stdout +open(OLDOUT, ">&STDOUT"); +open(STDOUT, ">/dev/null") or die "Can't redirect stdout: $!"; + +for (0..999) +{ + my $i = $_; + $app->say ("send ao $i"); + my $odata = $mon->wait_for_odata; + + die "out of sequence ODATA, received $odata->{PGM}->{odSqn} expected $i\n" unless $odata->{PGM}->{odSqn} == $i; +} + +# restore stdout +close(STDOUT) or die "Can't close STDOUT: $!"; +open(STDOUT, ">&OLDOUT") or die "Can't restore stdout: $!"; +close(OLDOUT) or die "Can't close OLDOUT: $!"; + +print "mon: received 1000 x odata.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/odata_rate.pl b/3rdparty/openpgm-svn-r1135/pgm/test/odata_rate.pl new file mode 100755 index 0000000..0db4d80 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/odata_rate.pl @@ -0,0 +1,69 @@ +#!/usr/bin/perl +# odata_number.pl +# 5.1.1. Maximum Cumulative Transmit Rate + +use strict; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$app->connect; + +sub close_ssh { + $mon = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("set ao TXW_MAX_RTE 1500"); +$app->say ("bind ao"); +$app->say ("connect ao"); + +print "app: send 50 data packets ...\n"; +my $t0 = [gettimeofday]; + +# hide stdout +open(OLDOUT, ">&STDOUT"); +open(STDOUT, ">/dev/null") or die "Can't redirect stdout: $!"; + +my $payload = "ringo" x 100; +my $bytes = 0; +for (1..50) +{ + $app->say ("send ao $payload"); + my $odata = $mon->wait_for_odata; + $bytes += $odata->{IP}->{length}; +} + +close(STDOUT) or die "Can't close STDOUT: $!"; +open(STDOUT, ">&OLDOUT") or die "Can't restore stdout: $!"; +close(OLDOUT) or die "Can't close OLDOUT: $!"; + +my $elapsed = tv_interval ( $t0, [gettimeofday] ); +print "mon: received 50 x odata, $bytes bytes in $elapsed seconds.\n"; + +my $rate = $bytes / $elapsed; +$rate = $bytes if ($rate > $bytes); +print "mon: incoming data rate $rate bps.\n"; + +die "incoming rate exceeds set TXW_MAX_RTE\n" unless $rate < 1650; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/odata_reception.pl b/3rdparty/openpgm-svn-r1135/pgm/test/odata_reception.pl new file mode 100755 index 0000000..4c47dc0 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/odata_reception.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl +# odata_reception.pl +# 6.1. Data Reception + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish ODATA sqn 90,000.\n"; +$sim->say ("net send odata ao 90000 90000 ringo"); +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: received data [$data].\n"; + +# no NAKs should be generated. +# TODO: test for silence in {mon} + +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90000 ichigo"); +print "app: wait for data ...\n"; +$data = $app->wait_for_data; +print "app: received data [$data].\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/on-demand_spm.pl b/3rdparty/openpgm-svn-r1135/pgm/test/on-demand_spm.pl new file mode 100755 index 0000000..eb86cf9 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/on-demand_spm.pl @@ -0,0 +1,49 @@ +#!/usr/bin/perl +# on-demand_spm.pl +# 5.1.4. Ambient SPMs with on-demand parity flag + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$app->connect; + +sub close_ssh { + $mon = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("set ao FEC RS(255,64)"); +$app->say ("bind ao"); +print "app: ready.\n"; + +print "mon: wait for spm ...\n"; +my $spm = $mon->wait_for_spm; +print "mon: received spm.\n"; + +die "SPM does not contain any PGM options\n" unless $spm->{PGM}->{pgmOptions}; +die "SPM does not contain a PGM_OPT_PARITY_PRM option\n" unless $spm->{PGM}->{pgmOptions}[1]->{type} =~ /OPT_PARITY_PRM/; +print "pro-active parity " . ($spm->{PGM}->{pgmOptions}[1]->{'P-bit'} ? 'enabled' : 'disabled') . ", P-bit " . ($spm->{PGM}->{pgmOptions}[1]->{'P-bit'} ? 'true' : 'false') . "\n"; +die "on-demand parity disabled, O-bit false\n" unless $spm->{PGM}->{pgmOptions}[1]->{'O-bit'}; +print "on-demand parity enabled, O-bit true\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/outofwindow_ncf.pl b/3rdparty/openpgm-svn-r1135/pgm/test/outofwindow_ncf.pl new file mode 100755 index 0000000..3e1eb88 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/outofwindow_ncf.pl @@ -0,0 +1,105 @@ +#!/usr/bin/perl +# outofwindow_ncf.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +## capture GSI of test spp +$app->say ("send ao nashi"); +print "mon: wait for odata ...\n"; +my $odata = $mon->wait_for_odata; +print "mon: odata received.\n"; + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; +$sim->say ("net send spm ao 3200 90001 90000"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90001 ringo"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +## first run through with regular NAK generation to get regular backoff interval +print "sim: publish ODATA sqn 90,003.\n"; +$sim->say ("net send odata ao 90003 90001 ichigo"); +my $t0 = [gettimeofday]; +print "sim: waiting for valid NAK.\n"; +$sim->wait_for_nak; +my $normal_backoff = tv_interval ( $t0, [gettimeofday] ); +print "sim: NAK received in $normal_backoff seconds.\n"; + +## cleanup by publishing repair data +print "sim: publish RDATA sqn 90,002.\n"; +$sim->say ("net send odata ao 90002 90001 momo"); +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +## second run with NAK suppression +$t0 = [gettimeofday]; +print "sim: publish ODATA sqn 90,005.\n"; +$sim->say ("net send odata ao 90005 90001 anzu"); +print "sim: publish NCF sqn 90,004.\n"; +$sim->say ("net send ncf ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort} 90002"); + +print "sim: waiting for valid NAK.\n"; +$sim->wait_for_nak; +my $outofwindow_backoff = tv_interval ( $t0, [gettimeofday] ); +print "sim: NAK received in $outofwindow_backoff seconds.\n"; + +# allow 100ms tolerance +my $fabs = abs( ($outofwindow_backoff - $normal_backoff) * 1000 ); +die "Out-of-window NCF altered back-off interval by $fabs ms.\n" unless ($fabs < 100); + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion.pl b/3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion.pl new file mode 100755 index 0000000..3b290ee --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion.pl @@ -0,0 +1,89 @@ +#!/usr/bin/perl +# rdata_completion.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +## capture GSI of test spp +$app->say ("send ao nashi"); +print "mon: wait for odata ...\n"; +my $odata = $mon->wait_for_odata; +print "mon: odata received.\n"; + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; +$sim->say ("net send spm ao 3200 90001 90000"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90001 ringo"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,003.\n"; +$sim->say ("net send odata ao 90003 90001 ichigo"); +print "sim: waiting for valid NAK.\n"; +$sim->wait_for_nak; +print "sim: NAK received.\n"; + +print "sim: publish RDATA sqn 90,002.\n"; +$sim->say ("net send rdata ao 90002 90001 momo"); + +for (1..2) +{ + print "app: wait for data ...\n"; + my $data = $app->wait_for_data; + print "app: data received [$data].\n"; +} + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion_parity.pl b/3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion_parity.pl new file mode 100755 index 0000000..95a6f7b --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion_parity.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl +# rdata_completion_parity.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("set ao FEC RS(255,4)"); +$app->say ("bind ao"); +$app->say ("listen ao"); + +## capture GSI of test spp +$app->say ("send ao nashi"); +print "mon: wait for odata ...\n"; +my $odata = $mon->wait_for_odata; +print "mon: odata received.\n"; + +$sim->say ("create fake ao"); +$sim->say ("set ao FEC RS(255,4)"); +$sim->say ("bind ao"); + +print "sim: publish SPM txw_trail 32,769 txw_lead 32,768 at spm_sqn 3200, advertise on-demand parity, k=4.\n"; +$sim->say ("net send spm ao 3200 32768 32767 on-demand 4"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 32,768.\n"; +$sim->say ("net send odata ao 32768 32768 ringo000"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 32,770.\n"; +$sim->say ("net send odata ao 32770 32768 momo0000"); +print "sim: publish ODATA sqn 32,771.\n"; +$sim->say ("net send odata ao 32771 32768 yakitori"); +print "sim: publish ODATA sqn 32,772.\n"; +$sim->say ("net send odata ao 32772 32768 sasami00"); +print "sim: publish ODATA sqn 32,773.\n"; +$sim->say ("net send odata ao 32773 32768 tebasaki"); + +print "sim: waiting for valid parity NAK.\n"; +my $nak = $sim->wait_for_nak; +die "Selective NAK received, parityPacket=false\n" unless $nak->{PGM}->{options}->{parityPacket}; +print "sim: Parity NAK received.\n"; + +print "sim: publish parity RDATA, tg_sqn 32,768, pkt_cnt 1 (sqn 32,768).\n"; +$sim->say ("net send parity rdata ao 32768 32768 ringo000 ichigo00 momo0000 yakitori"); + +for (1..5) +{ + print "app: wait for data ...\n"; + my $data = $app->wait_for_data; + print "app: data received [$data].\n"; +} + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion_parity_var_pktlen.pl b/3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion_parity_var_pktlen.pl new file mode 100755 index 0000000..9011ea1 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/rdata_completion_parity_var_pktlen.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl +# rdata_completion_parity_var_pktlen.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("set ao FEC RS(255,4)"); +$app->say ("bind ao"); +$app->say ("listen ao"); + +## capture GSI of test spp +$app->say ("send ao nashi"); +print "mon: wait for odata ...\n"; +my $odata = $mon->wait_for_odata; +print "mon: odata received.\n"; + +$sim->say ("create fake ao"); +$sim->say ("set ao FEC RS(255,4)"); +$sim->say ("bind ao"); + +print "sim: publish SPM txw_trail 32,769 txw_lead 32,768 at spm_sqn 3200, advertise on-demand parity, k=4.\n"; +$sim->say ("net send spm ao 3200 32768 32767 on-demand 4"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 32,768.\n"; +$sim->say ("net send odata ao 32768 32768 ringo"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak ({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 32,770.\n"; +$sim->say ("net send odata ao 32770 32768 momo"); +print "sim: publish ODATA sqn 32,771.\n"; +$sim->say ("net send odata ao 32771 32768 yakitori"); +print "sim: publish ODATA sqn 32,772.\n"; +$sim->say ("net send odata ao 32772 32768 sasami"); +print "sim: publish ODATA sqn 32,773.\n"; +$sim->say ("net send odata ao 32773 32768 tebasaki"); + +print "sim: waiting for valid parity NAK.\n"; +my $nak = $sim->wait_for_nak; +die "Selective NAK received, parityPacket=false\n" unless $nak->{PGM}->{options}->{parityPacket}; +print "sim: Parity NAK received.\n"; + +print "sim: publish parity RDATA, tg_sqn 32,768, pkt_cnt 1 (sqn 32,768).\n"; +$sim->say ("net send parity rdata ao 32768 32768 ringo ichigo momo yakitori"); + +for (1..5) +{ + print "app: wait for data ...\n"; + my $data = $app->wait_for_data; + print "app: data received [$data].\n"; +} + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/rdata_jump.pl b/3rdparty/openpgm-svn-r1135/pgm/test/rdata_jump.pl new file mode 100755 index 0000000..dbb3e02 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/rdata_jump.pl @@ -0,0 +1,73 @@ +#!/usr/bin/perl +# rdata_jump.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; +$sim->say ("net send spm ao 3200 90001 90000"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90001 ringo"); + +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: data received [$data].\n"; + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish RDATA sqn 90,003.\n"; +$sim->say ("net send rdata ao 90003 90001 ichigo"); + +print "sim: waiting for valid NAK.\n"; +$sim->wait_for_nak; +print "sim: NAK received.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/rdata_reception.pl b/3rdparty/openpgm-svn-r1135/pgm/test/rdata_reception.pl new file mode 100755 index 0000000..3592cc7 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/rdata_reception.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl +# rdata_reception.pl +# 6.1. Data Reception + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish RDATA sqn 90,000.\n"; +$sim->say ("net send rdata ao 90000 90000 ringo"); +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: received data [$data].\n"; + +# no NAKs should be generated. +# TODO: test for silence in {mon} + +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90000 ichigo"); +print "app: wait for data ...\n"; +$data = $app->wait_for_data; +print "app: received data [$data].\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/sim.c b/3rdparty/openpgm-svn-r1135/pgm/test/sim.c new file mode 100644 index 0000000..d600fae --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/sim.c @@ -0,0 +1,2301 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM conformance endpoint simulator. + * + * Copyright (c) 2006-2008 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dump-json.h" +#include "async.h" + + +/* typedefs */ + +struct idle_source { + GSource source; + guint64 expiration; +}; + +struct sim_session { + char* name; + pgm_sock_t* sock; + gboolean is_transport_fake; + GIOChannel* recv_channel; + pgm_async_t* async; +}; + +/* globals */ +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "sim" + +#ifndef SOL_IP +# define SOL_IP IPPROTO_IP +#endif +#ifndef SOL_IPV6 +# define SOL_IPV6 IPPROTO_IPV6 +#endif + + +static int g_port = 7500; +static const char* g_network = ";239.192.0.1"; + +static int g_max_tpdu = 1500; +static int g_sqns = 100 * 1000; + +static GList* g_sessions_list = NULL; +static GHashTable* g_sessions = NULL; +static GMainLoop* g_loop = NULL; +static GIOChannel* g_stdin_channel = NULL; + + +static void on_signal (int, gpointer); +static gboolean on_startup (gpointer); +static gboolean on_mark (gpointer); +static void destroy_session (struct sim_session*); +static int on_data (gpointer, guint, gpointer); +static gboolean on_stdin_data (GIOChannel*, GIOCondition, gpointer); +void generic_net_send_nak (guint8, char*, pgm_tsi_t*, struct pgm_sqn_list_t*); + + +G_GNUC_NORETURN static +void +usage (const char* bin) +{ + fprintf (stderr, "Usage: %s [options]\n", bin); + fprintf (stderr, " -n : Multicast group or unicast IP address\n"); + fprintf (stderr, " -s : IP port\n"); + exit (1); +} + +int +main ( + int argc, + char *argv[] + ) +{ + pgm_error_t* pgm_err = NULL; + +/* pre-initialise PGM messages module to add hook for GLib logging */ + pgm_messages_init(); + log_init (); + g_message ("sim"); + + if (!pgm_init (&pgm_err)) { + g_error ("Unable to start PGM engine: %s", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + pgm_error_free (pgm_err); + pgm_messages_shutdown(); + return EXIT_FAILURE; + } + +/* parse program arguments */ + const char* binary_name = strrchr (argv[0], '/'); + int c; + while ((c = getopt (argc, argv, "s:n:h")) != -1) + { + switch (c) { + case 'n': g_network = optarg; break; + case 's': g_port = atoi (optarg); break; + + case 'h': + case '?': + pgm_messages_shutdown(); + usage (binary_name); + } + } + + g_loop = g_main_loop_new (NULL, FALSE); + +/* setup signal handlers */ + signal (SIGSEGV, on_sigsegv); + signal (SIGHUP, SIG_IGN); + pgm_signal_install (SIGINT, on_signal, g_loop); + pgm_signal_install (SIGTERM, on_signal, g_loop); + +/* delayed startup */ + g_message ("scheduling startup."); + g_timeout_add (0, (GSourceFunc)on_startup, NULL); + +/* dispatch loop */ + g_message ("entering main event loop ... "); + g_main_loop_run (g_loop); + + g_message ("event loop terminated, cleaning up."); + +/* cleanup */ + g_main_loop_unref(g_loop); + g_loop = NULL; + + if (g_sessions) { + g_message ("destroying sessions."); + while (g_sessions_list) { + destroy_session (g_sessions_list->data); + g_sessions_list = g_list_delete_link (g_sessions_list, g_sessions_list); + } + g_hash_table_unref (g_sessions); + g_sessions = NULL; + } + + if (g_stdin_channel) { + puts ("unbinding stdin."); + g_io_channel_unref (g_stdin_channel); + g_stdin_channel = NULL; + } + + g_message ("PGM engine shutdown."); + pgm_shutdown(); + g_message ("finished."); + pgm_messages_shutdown(); + return EXIT_SUCCESS; +} + +static +void +destroy_session ( + struct sim_session* sess + ) +{ + printf ("destroying socket \"%s\"\n", sess->name); + pgm_close (sess->sock, TRUE); + sess->sock = NULL; + g_free (sess->name); + sess->name = NULL; + g_free (sess); +} + +static +void +on_signal ( + int signum, + gpointer user_data + ) +{ + GMainLoop* loop = (GMainLoop*)user_data; + g_message ("on_signal (signum:%d user-data:%p)", signum, user_data); + g_main_loop_quit (loop); +} + +static +gboolean +on_startup ( + G_GNUC_UNUSED gpointer data + ) +{ + g_message ("startup."); + + g_sessions = g_hash_table_new (g_str_hash, g_str_equal); + +/* add stdin to event manager */ + g_stdin_channel = g_io_channel_unix_new (fileno(stdin)); + printf ("binding stdin with encoding %s.\n", g_io_channel_get_encoding(g_stdin_channel)); + + g_io_add_watch (g_stdin_channel, G_IO_IN | G_IO_PRI, on_stdin_data, NULL); + +/* period timer to indicate some form of life */ +// TODO: Gnome 2.14: replace with g_timeout_add_seconds() + g_timeout_add(10 * 1000, (GSourceFunc)on_mark, NULL); + + puts ("READY"); + fflush (stdout); + return FALSE; +} + +static +bool +fake_pgm_socket ( + pgm_sock_t**restrict sock, + const sa_family_t family, + const int pgm_sock_type, + const int protocol, + G_GNUC_UNUSED pgm_error_t**restrict error + ) +{ + pgm_sock_t* new_sock; + + g_return_val_if_fail (NULL != sock, FALSE); + g_return_val_if_fail (AF_INET == family || AF_INET6 == family, FALSE); + g_return_val_if_fail (SOCK_SEQPACKET == pgm_sock_type, FALSE); + g_return_val_if_fail (IPPROTO_UDP == protocol || IPPROTO_PGM == protocol, FALSE); + + new_sock = pgm_new0 (pgm_sock_t, 1); + new_sock->family = family; + new_sock->socket_type = pgm_sock_type; + new_sock->protocol = protocol; + new_sock->can_send_data = TRUE; + new_sock->can_send_nak = TRUE; + new_sock->can_recv_data = TRUE; + new_sock->dport = DEFAULT_DATA_DESTINATION_PORT; + new_sock->tsi.sport = DEFAULT_DATA_SOURCE_PORT; + new_sock->adv_mode = 0; /* advance with time */ + +/* PGMCC */ + new_sock->acker_nla.ss_family = family; + +/* open sockets to implement PGM */ + int socket_type; + if (IPPROTO_UDP == new_sock->protocol) { + puts ("Opening UDP encapsulated sockets."); + socket_type = SOCK_DGRAM; + new_sock->udp_encap_ucast_port = DEFAULT_UDP_ENCAP_UCAST_PORT; + new_sock->udp_encap_mcast_port = DEFAULT_UDP_ENCAP_MCAST_PORT; + } else { + puts ("Opening raw sockets."); + socket_type = SOCK_RAW; + } + + if ((new_sock->recv_sock = socket (new_sock->family, + socket_type, + new_sock->protocol)) == PGM_INVALID_SOCKET) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + "Creating receive socket: %s", + pgm_sock_strerror (save_errno)); +#ifndef _WIN32 + if (EPERM == save_errno) { + g_critical ("PGM protocol requires CAP_NET_RAW capability, e.g. sudo execcap 'cap_net_raw=ep'"); + } +#endif + goto err_destroy; + } + + if ((new_sock->send_sock = socket (new_sock->family, + socket_type, + new_sock->protocol)) == PGM_INVALID_SOCKET) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + "Creating send socket: %s", + pgm_sock_strerror (save_errno)); + goto err_destroy; + } + + if ((new_sock->send_with_router_alert_sock = socket (new_sock->family, + socket_type, + new_sock->protocol)) == PGM_INVALID_SOCKET) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + "Creating IP Router Alert (RFC 2113) send socket: %s", + pgm_sock_strerror (save_errno)); + goto err_destroy; + } + + *sock = new_sock; + + puts ("PGM socket successfully created."); + return TRUE; + +err_destroy: + if (PGM_INVALID_SOCKET != new_sock->recv_sock) { + if (PGM_SOCKET_ERROR == pgm_closesocket (new_sock->recv_sock)) { + const int save_errno = pgm_sock_errno(); + g_warning ("Close on receive socket failed: %s", + pgm_sock_strerror (save_errno)); + } + new_sock->recv_sock = PGM_INVALID_SOCKET; + } + if (PGM_INVALID_SOCKET != new_sock->send_sock) { + if (PGM_SOCKET_ERROR == pgm_closesocket (new_sock->send_sock)) { + const int save_errno = pgm_sock_errno(); + g_warning ("Close on send socket failed: %s", + pgm_sock_strerror (save_errno)); + } + new_sock->send_sock = PGM_INVALID_SOCKET; + } + if (PGM_INVALID_SOCKET != new_sock->send_with_router_alert_sock) { + if (PGM_SOCKET_ERROR == pgm_closesocket (new_sock->send_with_router_alert_sock)) { + const int save_errno = pgm_sock_errno(); + g_warning ("Close on IP Router Alert (RFC 2113) send socket failed: %s", + pgm_sock_strerror (save_errno)); + } + new_sock->send_with_router_alert_sock = PGM_INVALID_SOCKET; + } + pgm_free (new_sock); + return FALSE; +} + +static +gboolean +on_io_data ( + GIOChannel* source, + G_GNUC_UNUSED GIOCondition condition, + gpointer data + ) +{ + pgm_sock_t* sock = data; + + struct pgm_sk_buff_t* skb = pgm_alloc_skb (sock->max_tpdu); + int fd = g_io_channel_unix_get_fd(source); + struct sockaddr_storage src_addr; + socklen_t src_addr_len = sizeof(src_addr); + skb->len = recvfrom(fd, skb->head, sock->max_tpdu, MSG_DONTWAIT, (struct sockaddr*)&src_addr, &src_addr_len); + + printf ("%i bytes received from %s.\n", skb->len, inet_ntoa(((struct sockaddr_in*)&src_addr)->sin_addr)); + + monitor_packet (skb->data, skb->len); + fflush (stdout); + +/* parse packet to maintain peer database */ + if (sock->udp_encap_ucast_port) { + if (!pgm_parse_udp_encap (skb, NULL)) + goto out; + } else { + struct sockaddr_storage addr; + if (!pgm_parse_raw (skb, (struct sockaddr*)&addr, NULL)) + goto out; + } + + if (PGM_IS_UPSTREAM (skb->pgm_header->pgm_type) || + PGM_IS_PEER (skb->pgm_header->pgm_type)) + goto out; /* ignore */ + +/* downstream = source to receivers */ + if (!PGM_IS_DOWNSTREAM (skb->pgm_header->pgm_type)) + goto out; + +/* pgm packet DPORT contains our transport DPORT */ + if (skb->pgm_header->pgm_dport != sock->dport) + goto out; + +/* search for TSI peer context or create a new one */ + pgm_peer_t* sender = pgm_hashtable_lookup (sock->peers_hashtable, &skb->tsi); + if (sender == NULL) + { + printf ("new peer, tsi %s, local nla %s\n", + pgm_tsi_print (&skb->tsi), + inet_ntoa(((struct sockaddr_in*)&src_addr)->sin_addr)); + + pgm_peer_t* peer = g_new0 (pgm_peer_t, 1); + peer->sock = sock; + memcpy (&peer->tsi, &skb->tsi, sizeof(pgm_tsi_t)); + ((struct sockaddr_in*)&peer->nla)->sin_addr.s_addr = INADDR_ANY; + memcpy (&peer->local_nla, &src_addr, src_addr_len); + + pgm_hashtable_insert (sock->peers_hashtable, &peer->tsi, peer); + sender = peer; + } + +/* handle SPMs for advertised NLA */ + if (skb->pgm_header->pgm_type == PGM_SPM) + { + char *pgm_data = (char*)(skb->pgm_header + 1); + struct pgm_spm* spm = (struct pgm_spm*)pgm_data; + guint32 spm_sqn = g_ntohl (spm->spm_sqn); + + if ( pgm_uint32_gte (spm_sqn, sender->spm_sqn) + || ( ((struct sockaddr*)&sender->nla)->sa_family == 0 ) ) + { + pgm_nla_to_sockaddr (&spm->spm_nla_afi, (struct sockaddr*)&sender->nla); + sender->spm_sqn = spm_sqn; + } + } + +out: + return TRUE; +} + +static +bool +fake_pgm_bind3 ( + pgm_sock_t* restrict sock, + const struct pgm_sockaddr_t*const restrict sockaddr, + const socklen_t sockaddrlen, + const struct pgm_interface_req_t*const send_req, /* only use gr_interface and gr_group::sin6_scope */ + const socklen_t send_req_len, + const struct pgm_interface_req_t*const recv_req, + const socklen_t recv_req_len, + pgm_error_t** restrict error /* maybe NULL */ + ) +{ + g_return_val_if_fail (NULL != sock, FALSE); + g_return_val_if_fail (NULL != sockaddr, FALSE); + g_return_val_if_fail (0 != sockaddrlen, FALSE); + if (sockaddr->sa_addr.sport) pgm_return_val_if_fail (sockaddr->sa_addr.sport != sockaddr->sa_port, FALSE); + g_return_val_if_fail (NULL != send_req, FALSE); + g_return_val_if_fail (sizeof(struct pgm_interface_req_t) == send_req_len, FALSE); + g_return_val_if_fail (NULL != recv_req, FALSE); + g_return_val_if_fail (sizeof(struct pgm_interface_req_t) == recv_req_len, FALSE); + + if (sock->is_bound || + sock->is_destroyed) + { + pgm_return_val_if_reached (FALSE); + } + + memcpy (&sock->tsi, &sockaddr->sa_addr, sizeof(pgm_tsi_t)); + sock->dport = htons (sockaddr->sa_port); + if (sock->tsi.sport) { + sock->tsi.sport = htons (sock->tsi.sport); + } else { + do { + sock->tsi.sport = htons (pgm_random_int_range (0, UINT16_MAX)); + } while (sock->tsi.sport == sock->dport); + } + +/* UDP encapsulation port */ + if (sock->udp_encap_mcast_port) { + ((struct sockaddr_in*)&sock->send_gsr.gsr_group)->sin_port = htons (sock->udp_encap_mcast_port); + } + +/* pseudo-random number generator for back-off intervals */ + pgm_rand_create (&sock->rand_); + +/* PGM Children support of POLLs requires 32-bit random node identifier RAND_NODE_ID */ + if (sock->can_recv_data) { + sock->rand_node_id = pgm_rand_int (&sock->rand_); + } + +/* determine IP header size for rate regulation engine & stats */ + sock->iphdr_len = (AF_INET == sock->family) ? sizeof(struct pgm_ip) : sizeof(struct pgm_ip6_hdr); + pgm_trace (PGM_LOG_ROLE_NETWORK,"Assuming IP header size of %zu bytes", sock->iphdr_len); + + if (sock->udp_encap_ucast_port) { + const size_t udphdr_len = sizeof(struct pgm_udphdr); + printf ("Assuming UDP header size of %zu bytes\n", udphdr_len); + sock->iphdr_len += udphdr_len; + } + + const sa_family_t pgmcc_family = sock->use_pgmcc ? sock->family : 0; + sock->max_tsdu = sock->max_tpdu - sock->iphdr_len - pgm_pkt_offset (FALSE, pgmcc_family); + sock->max_tsdu_fragment = sock->max_tpdu - sock->iphdr_len - pgm_pkt_offset (TRUE, pgmcc_family); + const unsigned max_fragments = sock->txw_sqns ? MIN( PGM_MAX_FRAGMENTS, sock->txw_sqns ) : PGM_MAX_FRAGMENTS; + sock->max_apdu = MIN( PGM_MAX_APDU, max_fragments * sock->max_tsdu_fragment ); + +/* create peer list */ + if (sock->can_recv_data) { + sock->peers_hashtable = pgm_hashtable_new (pgm_tsi_hash, pgm_tsi_equal); + pgm_assert (NULL != sock->peers_hashtable); + } + +/* IP/PGM only */ + { + const sa_family_t recv_family = sock->family; + if (AF_INET == recv_family) + { +/* include IP header only for incoming data, only works for IPv4 */ + puts ("Request IP headers."); + if (PGM_SOCKET_ERROR == pgm_sockaddr_hdrincl (sock->recv_sock, recv_family, TRUE)) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + "Enabling IP header in front of user data: %s", + pgm_sock_strerror (save_errno)); + return FALSE; + } + } + else + { + pgm_assert (AF_INET6 == recv_family); + puts ("Request socket packet-info."); + if (PGM_SOCKET_ERROR == pgm_sockaddr_pktinfo (sock->recv_sock, recv_family, TRUE)) + { + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + "Enabling receipt of control message per incoming datagram: %s", + pgm_sock_strerror (save_errno)); + return FALSE; + } + } + } + + union { + struct sockaddr sa; + struct sockaddr_in s4; + struct sockaddr_in6 s6; + struct sockaddr_storage ss; + } recv_addr, recv_addr2, send_addr, send_with_router_alert_addr; + +#ifdef CONFIG_BIND_INADDR_ANY +/* force default interface for bind-only, source address is still valid for multicast membership. + * effectively same as running getaddrinfo(hints = {ai_flags = AI_PASSIVE}) + */ + if (AF_INET == sock->family) { + memset (&recv_addr.s4, 0, sizeof(struct sockaddr_in)); + recv_addr.s4.sin_family = AF_INET; + recv_addr.s4.sin_addr.s_addr = INADDR_ANY; + } else { + memset (&recv_addr.s6, 0, sizeof(struct sockaddr_in6)); + recv_addr.s6.sin6_family = AF_INET6; + recv_addr.s6.sin6_addr = in6addr_any; + } + puts ("Binding receive socket to INADDR_ANY."); +#else + if (!pgm_if_indextoaddr (recv_req->ir_interface, + sock->family, + recv_req->ir_scope_id, + &recv_addr.sa, + error)) + { + return FALSE; + } + printf ("Binding receive socket to interface index %u scope %u\n"), + recv_req->ir_interface, + recv_req->ir_scope_id); + +#endif /* CONFIG_BIND_INADDR_ANY */ + + memcpy (&recv_addr2.sa, &recv_addr.sa, pgm_sockaddr_len (&recv_addr.sa)); + ((struct sockaddr_in*)&recv_addr)->sin_port = htons (sock->udp_encap_mcast_port); + if (PGM_SOCKET_ERROR == bind (sock->recv_sock, + &recv_addr.sa, + pgm_sockaddr_len (&recv_addr.sa))) + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&recv_addr, addr, sizeof(addr)); + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + "Binding receive socket to address %s: %s", + addr, + pgm_sock_strerror (save_errno)); + return FALSE; + } + + { + char s[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&recv_addr, s, sizeof(s)); + printf ("bind succeeded on recv_gsr[0] interface %s\n", s); + } + +/* keep a copy of the original address source to re-use for router alert bind */ + memset (&send_addr, 0, sizeof(send_addr)); + + if (!pgm_if_indextoaddr (send_req->ir_interface, + sock->family, + send_req->ir_scope_id, + (struct sockaddr*)&send_addr, + error)) + { + return FALSE; + } + else + { + printf ("Binding send socket to interface index %u scope %u\n", + send_req->ir_interface, + send_req->ir_scope_id); + } + + memcpy (&send_with_router_alert_addr, &send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)); + if (PGM_SOCKET_ERROR == bind (sock->send_sock, + (struct sockaddr*)&send_addr, + pgm_sockaddr_len ((struct sockaddr*)&send_addr))) + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&send_addr, addr, sizeof(addr)); + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + "Binding send socket to address %s: %s", + addr, + pgm_sock_strerror (save_errno)); + return FALSE; + } + +/* resolve bound address if 0.0.0.0 */ + if (AF_INET == send_addr.ss.ss_family) + { + if ((INADDR_ANY == ((struct sockaddr_in*)&send_addr)->sin_addr.s_addr) && + !pgm_if_getnodeaddr (AF_INET, (struct sockaddr*)&send_addr, sizeof(send_addr), error)) + { + return FALSE; + } + } + else if ((memcmp (&in6addr_any, &((struct sockaddr_in6*)&send_addr)->sin6_addr, sizeof(in6addr_any)) == 0) && + !pgm_if_getnodeaddr (AF_INET6, (struct sockaddr*)&send_addr, sizeof(send_addr), error)) + { + return FALSE; + } + + { + char s[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&send_addr, s, sizeof(s)); + printf ("bind succeeded on send_gsr interface %s\n", s); + } + + if (PGM_SOCKET_ERROR == bind (sock->send_with_router_alert_sock, + (struct sockaddr*)&send_with_router_alert_addr, + pgm_sockaddr_len((struct sockaddr*)&send_with_router_alert_addr))) + { + char addr[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&send_with_router_alert_addr, addr, sizeof(addr)); + const int save_errno = pgm_sock_errno(); + pgm_set_error (error, + PGM_ERROR_DOMAIN_SOCKET, + pgm_error_from_sock_errno (save_errno), + "Binding IP Router Alert (RFC 2113) send socket to address %s: %s", + addr, + pgm_sock_strerror (save_errno)); + return FALSE; + } + + { + char s[INET6_ADDRSTRLEN]; + pgm_sockaddr_ntop ((struct sockaddr*)&send_with_router_alert_addr, s, sizeof(s)); + printf ("bind (router alert) succeeded on send_gsr interface %s\n", s); + } + +/* save send side address for broadcasting as source nla */ + memcpy (&sock->send_addr, &send_addr, pgm_sockaddr_len ((struct sockaddr*)&send_addr)); + + sock->is_controlled_spm = FALSE; + sock->is_controlled_odata = FALSE; + sock->is_controlled_rdata = FALSE; + +/* allocate first incoming packet buffer */ + sock->rx_buffer = pgm_alloc_skb (sock->max_tpdu); + +/* bind complete */ + sock->is_bound = TRUE; + +/* cleanup */ + puts ("PGM socket successfully bound."); + return TRUE; +} + +static +bool +fake_pgm_bind ( + pgm_sock_t* restrict sock, + const struct pgm_sockaddr_t*const restrict sockaddr, + const socklen_t sockaddrlen, + pgm_error_t** restrict error + ) +{ + struct pgm_interface_req_t null_req; + memset (&null_req, 0, sizeof(null_req)); + return fake_pgm_bind3 (sock, sockaddr, sockaddrlen, &null_req, sizeof(null_req), &null_req, sizeof(null_req), error); +} + +static +bool +fake_pgm_connect ( + pgm_sock_t* restrict sock, + G_GNUC_UNUSED pgm_error_t** restrict error /* maybe NULL */ + ) +{ + g_return_val_if_fail (sock != NULL, FALSE); + g_return_val_if_fail (sock->recv_gsr_len > 0, FALSE); +#ifdef CONFIG_TARGET_WINE + g_return_val_if_fail (sock->recv_gsr_len == 1, FALSE); +#endif + for (unsigned i = 0; i < sock->recv_gsr_len; i++) + { + g_return_val_if_fail (sock->recv_gsr[i].gsr_group.ss_family == sock->recv_gsr[0].gsr_group.ss_family, FALSE); + g_return_val_if_fail (sock->recv_gsr[i].gsr_group.ss_family == sock->recv_gsr[i].gsr_source.ss_family, FALSE); + } + g_return_val_if_fail (sock->send_gsr.gsr_group.ss_family == sock->recv_gsr[0].gsr_group.ss_family, FALSE); +/* state */ + if (PGM_UNLIKELY(sock->is_connected || !sock->is_bound || sock->is_destroyed)) { + g_return_val_if_reached (FALSE); + } + + sock->next_poll = pgm_time_update_now() + pgm_secs( 30 ); + sock->is_connected = TRUE; + +/* cleanup */ + puts ("PGM socket successfully connected."); + return TRUE; +} + + +static +bool +fake_pgm_close ( + pgm_sock_t* sock, + G_GNUC_UNUSED bool flush + ) +{ + g_return_val_if_fail (sock != NULL, FALSE); + g_return_val_if_fail (!sock->is_destroyed, FALSE); +/* flag existing calls */ + sock->is_destroyed = TRUE; +/* cancel running blocking operations */ + if (PGM_INVALID_SOCKET != sock->recv_sock) { + puts ("Closing receive socket."); + pgm_closesocket (sock->recv_sock); + sock->recv_sock = PGM_INVALID_SOCKET; + } + if (PGM_INVALID_SOCKET != sock->send_sock) { + puts ("Closing send socket."); + pgm_closesocket (sock->send_sock); + sock->send_sock = PGM_INVALID_SOCKET; + } + if (sock->peers_hashtable) { + pgm_hashtable_destroy (sock->peers_hashtable); + sock->peers_hashtable = NULL; + } + if (sock->peers_list) { + do { + pgm_list_t* next = sock->peers_list->next; + pgm_peer_unref ((pgm_peer_t*)sock->peers_list->data); + + sock->peers_list = next; + } while (sock->peers_list); + } + if (PGM_INVALID_SOCKET != sock->send_with_router_alert_sock) { + puts ("Closing send with router alert socket."); + pgm_closesocket (sock->send_with_router_alert_sock); + sock->send_with_router_alert_sock = PGM_INVALID_SOCKET; + } + if (sock->spm_heartbeat_interval) { + puts ("freeing SPM heartbeat interval data."); + g_free (sock->spm_heartbeat_interval); + sock->spm_heartbeat_interval = NULL; + } + if (sock->rx_buffer) { + puts ("freeing receive buffer."); + pgm_free_skb (sock->rx_buffer); + sock->rx_buffer = NULL; + } + + g_free (sock); + return TRUE; +} + +static +void +session_create ( + char* session_name, + gboolean is_fake + ) +{ + pgm_error_t* pgm_err = NULL; + gboolean status; + +/* check for duplicate */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess != NULL) { + printf ("FAILED: duplicate session name '%s'\n", session_name); + return; + } + +/* create new and fill in bits */ + sess = g_new0(struct sim_session, 1); + sess->name = g_memdup (session_name, strlen(session_name)+1); + + if (is_fake) { + sess->is_transport_fake = TRUE; + status = fake_pgm_socket (&sess->sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err); + } else { + status = pgm_socket (&sess->sock, AF_INET, SOCK_SEQPACKET, IPPROTO_PGM, &pgm_err); + } + if (!status) { + printf ("FAILED: pgm_socket(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + pgm_error_free (pgm_err); + goto err_free; + } + +/* success */ + g_hash_table_insert (g_sessions, sess->name, sess); + g_sessions_list = g_list_prepend (g_sessions_list, sess); + printf ("created new session \"%s\"\n", sess->name); + puts ("READY"); + return; + +err_free: + g_free(sess->name); + g_free(sess); +} + +static +void +session_set_fec ( + char* session_name, + guint block_size, + guint group_size + ) +{ +/* check that session exists */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + if (block_size > UINT8_MAX || + group_size > UINT8_MAX) + { + puts ("FAILED: value out of bounds"); + return; + } + + const struct pgm_fecinfo_t fecinfo = { + .block_size = block_size, + .proactive_packets = 0, + .group_size = group_size, + .ondemand_parity_enabled = TRUE, + .var_pktlen_enabled = TRUE + }; + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_USE_FEC, &fecinfo, sizeof(fecinfo))) + printf ("FAILED: set FEC = RS(%d, %d)\n", block_size, group_size); + else + puts ("READY"); +} + +static +void +session_bind ( + char* session_name + ) +{ + pgm_error_t* pgm_err = NULL; + +/* check that session exists */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + +/* Use RFC 2113 tagging for PGM Router Assist */ + const int no_router_assist = 0; + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_IP_ROUTER_ALERT, &no_router_assist, sizeof(no_router_assist))) + puts ("FAILED: disable IP_ROUTER_ALERT"); + +/* set PGM parameters */ + const int send_and_receive = 0, + active = 0, + mtu = g_max_tpdu, + txw_sqns = g_sqns, + rxw_sqns = g_sqns, + ambient_spm = pgm_secs (30), + heartbeat_spm[] = { pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (100), + pgm_msecs (1300), + pgm_secs (7), + pgm_secs (16), + pgm_secs (25), + pgm_secs (30) }, + peer_expiry = pgm_secs (300), + spmr_expiry = pgm_msecs (250), + nak_bo_ivl = pgm_msecs (50), + nak_rpt_ivl = pgm_secs (2), + nak_rdata_ivl = pgm_secs (2), + nak_data_retries = 50, + nak_ncf_retries = 50; + + g_assert (G_N_ELEMENTS(heartbeat_spm) > 0); + + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_SEND_ONLY, &send_and_receive, sizeof(send_and_receive))) + puts ("FAILED: set bi-directional transport"); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_RECV_ONLY, &send_and_receive, sizeof(send_and_receive))) + puts ("FAILED: set bi-directional transport"); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_PASSIVE, &active, sizeof(active))) + puts ("FAILED: set active transport"); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_MTU, &mtu, sizeof(mtu))) + printf ("FAILED: set MAX_TPDU = %d bytes\n", mtu); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_TXW_SQNS, &txw_sqns, sizeof(txw_sqns))) + printf ("FAILED: set TXW_SQNS = %d\n", txw_sqns); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_RXW_SQNS, &rxw_sqns, sizeof(rxw_sqns))) + printf ("FAILED: set RXW_SQNS = %d\n", rxw_sqns); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_AMBIENT_SPM, &ambient_spm, sizeof(ambient_spm))) + printf ("FAILED: set AMBIENT_SPM = %ds\n", (int)pgm_to_secs (ambient_spm)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM, &heartbeat_spm, sizeof(heartbeat_spm))) + { + char buffer[1024]; + sprintf (buffer, "%d", heartbeat_spm[0]); + for (unsigned i = 1; i < G_N_ELEMENTS(heartbeat_spm); i++) { + char t[1024]; + sprintf (t, ", %d", heartbeat_spm[i]); + strcat (buffer, t); + } + printf ("FAILED: set HEARTBEAT_SPM = { %s }\n", buffer); + } + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry, sizeof(peer_expiry))) + printf ("FAILED: set PEER_EXPIRY = %ds\n",(int) pgm_to_secs (peer_expiry)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry, sizeof(spmr_expiry))) + printf ("FAILED: set SPMR_EXPIRY = %dms\n", (int)pgm_to_msecs (spmr_expiry)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl, sizeof(nak_bo_ivl))) + printf ("FAILED: set NAK_BO_IVL = %dms\n", (int)pgm_to_msecs (nak_bo_ivl)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl, sizeof(nak_rpt_ivl))) + printf ("FAILED: set NAK_RPT_IVL = %dms\n", (int)pgm_to_msecs (nak_rpt_ivl)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL, &nak_rdata_ivl, sizeof(nak_rdata_ivl))) + printf ("FAILED: set NAK_RDATA_IVL = %dms\n", (int)pgm_to_msecs (nak_rdata_ivl)); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES, &nak_data_retries, sizeof(nak_data_retries))) + printf ("FAILED: set NAK_DATA_RETRIES = %d\n", nak_data_retries); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES, &nak_ncf_retries, sizeof(nak_ncf_retries))) + printf ("FAILED: set NAK_NCF_RETRIES = %d\n", nak_ncf_retries); + +/* create global session identifier */ + struct pgm_sockaddr_t addr; + memset (&addr, 0, sizeof(addr)); + addr.sa_port = g_port; + addr.sa_addr.sport = 0; + if (!pgm_gsi_create_from_hostname (&addr.sa_addr.gsi, &pgm_err)) { + printf ("FAILED: pgm_gsi_create_from_hostname(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + } + +{ + char buffer[1024]; + pgm_tsi_print_r (&addr.sa_addr, buffer, sizeof(buffer)); + printf ("pgm_bind (sock:%p addr:{port:%d tsi:%s} err:%p)\n", + (gpointer)sess->sock, + addr.sa_port, buffer, + (gpointer)&pgm_err); +} + const bool status = sess->is_transport_fake ? + fake_pgm_bind (sess->sock, &addr, sizeof(addr), &pgm_err) : + pgm_bind (sess->sock, &addr, sizeof(addr), &pgm_err); + if (!status) { + printf ("FAILED: pgm_bind(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + pgm_error_free (pgm_err); + } else + puts ("READY"); +} + +static +void +session_connect ( + char* session_name + ) +{ + struct pgm_addrinfo_t hints = { + .ai_family = AF_INET + }, *res = NULL; + pgm_error_t* pgm_err = NULL; + +/* check that session exists */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + if (!pgm_getaddrinfo (g_network, &hints, &res, &pgm_err)) { + printf ("FAILED: pgm_getaddrinfo(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + pgm_error_free (pgm_err); + return; + } + +/* join IP multicast groups */ + for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_JOIN_GROUP, &res->ai_recv_addrs[i], sizeof(struct group_req))) + { + char group[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&res->ai_recv_addrs[i].gsr_group, sizeof(struct sockaddr_in), + group, sizeof(group), + NULL, 0, + NI_NUMERICHOST); + printf ("FAILED: join group (#%u %s)\n", (unsigned)res->ai_recv_addrs[i].gsr_interface, group); + } + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_SEND_GROUP, &res->ai_send_addrs[0], sizeof(struct group_req))) + { + char group[INET6_ADDRSTRLEN]; + getnameinfo ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, sizeof(struct sockaddr_in), + group, sizeof(group), + NULL, 0, + NI_NUMERICHOST); + printf ("FAILED: send group (#%u %s)\n", (unsigned)res->ai_send_addrs[0].gsr_interface, group); + } + pgm_freeaddrinfo (res); + +/* set IP parameters */ + const int non_blocking = 1, + no_multicast_loop = 0, + multicast_hops = 16, + dscp = 0x2e << 2; /* Expedited Forwarding PHB for network elements, no ECN. */ + + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_MULTICAST_LOOP, &no_multicast_loop, sizeof(no_multicast_loop))) + puts ("FAILED: disable multicast loop"); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops))) + printf ("FAILED: set TTL = %d\n", multicast_hops); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_TOS, &dscp, sizeof(dscp))) + printf ("FAILED: set TOS = 0x%x\n", dscp); + if (!pgm_setsockopt (sess->sock, IPPROTO_PGM, PGM_NOBLOCK, &non_blocking, sizeof(non_blocking))) + puts ("FAILED: set non-blocking sockets"); + + const bool status = sess->is_transport_fake ? + fake_pgm_connect (sess->sock, &pgm_err) : + pgm_connect (sess->sock, &pgm_err); + if (!status) { + printf ("FAILED: pgm_connect(): %s\n", (pgm_err && pgm_err->message) ? pgm_err->message : "(null)"); + return; + } + + if (sess->is_transport_fake) + { +/* add receive socket(s) to event manager */ + sess->recv_channel = g_io_channel_unix_new (sess->sock->recv_sock); + + GSource *source; + source = g_io_create_watch (sess->recv_channel, G_IO_IN); + g_source_set_callback (source, (GSourceFunc)on_io_data, sess->sock, NULL); + g_source_attach (source, NULL); + g_source_unref (source); + } + else + { + pgm_async_create (&sess->async, sess->sock, 0); + pgm_async_add_watch (sess->async, on_data, sess); + } + + puts ("READY"); +} + +static inline +gssize +pgm_sendto_hops ( + pgm_sock_t* sock, + G_GNUC_UNUSED gboolean rl, + gboolean ra, + const int hops, + const void* buf, + gsize len, + const struct sockaddr* to, + socklen_t tolen + ) +{ + const int send_sock = ra ? sock->send_with_router_alert_sock : sock->send_sock; + pgm_mutex_lock (&sock->send_mutex); + const ssize_t sent = sendto (send_sock, buf, len, 0, to, tolen); + pgm_mutex_unlock (&sock->send_mutex); + return sent > 0 ? (gssize)len : (gssize)sent; +} + +static +int +pgm_reset_heartbeat_spm ( + pgm_sock_t* sock + ) +{ + int retval = 0; + + pgm_mutex_lock (&sock->timer_mutex); + +/* re-set spm timer */ + sock->spm_heartbeat_state = 1; + sock->next_heartbeat_spm = pgm_time_update_now() + sock->spm_heartbeat_interval[sock->spm_heartbeat_state++]; + +/* prod timer thread if sleeping */ + if (pgm_time_after( sock->next_poll, sock->next_heartbeat_spm )) + sock->next_poll = sock->next_heartbeat_spm; + + pgm_mutex_unlock (&sock->timer_mutex); + + return retval; +} + +static inline +int +brokn_send_apdu_unlocked ( + pgm_sock_t* sock, + const gchar* buf, + gsize count, + gsize* bytes_written + ) +{ + guint32 opt_sqn = pgm_txw_next_lead(sock->window); + guint packets = 0; + guint bytes_sent = 0; + guint data_bytes_sent = 0; + + pgm_mutex_lock (&sock->source_mutex); + + do { +/* retrieve packet storage from transmit window */ + int header_length = sizeof(struct pgm_header) + sizeof(struct pgm_data) + + sizeof(struct pgm_opt_length) + /* includes header */ + sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fragment); + int tsdu_length = MIN(sock->max_tpdu - sock->iphdr_len - header_length, count - data_bytes_sent); + int tpdu_length = header_length + tsdu_length; + + struct pgm_sk_buff_t* skb = pgm_alloc_skb (tsdu_length); + pgm_skb_put (skb, tpdu_length); + + skb->pgm_header = (struct pgm_header*)skb->data; + memcpy (skb->pgm_header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + skb->pgm_header->pgm_sport = sock->tsi.sport; + skb->pgm_header->pgm_dport = sock->dport; + skb->pgm_header->pgm_type = PGM_ODATA; + skb->pgm_header->pgm_options = PGM_OPT_PRESENT; + skb->pgm_header->pgm_tsdu_length = g_htons (tsdu_length); + +/* ODATA */ + skb->pgm_data = (struct pgm_data*)(skb->pgm_header + 1); + skb->pgm_data->data_sqn = g_htonl (pgm_txw_next_lead(sock->window)); + skb->pgm_data->data_trail = g_htonl (pgm_txw_trail(sock->window)); + +/* OPT_LENGTH */ + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(skb->pgm_data + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = g_htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment) ); +/* OPT_FRAGMENT */ + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment); + skb->pgm_opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + skb->pgm_opt_fragment->opt_reserved = 0; + skb->pgm_opt_fragment->opt_sqn = g_htonl (opt_sqn); + skb->pgm_opt_fragment->opt_frag_off = g_htonl (data_bytes_sent); + skb->pgm_opt_fragment->opt_frag_len = g_htonl (count); + +/* TODO: the assembly checksum & copy routine is faster than memcpy & pgm_cksum on >= opteron hardware */ + skb->pgm_header->pgm_checksum = 0; + + int pgm_header_len = (char*)(skb->pgm_opt_fragment + 1) - (char*)skb->pgm_header; + guint32 unfolded_header = pgm_csum_partial ((const void*)skb->pgm_header, pgm_header_len, 0); + guint32 unfolded_odata = pgm_csum_partial_copy ((const void*)(buf + data_bytes_sent), (void*)(skb->pgm_opt_fragment + 1), tsdu_length, 0); + skb->pgm_header->pgm_checksum = pgm_csum_fold (pgm_csum_block_add (unfolded_header, unfolded_odata, pgm_header_len)); + +/* add to transmit window */ + pgm_spinlock_lock (&sock->txw_spinlock); + pgm_txw_add (sock->window, skb); + pgm_spinlock_unlock (&sock->txw_spinlock); + +/* do not send send packet */ + if (packets != 1) + pgm_sendto_hops (sock, + TRUE, + FALSE, + sock->hops, + skb->data, + tpdu_length, + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + +/* save unfolded odata for retransmissions */ + *(guint32*)&skb->cb = unfolded_odata; + + packets++; + bytes_sent += tpdu_length + sock->iphdr_len; + data_bytes_sent += tsdu_length; + + } while (data_bytes_sent < count); + + if (data_bytes_sent > 0 && bytes_written) + *bytes_written = data_bytes_sent; + +/* release txw lock here in order to allow spms to lock mutex */ + pgm_mutex_unlock (&sock->source_mutex); + pgm_reset_heartbeat_spm (sock); + return PGM_IO_STATUS_NORMAL; +} + +static +int +brokn_send ( + pgm_sock_t* sock, + const gchar* data, + gsize len, + gsize* bytes_written + ) +{ + if ( len <= ( sock->max_tpdu - ( sizeof(struct pgm_header) + + sizeof(struct pgm_data) ) ) ) + { + puts ("FAILED: cannot send brokn single TPDU length APDU"); + return PGM_IO_STATUS_ERROR; + } + + return brokn_send_apdu_unlocked (sock, data, len, bytes_written); +} + +static +void +session_send ( + char* session_name, + char* string, + gboolean is_brokn /* send broken apdu */ + ) +{ +/* check that session exists */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + +/* send message */ + int status; + gsize stringlen = strlen(string) + 1; + int n_fds = 1; + struct pollfd fds[ n_fds ]; + struct timeval tv; + int timeout; +again: + if (is_brokn) + status = brokn_send (sess->sock, string, stringlen, NULL); + else + status = pgm_send (sess->sock, string, stringlen, NULL); + switch (status) { + case PGM_IO_STATUS_NORMAL: + puts ("READY"); + break; + case PGM_IO_STATUS_TIMER_PENDING: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (sess->sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen); + } + goto block; + case PGM_IO_STATUS_RATE_LIMITED: + { + socklen_t optlen = sizeof (tv); + pgm_getsockopt (sess->sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen); + } +/* fall through */ + case PGM_IO_STATUS_WOULD_BLOCK: +block: + timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); + memset (fds, 0, sizeof(fds)); + pgm_poll_info (sess->sock, fds, &n_fds, POLLOUT); + poll (fds, n_fds, timeout /* ms */); + goto again; + default: + puts ("FAILED: pgm_send()"); + break; + } +} + +static +void +session_destroy ( + char* session_name + ) +{ +/* check that session exists */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + +/* remove from hash table */ + g_hash_table_remove (g_sessions, session_name); + +/* close down receive side first to stop new data incoming */ + if (sess->recv_channel) { + puts ("closing receive channel."); + + GError *err = NULL; + g_io_channel_shutdown (sess->recv_channel, TRUE, &err); + + if (err) { + g_warning ("i/o shutdown error %i %s", err->code, err->message); + } + +/* TODO: flush GLib main loop with context specific to the recv channel */ + + sess->recv_channel = NULL; + } + + if (sess->is_transport_fake) + { + fake_pgm_close (sess->sock, TRUE); + } + else + { + pgm_close (sess->sock, TRUE); + } + sess->sock = NULL; + g_free (sess->name); + sess->name = NULL; + g_free (sess); + + puts ("READY"); +} + +static +void +net_send_data ( + char* session_name, + guint8 pgm_type, /* PGM_ODATA or PGM_RDATA */ + guint32 data_sqn, + guint32 txw_trail, + char* string + ) +{ +/* check that session exists */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + pgm_sock_t* sock = sess->sock; + +/* payload is string including terminating null. */ + int count = strlen(string) + 1; + +/* send */ + int retval = 0; + int tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_data) + count; + + gchar buf[ tpdu_length ]; + + struct pgm_header *header = (struct pgm_header*)buf; + struct pgm_data *data = (struct pgm_data*)(header + 1); + memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + header->pgm_sport = sock->tsi.sport; + header->pgm_dport = sock->dport; + header->pgm_type = pgm_type; + header->pgm_options = 0; + header->pgm_tsdu_length = g_htons (count); + +/* O/RDATA */ + data->data_sqn = g_htonl (data_sqn); + data->data_trail = g_htonl (txw_trail); + + memcpy (data + 1, string, count); + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); + + pgm_mutex_lock (&sock->send_mutex); + retval = sendto (sock->send_sock, + header, + tpdu_length, + 0, /* not expecting a reply */ + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + pgm_mutex_unlock (&sock->send_mutex); + + puts ("READY"); +} + +/* differs to net_send_data in that the string parameters contains every payload + * for the transmission group. this is required to calculate the correct parity + * as the fake transport does not own a transmission window. + * + * all payloads must be the same length unless variable TSDU support is enabled. + */ +static +void +net_send_parity ( + char* session_name, + guint8 pgm_type, /* PGM_ODATA or PGM_RDATA */ + guint32 data_sqn, + guint32 txw_trail, + char* string + ) +{ +/* check that session exists */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + pgm_sock_t* sock = sess->sock; + +/* split string into individual payloads */ + guint16 parity_length = 0; + gchar** src; + src = g_strsplit (string, " ", sock->rs_k); + +/* payload is string including terminating null. */ + parity_length = strlen(*src) + 1; + +/* check length of payload array */ + gboolean is_var_pktlen = FALSE; + guint i; + for (i = 0; src[i]; i++) + { + guint tsdu_length = strlen(src[i]) + 1; + if (tsdu_length != parity_length) { + is_var_pktlen = TRUE; + + if (tsdu_length > parity_length) + parity_length = tsdu_length; + } + } + + if ( i != sock->rs_k ) { + printf ("FAILED: payload array length %u, whilst rs_k is %u.\n", i, sock->rs_k); + return; + } + +/* add padding and append TSDU lengths */ + if (is_var_pktlen) + { + for (i = 0; src[i]; i++) + { + guint tsdu_length = strlen(src[i]) + 1; + gchar* new_string = g_new0 (gchar, parity_length + 2); + strncpy (new_string, src[i], parity_length); + *(guint16*)(new_string + parity_length) = tsdu_length; + g_free (src[i]); + src[i] = new_string; + } + parity_length += 2; + } + +/* calculate FEC block offset */ + guint32 tg_sqn_mask = 0xffffffff << sock->tg_sqn_shift; + guint rs_h = data_sqn & ~tg_sqn_mask; + +/* send */ + int retval = 0; + int tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_data) + parity_length; + + gchar buf[ tpdu_length ]; + + struct pgm_header *header = (struct pgm_header*)buf; + struct pgm_data *data = (struct pgm_data*)(header + 1); + memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + header->pgm_sport = sock->tsi.sport; + header->pgm_dport = sock->dport; + header->pgm_type = pgm_type; + header->pgm_options = is_var_pktlen ? (PGM_OPT_PARITY | PGM_OPT_VAR_PKTLEN) : PGM_OPT_PARITY; + header->pgm_tsdu_length = g_htons (parity_length); + +/* O/RDATA */ + data->data_sqn = g_htonl (data_sqn); + data->data_trail = g_htonl (txw_trail); + + memset (data + 1, 0, parity_length); + pgm_rs_t rs; + pgm_rs_create (&rs, sock->rs_n, sock->rs_k); + pgm_rs_encode (&rs, (const pgm_gf8_t**)src, sock->rs_k + rs_h, (pgm_gf8_t*)(data + 1), parity_length); + pgm_rs_destroy (&rs); + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); + + pgm_mutex_lock (&sock->send_mutex); + retval = sendto (sock->send_sock, + header, + tpdu_length, + 0, /* not expecting a reply */ + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + pgm_mutex_unlock (&sock->send_mutex); + + g_strfreev (src); + src = NULL; + + puts ("READY"); +} + +static +void +net_send_spm ( + char* session_name, + guint32 spm_sqn, + guint32 txw_trail, + guint32 txw_lead, + gboolean proactive_parity, + gboolean ondemand_parity, + guint k + ) +{ +/* check that session exists */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + pgm_sock_t* sock = sess->sock; + +/* send */ + int retval = 0; + int tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_spm); + + if (proactive_parity || ondemand_parity) { + tpdu_length += sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_parity_prm); + } + + gchar buf[ tpdu_length ]; + + struct pgm_header *header = (struct pgm_header*)buf; + struct pgm_spm *spm = (struct pgm_spm*)(header + 1); + memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + header->pgm_sport = sock->tsi.sport; + header->pgm_dport = sock->dport; + header->pgm_type = PGM_SPM; + header->pgm_options = (proactive_parity || ondemand_parity) ? (PGM_OPT_PRESENT | PGM_OPT_NETWORK) : 0; + header->pgm_tsdu_length = 0; + +/* SPM */ + spm->spm_sqn = g_htonl (spm_sqn); + spm->spm_trail = g_htonl (txw_trail); + spm->spm_lead = g_htonl (txw_lead); + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->send_addr, (char*)&spm->spm_nla_afi); + + if (proactive_parity || ondemand_parity) { + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(spm + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = g_htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_parity_prm) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_PARITY_PRM | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_parity_prm); + struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1); + opt_parity_prm->opt_reserved = (proactive_parity ? PGM_PARITY_PRM_PRO : 0) | + (ondemand_parity ? PGM_PARITY_PRM_OND : 0); + opt_parity_prm->parity_prm_tgs = g_htonl (k); + } + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); + + retval = sendto (sock->send_sock, + header, + tpdu_length, + 0, /* not expecting a reply */ + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + puts ("READY"); +} + +static +void +net_send_spmr ( + char* session_name, + pgm_tsi_t* tsi + ) +{ +/* check that session exists */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + + pgm_sock_t* sock = sess->sock; + +/* check that the peer exists */ + pgm_peer_t* peer = pgm_hashtable_lookup (sock->peers_hashtable, tsi); + struct sockaddr_storage peer_nla; + pgm_gsi_t* peer_gsi; + guint16 peer_sport; + + if (peer == NULL) { +/* ourself */ + if (pgm_tsi_equal (tsi, &sock->tsi)) + { + peer_gsi = &sock->tsi.gsi; + peer_sport = sock->tsi.sport; + } + else + { + printf ("FAILED: peer \"%s\" not found\n", pgm_tsi_print (tsi)); + return; + } + } + else + { + memcpy (&peer_nla, &peer->local_nla, sizeof(struct sockaddr_storage)); + peer_gsi = &peer->tsi.gsi; + peer_sport = peer->tsi.sport; + } + +/* send */ + int retval = 0; + int tpdu_length = sizeof(struct pgm_header); + gchar buf[ tpdu_length ]; + + struct pgm_header *header = (struct pgm_header*)buf; + memcpy (header->pgm_gsi, peer_gsi, sizeof(pgm_gsi_t)); + header->pgm_sport = sock->dport; + header->pgm_dport = peer_sport; + header->pgm_type = PGM_SPMR; + header->pgm_options = 0; + header->pgm_tsdu_length = 0; + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); + + pgm_mutex_lock (&sock->send_mutex); +/* TTL 1 */ + pgm_sockaddr_multicast_hops (sock->send_sock, sock->send_gsr.gsr_group.ss_family, 1); + retval = sendto (sock->send_sock, + header, + tpdu_length, + 0, /* not expecting a reply */ + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); +/* default TTL */ + pgm_sockaddr_multicast_hops (sock->send_sock, sock->send_gsr.gsr_group.ss_family, sock->hops); + + if (!pgm_tsi_equal (tsi, &sock->tsi)) + { + retval = sendto (sock->send_sock, + header, + tpdu_length, + 0, /* not expecting a reply */ + (struct sockaddr*)&peer_nla, + pgm_sockaddr_len((struct sockaddr*)&peer_nla)); + } + + pgm_mutex_unlock (&sock->send_mutex); + + puts ("READY"); +} + +/* Send a NAK on a valid transport. A fake transport would need to specify the senders NLA, + * we use the peer list to bypass extracting it from the monitor output. + */ + +static +void +net_send_ncf ( + char* session_name, + pgm_tsi_t* tsi, + struct pgm_sqn_list_t* sqn_list /* list of sequence numbers */ + ) +{ +/* check that session exists */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + +/* check that the peer exists */ + pgm_sock_t* sock = sess->sock; + pgm_peer_t* peer = pgm_hashtable_lookup (sock->peers_hashtable, tsi); + if (peer == NULL) { + printf ("FAILED: peer \"%s\" not found\n", pgm_tsi_print (tsi)); + return; + } + +/* check for valid nla */ + if (((struct sockaddr*)&peer->nla)->sa_family == 0 ) { + puts ("FAILED: peer NLA unknown, cannot send NCF."); + return; + } + +/* send */ + int retval = 0; + int tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); + + if (sqn_list->len > 1) { + tpdu_length += sizeof(struct pgm_opt_length) + /* includes header */ + sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(guint32) ); + } + + gchar buf[ tpdu_length ]; + + struct pgm_header *header = (struct pgm_header*)buf; + struct pgm_nak *ncf = (struct pgm_nak*)(header + 1); + memcpy (header->pgm_gsi, &sock->tsi.gsi, sizeof(pgm_gsi_t)); + + struct sockaddr_storage peer_nla; + memcpy (&peer_nla, &peer->nla, sizeof(struct sockaddr_storage)); + +/* dport & sport swap over for a nak */ + header->pgm_sport = sock->tsi.sport; + header->pgm_dport = sock->dport; + header->pgm_type = PGM_NCF; + header->pgm_options = (sqn_list->len > 1) ? (PGM_OPT_PRESENT | PGM_OPT_NETWORK) : 0; + header->pgm_tsdu_length = 0; + +/* NCF */ + ncf->nak_sqn = g_htonl (sqn_list->sqn[0]); + +/* source nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&peer_nla, (char*)&ncf->nak_src_nla_afi); + +/* group nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->recv_gsr[0].gsr_group, (char*)&ncf->nak_grp_nla_afi); + +/* OPT_NAK_LIST */ + if (sqn_list->len > 1) + { + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(ncf + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = g_htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(guint32) ) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(guint32) ); + struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); + opt_nak_list->opt_reserved = 0; + for (guint i = 1; i < sqn_list->len; i++) { + opt_nak_list->opt_sqn[i-1] = g_htonl (sqn_list->sqn[i]); + } + } + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); + + retval = sendto (sock->send_with_router_alert_sock, + header, + tpdu_length, + 0, /* not expecting a reply */ + (struct sockaddr*)&sock->send_gsr.gsr_group, + pgm_sockaddr_len((struct sockaddr*)&sock->send_gsr.gsr_group)); + + puts ("READY"); +} + +static +void +net_send_nak ( + char* session_name, + pgm_tsi_t* tsi, + struct pgm_sqn_list_t* sqn_list, /* list of sequence numbers */ + gboolean is_parity /* TRUE = parity, FALSE = selective */ + ) +{ +/* check that session exists */ + struct sim_session* sess = g_hash_table_lookup (g_sessions, session_name); + if (sess == NULL) { + printf ("FAILED: session '%s' not found\n", session_name); + return; + } + +/* check that the peer exists */ + pgm_sock_t* sock = sess->sock; + pgm_peer_t* peer = pgm_hashtable_lookup (sock->peers_hashtable, tsi); + if (peer == NULL) { + printf ("FAILED: peer \"%s\" not found\n", pgm_tsi_print(tsi)); + return; + } + +/* send */ + int retval = 0; + int tpdu_length = sizeof(struct pgm_header) + sizeof(struct pgm_nak); + + if (sqn_list->len > 1) { + tpdu_length += sizeof(struct pgm_opt_length) + /* includes header */ + sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(guint32) ); + } + + gchar buf[ tpdu_length ]; + + struct pgm_header *header = (struct pgm_header*)buf; + struct pgm_nak *nak = (struct pgm_nak*)(header + 1); + memcpy (header->pgm_gsi, &peer->tsi.gsi, sizeof(pgm_gsi_t)); + + guint16 peer_sport = peer->tsi.sport; + struct sockaddr_storage peer_nla; + memcpy (&peer_nla, &peer->nla, sizeof(struct sockaddr_storage)); + +/* dport & sport swap over for a nak */ + header->pgm_sport = sock->dport; + header->pgm_dport = peer_sport; + header->pgm_type = PGM_NAK; + if (is_parity) { + header->pgm_options = (sqn_list->len > 1) ? (PGM_OPT_PRESENT | PGM_OPT_NETWORK | PGM_OPT_PARITY) + : PGM_OPT_PARITY; + } else { + header->pgm_options = (sqn_list->len > 1) ? (PGM_OPT_PRESENT | PGM_OPT_NETWORK) : 0; + } + header->pgm_tsdu_length = 0; + +/* NAK */ + nak->nak_sqn = g_htonl (sqn_list->sqn[0]); + +/* source nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&peer_nla, (char*)&nak->nak_src_nla_afi); + +/* group nla */ + pgm_sockaddr_to_nla ((struct sockaddr*)&sock->recv_gsr[0].gsr_group, (char*)&nak->nak_grp_nla_afi); + +/* OPT_NAK_LIST */ + if (sqn_list->len > 1) + { + struct pgm_opt_length* opt_len = (struct pgm_opt_length*)(nak + 1); + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = g_htons ( sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(guint32) ) ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_NAK_LIST | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_nak_list) + + ( (sqn_list->len-1) * sizeof(guint32) ); + struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1); + opt_nak_list->opt_reserved = 0; + for (guint i = 1; i < sqn_list->len; i++) { + opt_nak_list->opt_sqn[i-1] = g_htonl (sqn_list->sqn[i]); + } + } + + header->pgm_checksum = 0; + header->pgm_checksum = pgm_csum_fold (pgm_csum_partial ((char*)header, tpdu_length, 0)); + + retval = sendto (sock->send_with_router_alert_sock, + header, + tpdu_length, + 0, /* not expecting a reply */ + (struct sockaddr*)&peer_nla, + pgm_sockaddr_len((struct sockaddr*)&peer_nla)); + + puts ("READY"); +} + +static +int +on_data ( + gpointer data, + G_GNUC_UNUSED guint len, + G_GNUC_UNUSED gpointer user_data + ) +{ + printf ("DATA: %s\n", (char*)data); + fflush (stdout); + + return 0; +} + +/* process input commands from stdin/fd + */ + +static +gboolean +on_stdin_data ( + GIOChannel* source, + G_GNUC_UNUSED GIOCondition condition, + G_GNUC_UNUSED gpointer data + ) +{ + gchar* str = NULL; + gsize len = 0; + gsize term = 0; + GError* err = NULL; + + g_io_channel_read_line (source, &str, &len, &term, &err); + if (len > 0) { + if (term) str[term] = 0; + +/* quit */ + if (strcmp(str, "quit") == 0) + { + g_main_loop_quit(g_loop); + goto out; + } + + regex_t preg; + regmatch_t pmatch[10]; + const char *re; + +/* endpoint simulator specific: */ + +/* send odata or rdata */ + re = "^net[[:space:]]+send[[:space:]]+([or])data[[:space:]]+" + "([[:alnum:]]+)[[:space:]]+" /* transport */ + "([0-9]+)[[:space:]]+" /* sequence number */ + "([0-9]+)[[:space:]]+" /* txw_trail */ + "([[:alnum:]]+)$"; /* payload */ + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + guint8 pgm_type = *(str + pmatch[1].rm_so) == 'o' ? PGM_ODATA : PGM_RDATA; + + char *name = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); + name[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; + + char* p = str + pmatch[3].rm_so; + guint32 data_sqn = strtoul (p, &p, 10); + + p = str + pmatch[4].rm_so; + guint txw_trail = strtoul (p, &p, 10); + + char *string = g_memdup (str + pmatch[5].rm_so, pmatch[5].rm_eo - pmatch[5].rm_so + 1 ); + string[ pmatch[5].rm_eo - pmatch[5].rm_so ] = 0; + + net_send_data (name, pgm_type, data_sqn, txw_trail, string); + + g_free (name); + g_free (string); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* send parity odata or rdata */ + re = "^net[[:space:]]+send[[:space:]]+parity[[:space:]]+([or])data[[:space:]]+" + "([[:alnum:]]+)[[:space:]]+" /* transport */ + "([0-9]+)[[:space:]]+" /* sequence number */ + "([0-9]+)[[:space:]]+" /* txw_trail */ + "([a-z0-9 ]+)$"; /* payloads */ + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + guint8 pgm_type = *(str + pmatch[1].rm_so) == 'o' ? PGM_ODATA : PGM_RDATA; + + char *name = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); + name[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; + + char* p = str + pmatch[3].rm_so; + guint32 data_sqn = strtoul (p, &p, 10); + + p = str + pmatch[4].rm_so; + guint txw_trail = strtoul (p, &p, 10); + +/* ideally confirm number of payloads matches sess->sock::rs_k ... */ + char *string = g_memdup (str + pmatch[5].rm_so, pmatch[5].rm_eo - pmatch[5].rm_so + 1 ); + string[ pmatch[5].rm_eo - pmatch[5].rm_so ] = 0; + + net_send_parity (name, pgm_type, data_sqn, txw_trail, string); + + g_free (name); + g_free (string); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* send spm */ + re = "^net[[:space:]]+send[[:space:]]+spm[[:space:]]+" + "([[:alnum:]]+)[[:space:]]+" /* transport */ + "([0-9]+)[[:space:]]+" /* spm sequence number */ + "([0-9]+)[[:space:]]+" /* txw_trail */ + "([0-9]+)" /* txw_lead */ + "([[:space:]]+pro-active)?" /* pro-active parity */ + "([[:space:]]+on-demand)?" /* on-demand parity */ + "([[:space:]]+[0-9]+)?$"; /* transmission group size */ + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + char* p = str + pmatch[2].rm_so; + guint32 spm_sqn = strtoul (p, &p, 10); + + p = str + pmatch[3].rm_so; + guint txw_trail = strtoul (p, &p, 10); + + p = str + pmatch[4].rm_so; + guint txw_lead = strtoul (p, &p, 10); + + gboolean proactive_parity = pmatch[5].rm_eo > pmatch[5].rm_so; + gboolean ondemand_parity = pmatch[6].rm_eo > pmatch[6].rm_so; + + p = str + pmatch[7].rm_so; + guint k = (pmatch[7].rm_eo > pmatch[7].rm_so) ? strtoul (p, &p, 10) : 0; + + net_send_spm (name, spm_sqn, txw_trail, txw_lead, proactive_parity, ondemand_parity, k); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* send spmr */ + re = "^net[[:space:]]+send[[:space:]]+spmr[[:space:]]+" + "([[:alnum:]]+)[[:space:]]+" /* transport */ + "([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)$"; /* TSI */ + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + pgm_tsi_t tsi; + char *p = str + pmatch[2].rm_so; + tsi.gsi.identifier[0] = strtol (p, &p, 10); + ++p; + tsi.gsi.identifier[1] = strtol (p, &p, 10); + ++p; + tsi.gsi.identifier[2] = strtol (p, &p, 10); + ++p; + tsi.gsi.identifier[3] = strtol (p, &p, 10); + ++p; + tsi.gsi.identifier[4] = strtol (p, &p, 10); + ++p; + tsi.gsi.identifier[5] = strtol (p, &p, 10); + ++p; + tsi.sport = g_htons ( strtol (p, NULL, 10) ); + + net_send_spmr (name, &tsi); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* send nak/ncf */ + re = "^net[[:space:]]+send[[:space:]](parity[[:space:]])?n(ak|cf)[[:space:]]+" + "([[:alnum:]]+)[[:space:]]+" /* transport */ + "([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)[[:space:]]+" /* TSI */ + "([0-9,]+)$"; /* sequence number or list */ + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[3].rm_so, pmatch[3].rm_eo - pmatch[3].rm_so + 1 ); + name[ pmatch[3].rm_eo - pmatch[3].rm_so ] = 0; + + pgm_tsi_t tsi; + char *p = str + pmatch[4].rm_so; + tsi.gsi.identifier[0] = strtol (p, &p, 10); + ++p; + tsi.gsi.identifier[1] = strtol (p, &p, 10); + ++p; + tsi.gsi.identifier[2] = strtol (p, &p, 10); + ++p; + tsi.gsi.identifier[3] = strtol (p, &p, 10); + ++p; + tsi.gsi.identifier[4] = strtol (p, &p, 10); + ++p; + tsi.gsi.identifier[5] = strtol (p, &p, 10); + ++p; + tsi.sport = g_htons ( strtol (p, NULL, 10) ); + +/* parse list of sequence numbers */ + struct pgm_sqn_list_t sqn_list; + sqn_list.len = 0; + { + char* saveptr = NULL; + for (p = str + pmatch[5].rm_so; ; p = NULL) { + char* token = strtok_r (p, ",", &saveptr); + if (!token) break; + sqn_list.sqn[sqn_list.len++] = strtoul (token, NULL, 10); + } + } + + if ( *(str + pmatch[2].rm_so) == 'a' ) + { + net_send_nak (name, &tsi, &sqn_list, (pmatch[1].rm_eo > pmatch[1].rm_so)); + } + else + { + net_send_ncf (name, &tsi, &sqn_list); + } + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/** same as test application: **/ + +/* create transport */ + re = "^create[[:space:]]+(fake[[:space:]]+)?([[:alnum:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); + name[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; + + session_create (name, (pmatch[1].rm_eo > pmatch[1].rm_so)); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* enable Reed-Solomon Forward Error Correction */ + re = "^set[[:space:]]+([[:alnum:]]+)[[:space:]]+FEC[[:space:]]+RS[[:space:]]*\\([[:space:]]*([0-9]+)[[:space:]]*,[[:space:]]*([0-9]+)[[:space:]]*\\)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + char *p = str + pmatch[2].rm_so; + *(str + pmatch[2].rm_eo) = 0; + guint n = strtol (p, &p, 10); + p = str + pmatch[3].rm_so; + *(str + pmatch[3].rm_eo) = 0; + guint k = strtol (p, &p, 10); + session_set_fec (name, n, k); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* bind socket */ + re = "^bind[[:space:]]+([[:alnum:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + session_bind (name); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* connect socket */ + re = "^connect[[:space:]]+([[:alnum:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + session_connect (name); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* send packet */ + re = "^send[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + char *string = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); + string[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; + + session_send (name, string, FALSE); + + g_free (name); + g_free (string); + regfree (&preg); + goto out; + } + regfree (&preg); + + re = "^send[[:space:]]+(brokn[[:space:]]+)?([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]+x[[:space:]]([0-9]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so + 1 ); + name[ pmatch[2].rm_eo - pmatch[2].rm_so ] = 0; + + char* p = str + pmatch[4].rm_so; + int factor = strtol (p, &p, 10); + int src_len = pmatch[3].rm_eo - pmatch[3].rm_so; + char *string = g_malloc ( (factor * src_len) + 1 ); + for (int i = 0; i < factor; i++) + { + memcpy (string + (i * src_len), str + pmatch[3].rm_so, src_len); + } + string[ factor * src_len ] = 0; + + session_send (name, string, (pmatch[1].rm_eo > pmatch[1].rm_so)); + + g_free (name); + g_free (string); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* destroy transport */ + re = "^destroy[[:space:]]+([[:alnum:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *name = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + name[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + + session_destroy (name); + + g_free (name); + regfree (&preg); + goto out; + } + regfree (&preg); + +/* set PGM network */ + re = "^set[[:space:]]+network[[:space:]]+([[:print:]]*;[[:print:]]+)$"; + regcomp (&preg, re, REG_EXTENDED); + if (0 == regexec (&preg, str, G_N_ELEMENTS(pmatch), pmatch, 0)) + { + char *pgm_network = g_memdup (str + pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so + 1 ); + pgm_network[ pmatch[1].rm_eo - pmatch[1].rm_so ] = 0; + g_network = pgm_network; + puts ("READY"); + + regfree (&preg); + goto out; + } + regfree (&preg); + + printf ("unknown command: %s\n", str); + } + +out: + fflush (stdout); + g_free (str); + return TRUE; +} + +/* idle log notification + */ + +static +gboolean +on_mark ( + G_GNUC_UNUSED gpointer data + ) +{ + g_message ("-- MARK --"); + return TRUE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/spm.pl b/3rdparty/openpgm-svn-r1135/pgm/test/spm.pl new file mode 100755 index 0000000..5da52ac --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/spm.pl @@ -0,0 +1,43 @@ +#!/usr/bin/perl +# spm.pl +# 5.1.4. Ambient SPMs + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$app->connect; + +sub close_ssh { + $mon = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +print "app: ready.\n"; + +print "mon: wait for spm ...\n"; +$mon->wait_for_spm; +print "mon: received spm.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/spm_jump.pl b/3rdparty/openpgm-svn-r1135/pgm/test/spm_jump.pl new file mode 100755 index 0000000..4660a83 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/spm_jump.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl +# spm_jump.pl +# 6.2. Source Path Messages + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; +$sim->say ("net send spm ao 3200 90001 90000"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,005 at spm_sqn 20.\n"; +$sim->say ("net send spm ao 20 90001 90005"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/spm_jump2.pl b/3rdparty/openpgm-svn-r1135/pgm/test/spm_jump2.pl new file mode 100755 index 0000000..20d279e --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/spm_jump2.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl +# spm_jump2.pl +# 6.3. Data Recovery by Negative Acknowledgment + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,000 at spm_sqn 3200.\n"; +$sim->say ("net send spm ao 3200 90001 90000"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish SPM txw_trail 90,001 txw_lead 90,001 at spm_sqn 3201.\n"; +$sim->say ("net send spm ao 3201 90001 90001"); + +print "sim: waiting for valid NAK.\n"; +$sim->wait_for_nak; +print "sim: NAK received.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/spm_reception.pl b/3rdparty/openpgm-svn-r1135/pgm/test/spm_reception.pl new file mode 100755 index 0000000..5718305 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/spm_reception.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl +# spm_reception.pl +# 6.1. Data Reception + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); + +print "sim: publish SPM txw_trail 90,000.\n"; +$sim->say ("net send spm ao 1 90001 90000"); + +# no NAKs should be generated. +print "sim: waiting 2 seconds for erroneous NAKs ...\n"; +$sim->die_on_nak({ 'timeout' => 2 }); +print "sim: no NAKs received.\n"; + +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90000 ichigo"); +print "app: wait for data ...\n"; +my $data = $app->wait_for_data; +print "app: received data [$data].\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/spmr.pl b/3rdparty/openpgm-svn-r1135/pgm/test/spmr.pl new file mode 100755 index 0000000..690e2a5 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/spmr.pl @@ -0,0 +1,75 @@ +#!/usr/bin/perl +# spmr.pl +# 13.3.1. SPM Requests + +use strict; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); +print "sim: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +## capture GSI of test spp +$app->say ("send ao nashi"); +print "mon: wait for odata ...\n"; +my $odata = $mon->wait_for_odata; +print "mon: odata received.\n"; +my $t0 = [gettimeofday]; +my $elapsed; + +$mon->disconnect (1); + +## spm hearbeats are going to clear out the data, lets wait for some quiet +print "sim: wait for SPM interval > 5 seconds ...\n"; +do { + $sim->wait_for_spm; + $elapsed = tv_interval ( $t0, [gettimeofday] ); + print "sim: received SPM after $elapsed seconds.\n"; +} while ($elapsed < 5); + +print "sim: request SPM via SPMR.\n"; +$sim->say ("net send spmr ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort}"); +$t0 = [gettimeofday]; + +print "sim: wait for SPM ...\n"; +$sim->wait_for_spm; +$elapsed = tv_interval ( $t0, [gettimeofday] ); +print "sim: SPM received after $elapsed seconds.\n"; +die "SPM interval too large, indicates heartbeat not SPMR induced.\n" unless ($elapsed < 5.0); + +print "test completed successfully.\n"; + +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/spmr_after_spm.pl b/3rdparty/openpgm-svn-r1135/pgm/test/spmr_after_spm.pl new file mode 100755 index 0000000..c8eb045 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/spmr_after_spm.pl @@ -0,0 +1,80 @@ +#!/usr/bin/perl +# spmr.pl +# 13.3.1. SPM Requests + +use strict; +use Time::HiRes qw( gettimeofday tv_interval ); +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +## capture GSI of test spp +$app->say ("send ao nashi"); +print "mon: wait for odata ...\n"; +my $odata = $mon->wait_for_odata; +print "mon: odata received.\n"; +my $t0 = [gettimeofday]; +my $elapsed; + +## spm hearbeats are going to clear out the data, lets wait for some quiet +print "mon: wait for SPM interval > 5 seconds ...\n"; +do { + $mon->wait_for_spm; + $elapsed = tv_interval ( $t0, [gettimeofday] ); + print "mon: received SPM after $elapsed seconds.\n"; +} while ($elapsed < 5); + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); +print "sim: ready.\n"; + +## app needs to send packet for sim to learn of local NLA +$app->say ("send ao budo"); +print "sim: wait for odata ...\n"; +$odata = $sim->wait_for_odata; +print "sim: odata received.\n"; + +print "sim: request SPM via SPMR.\n"; +$sim->say ("net send spmr ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort}"); +$t0 = [gettimeofday]; + +print "sim: wait for SPM ...\n"; +$sim->wait_for_spm; +$elapsed = tv_interval ( $t0, [gettimeofday] ); +print "sim: SPM received after $elapsed seconds.\n"; +die "SPM interval too large, indicates heartbeat not SPMR induced.\n" unless ($elapsed < 5.0); + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/spmr_from_odata.pl b/3rdparty/openpgm-svn-r1135/pgm/test/spmr_from_odata.pl new file mode 100755 index 0000000..519518b --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/spmr_from_odata.pl @@ -0,0 +1,55 @@ +#!/usr/bin/perl +# spmr_from_odata.pl +# 13.3.1. SPM Requests + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$mon->say ("filter $config{app}{ip}"); +print "mon: ready.\n"; + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); +print "sim: publish ODATA sqn 90,001.\n"; +$sim->say ("net send odata ao 90001 90001 ringo"); + +my $data = $app->wait_for_data; +print "app: received data [$data].\n"; + +print "mon: wait for SPMR ...\n"; +$mon->wait_for_spmr; +print "mon: received SPMR.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/spmr_suppression.pl b/3rdparty/openpgm-svn-r1135/pgm/test/spmr_suppression.pl new file mode 100755 index 0000000..5b73c26 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/spmr_suppression.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl +# spmr_suppression.pl +# 13.3.1. SPM Requests + +use strict; +use PGM::Test; + +BEGIN { require "test.conf.pl"; } + +$| = 1; + +my $mon = PGM::Test->new(tag => 'mon', host => $config{mon}{host}, cmd => $config{mon}{cmd}); +my $sim = PGM::Test->new(tag => 'sim', host => $config{sim}{host}, cmd => $config{sim}{cmd}); +my $app = PGM::Test->new(tag => 'app', host => $config{app}{host}, cmd => $config{app}{cmd}); + +$mon->connect; +$sim->connect; +$app->connect; + +sub close_ssh { + $mon = $sim = $app = undef; + print "finished.\n"; +} + +$SIG{'INT'} = sub { print "interrupt caught.\n"; close_ssh(); }; + +$sim->say ("create fake ao"); +$sim->say ("bind ao"); +$sim->say ("connect ao"); +print "sim: publish ODATA sqn 90,001 to monitor for GSI.\n"; +$sim->say ("net send odata ao 90001 90001 ringo"); + +## capture GSI of test sim (not app!) +my $odata = $mon->wait_for_odata; +$mon->say ("filter $config{app}{ip}"); + +$app->say ("create ao"); +$app->say ("bind ao"); +$app->say ("connect ao"); +$app->say ("listen ao"); + +print "sim: re-publish ODATA sqn 90,001 to app.\n"; +$sim->say ("net send odata ao 90001 90001 ringo"); +$sim->say ("net send spmr ao $odata->{PGM}->{gsi}.$odata->{PGM}->{sourcePort}"); + +my $data = $app->wait_for_data; +print "app: received data [$data].\n"; + +print "mon: wait for erroneous SPMR ...\n"; +$mon->die_on_spmr({ 'timeout' => 2 }); +print "mon: no SPMR received.\n"; + +print "test completed successfully.\n"; + +$mon->disconnect (1); +$sim->disconnect; +$app->disconnect; +close_ssh; + +# eof diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/sudoers.example b/3rdparty/openpgm-svn-r1135/pgm/test/sudoers.example new file mode 100644 index 0000000..9212139 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/sudoers.example @@ -0,0 +1,26 @@ +# /etc/sudoers +# +# This file MUST be edited with the 'visudo' command as root. +# +# See the man page for details on how to write a sudoers file. +# Host alias specification + +# User alias specification +User_Alias PGM_USER = steve-o + +# Cmnd alias specification +Cmnd_Alias PGM_CONFORMANCE = /miru/projects/openpgm/pgm/ref/debug/test/* + +# Defaults + +Defaults !lecture,tty_tickets,!fqdn + +# User privilege specification +root ALL=(ALL) ALL + +# Members of the admin group may gain root privileges +%admin ALL=(ALL) ALL + + +# PGM testing +PGM_USER ALL = NOPASSWD: PGM_CONFORMANCE diff --git a/3rdparty/openpgm-svn-r1135/pgm/test/test.conf.pl b/3rdparty/openpgm-svn-r1135/pgm/test/test.conf.pl new file mode 100644 index 0000000..66860c6 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/test/test.conf.pl @@ -0,0 +1,27 @@ +# test.conf.pl +use vars qw ( %config ); + +%config = ( + msapp => { + host => 'momo', + ip => '10.6.28.34', + }, + app => { + host => 'ayaka', ip => '10.6.28.31', + cmd => '/miru/projects/openpgm/pgm/ref/release-Linux-x86_64/test/app', + network => 'eth0;239.192.0.1' +# host => 'ryoko', ip => '10.6.28.36', +# cmd => 'LD_LIBRARY_PATH=/opt/glib-sunstudio/lib:$LD_LIBRARY_PATH /miru/projects/openpgm/pgm/ref/release-SunOS-sun4u-sunstudio/test/app', +# network => 'eri0;239.192.0.1' + }, + mon => { + host => 'sora', + cmd => '/miru/projects/openpgm/pgm/ref/release-Linux-x86_64/test/monitor', + network => 'eth0;239.192.0.1' + }, + sim => { + host => 'kiku', + cmd => '/miru/projects/openpgm/pgm/ref/release-Linux-x86_64/test/sim', + network => 'eth0;239.192.0.1' + }, +); diff --git a/3rdparty/openpgm-svn-r1135/pgm/thread.c b/3rdparty/openpgm-svn-r1135/pgm/thread.c new file mode 100644 index 0000000..ad68ca3 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/thread.c @@ -0,0 +1,457 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * mutexes and locks. + * + * Copyright (c) 2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +//#define THREAD_DEBUG + + +/* Globals */ + +#if defined(_WIN32) && !defined(CONFIG_HAVE_WIN_COND) +static DWORD cond_event_tls = TLS_OUT_OF_INDEXES; +#endif + +static volatile uint32_t thread_ref_count = 0; + + +#ifndef _WIN32 +# define posix_check_err(err, name) \ + do { \ + const int save_error = (err); \ + if (PGM_UNLIKELY(save_error)) { \ + pgm_error ("file %s: line %d (%s): error '%s' during '%s'", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, \ + strerror (save_error), name); \ + } \ + } while (0) +# define posix_check_cmd(cmd) posix_check_err ((cmd), #cmd) +#else +# define win32_check_err(err, name) \ + do { \ + const bool save_error = (err); \ + if (PGM_UNLIKELY(!save_error)) { \ + pgm_error ("file %s: line %d (%s): error '%s' during '%s'", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, \ + pgm_wsastrerror (GetLastError ()), name); \ + } \ + } while (0) +# define win32_check_cmd(cmd) win32_check_err ((cmd), #cmd) +#endif /* !_WIN32 */ + + +/* only needed for Win32 pre-Vista read-write locks + */ +void +pgm_thread_init (void) +{ + if (pgm_atomic_exchange_and_add32 (&thread_ref_count, 1) > 0) + return; + +#if defined(_WIN32) && !defined(CONFIG_HAVE_WIN_COND) + win32_check_cmd (TLS_OUT_OF_INDEXES != (cond_event_tls = TlsAlloc ())); +#endif +} + +void +pgm_thread_shutdown (void) +{ + pgm_return_if_fail (pgm_atomic_read32 (&thread_ref_count) > 0); + + if (pgm_atomic_exchange_and_add32 (&thread_ref_count, (uint32_t)-1) != 1) + return; + +#if defined(_WIN32) && !defined(CONFIG_HAVE_WIN_COND) + TlsFree (cond_event_tls); +#endif +} + +void +pgm_mutex_init ( + pgm_mutex_t* mutex + ) +{ + pgm_assert (NULL != mutex); +#ifndef _WIN32 + posix_check_cmd (pthread_mutex_init (&mutex->pthread_mutex, NULL)); +#else + HANDLE handle; + win32_check_cmd (handle = CreateMutex (NULL, FALSE, NULL)); + mutex->win32_mutex = handle; +#endif /* !_WIN32 */ +} + +bool +pgm_mutex_trylock ( + pgm_mutex_t* mutex + ) +{ + pgm_assert (NULL != mutex); +#ifndef _WIN32 + const int result = pthread_mutex_trylock (&mutex->pthread_mutex); + if (EBUSY == result) + return FALSE; + posix_check_err (result, "pthread_mutex_trylock"); + return TRUE; +#else + DWORD result; + win32_check_cmd (WAIT_FAILED != (result = WaitForSingleObject (mutex->win32_mutex, 0))); + return WAIT_TIMEOUT != result; +#endif /* !_WIN32 */ +} + +void +pgm_mutex_free ( + pgm_mutex_t* mutex + ) +{ + pgm_assert (NULL != mutex); +#ifndef _WIN32 + posix_check_cmd (pthread_mutex_destroy (&mutex->pthread_mutex)); +#else + win32_check_cmd (CloseHandle (mutex->win32_mutex)); +#endif /* !_WIN32 */ +} + +void +pgm_spinlock_init ( + pgm_spinlock_t* spinlock + ) +{ + pgm_assert (NULL != spinlock); +#ifndef _WIN32 + posix_check_cmd (pthread_spin_init (&spinlock->pthread_spinlock, PTHREAD_PROCESS_PRIVATE)); +#else + InitializeCriticalSection (&spinlock->win32_spinlock); +#endif /* !_WIN32 */ +} + +bool +pgm_spinlock_trylock ( + pgm_spinlock_t* spinlock + ) +{ + pgm_assert (NULL != spinlock); +#ifndef _WIN32 + const int result = pthread_spin_trylock (&spinlock->pthread_spinlock); + if (EBUSY == result) + return FALSE; + posix_check_err (result, "pthread_spinlock_trylock"); + return TRUE; +#else + return TryEnterCriticalSection (&spinlock->win32_spinlock); +#endif /* !_WIN32 */ +} + +void +pgm_spinlock_free ( + pgm_spinlock_t* spinlock + ) +{ + pgm_assert (NULL != spinlock); +#ifndef _WIN32 +/* ignore return value */ + pthread_spin_destroy (&spinlock->pthread_spinlock); +#else + DeleteCriticalSection (&spinlock->win32_spinlock); +#endif /* !_WIN32 */ +} + +void +pgm_cond_init ( + pgm_cond_t* cond + ) +{ + pgm_assert (NULL != cond); +#ifndef _WIN32 + posix_check_cmd (pthread_cond_init (&cond->pthread_cond, NULL)); +#elif defined(CONFIG_HAVE_WIN_COND) + InitializeConditionVariable (&cond->win32_cond); +#else + cond->len = 0; + cond->allocated_len = pgm_nearest_power (1, 2 + 1); + cond->phandle = pgm_new (HANDLE, cond->allocated_len); + InitializeCriticalSection (&cond->win32_spinlock); +#endif /* !_WIN32 */ +} + +void +pgm_cond_signal ( + pgm_cond_t* cond + ) +{ + pgm_assert (NULL != cond); +#ifndef _WIN32 + pthread_cond_signal (&cond->pthread_cond); +#elif defined(CONFIG_HAVE_WIN_COND) + WakeConditionVariable (&cond->win32_cond); +#else + EnterCriticalSection (&cond->win32_spinlock); + if (cond->len > 0) { + SetEvent (cond->phandle[ 0 ]); + memmove (&cond->phandle[ 0 ], &cond->phandle[ 1 ], cond->len - 1); + cond->len--; + } + LeaveCriticalSection (&cond->win32_spinlock); +#endif /* !_WIN32 */ +} + +void +pgm_cond_broadcast ( + pgm_cond_t* cond + ) +{ + pgm_assert (NULL != cond); +#ifndef _WIN32 + pthread_cond_broadcast (&cond->pthread_cond); +#elif defined(CONFIG_HAVE_WIN_COND) + WakeAllConditionVariable (&cond->win32_cond); +#else + EnterCriticalSection (&cond->win32_spinlock); + for (unsigned i = 0; i < cond->len; i++) + SetEvent (cond->phandle[ i ]); + cond->len = 0; + LeaveCriticalSection (&cond->win32_spinlock); +#endif /* !_WIN32 */ +} + +#ifndef _WIN32 +void +pgm_cond_wait ( + pgm_cond_t* cond, + pthread_mutex_t* mutex + ) +{ + pgm_assert (NULL != cond); + pgm_assert (NULL != mutex); + pthread_cond_wait (&cond->pthread_cond, mutex); +} +#else +void +pgm_cond_wait ( + pgm_cond_t* cond, + CRITICAL_SECTION* spinlock + ) +{ + pgm_assert (NULL != cond); + pgm_assert (NULL != spinlock); +# if defined(CONFIG_HAVE_WIN_COND) + SleepConditionVariableCS (&cond->win32_cond, spinlock, INFINITE); +# else + DWORD status; + HANDLE event = TlsGetValue (cond_event_tls); + + if (!event) { + win32_check_cmd (event = CreateEvent (0, FALSE, FALSE, NULL)); + TlsSetValue (cond_event_tls, event); + } + + EnterCriticalSection (&cond->win32_spinlock); + pgm_assert (WAIT_TIMEOUT == WaitForSingleObject (event, 0)); + if ((cond->len + 1) > cond->allocated_len) { + cond->allocated_len = pgm_nearest_power (1, cond->len + 1 + 1); + cond->phandle = pgm_realloc (cond->phandle, cond->allocated_len); + } + cond->phandle[ cond->len++ ] = event; + LeaveCriticalSection (&cond->win32_spinlock); + + EnterCriticalSection (spinlock); + win32_check_cmd (WAIT_FAILED != (status = WaitForSingleObject (event, INFINITE))); + LeaveCriticalSection (spinlock); + + if (WAIT_TIMEOUT == status) { + EnterCriticalSection (&cond->win32_spinlock); + for (unsigned i = 0; i < cond->len; i++) { + if (cond->phandle[ i ] == event) { + if (i != cond->len - 1) + memmove (&cond->phandle[ i ], &cond->phandle[ i + 1 ], sizeof(HANDLE) * (cond->len - i - 1)); + cond->len--; + break; + } + } + win32_check_cmd (WAIT_FAILED != (status = WaitForSingleObject (event, 0))); + LeaveCriticalSection (&cond->win32_spinlock); + } +# endif /* !CONFIG_HAVE_WIN_COND */ +} +#endif /* !_WIN32 */ + +void +pgm_cond_free ( + pgm_cond_t* cond + ) +{ + pgm_assert (NULL != cond); +#ifndef _WIN32 + posix_check_cmd (pthread_cond_destroy (&cond->pthread_cond)); +#elif defined(CONFIG_HAVE_WIN_COND) + /* nop */ +#else + DeleteCriticalSection (&cond->win32_spinlock); + pgm_free (cond->phandle); +#endif /* !_WIN32 */ +} + +void +pgm_rwlock_init ( + pgm_rwlock_t* rwlock + ) +{ + pgm_assert (NULL != rwlock); +#ifdef CONFIG_HAVE_WIN_SRW_LOCK + InitializeSRWLock (&rwlock->win32_lock); +#elif !defined(_WIN32) + posix_check_cmd (pthread_rwlock_init (&rwlock->pthread_rwlock, NULL)); +#else + InitializeCriticalSection (&rwlock->win32_spinlock); + pgm_cond_init (&rwlock->read_cond); + pgm_cond_init (&rwlock->write_cond); + rwlock->read_counter = 0; + rwlock->have_writer = FALSE; + rwlock->want_to_read = 0; + rwlock->want_to_write = 0; +#endif /* !CONFIG_HAVE_WIN_SRW_LOCK */ +} + +void +pgm_rwlock_free ( + pgm_rwlock_t* rwlock + ) +{ + pgm_assert (NULL != rwlock); +#ifdef CONFIG_HAVE_WIN_SRW_LOCK + /* nop */ +#elif !defined(_WIN32) + pthread_rwlock_destroy (&rwlock->pthread_rwlock); +#else + pgm_cond_free (&rwlock->read_cond); + pgm_cond_free (&rwlock->write_cond); + DeleteCriticalSection (&rwlock->win32_spinlock); +#endif /* !CONFIG_HAVE_WIN_SRW_LOCK */ +} + +#if !defined(CONFIG_HAVE_WIN_SRW_LOCK) && defined(_WIN32) +static inline +void +_pgm_rwlock_signal ( + pgm_rwlock_t* rwlock + ) +{ + pgm_assert (NULL != rwlock); + if (rwlock->want_to_write) + pgm_cond_signal (&rwlock->write_cond); + else if (rwlock->want_to_read) + pgm_cond_broadcast (&rwlock->read_cond); +} + +void +pgm_rwlock_reader_lock ( + pgm_rwlock_t* rwlock + ) +{ + pgm_assert (NULL != rwlock); + EnterCriticalSection (&rwlock->win32_spinlock); + rwlock->want_to_read++; + while (rwlock->have_writer || rwlock->want_to_write) + pgm_cond_wait (&rwlock->read_cond, &rwlock->win32_spinlock); + rwlock->want_to_read--; + rwlock->read_counter++; + LeaveCriticalSection (&rwlock->win32_spinlock); +} + +bool +pgm_rwlock_reader_trylock ( + pgm_rwlock_t* rwlock + ) +{ + pgm_assert (NULL != rwlock); + bool status; + EnterCriticalSection (&rwlock->win32_spinlock); + if (!rwlock->have_writer && !rwlock->want_to_write) { + rwlock->read_counter++; + status = TRUE; + } else + status = FALSE; + LeaveCriticalSection (&rwlock->win32_spinlock); + return status; +} + +void +pgm_rwlock_reader_unlock( + pgm_rwlock_t* rwlock + ) +{ + pgm_assert (NULL != rwlock); + EnterCriticalSection (&rwlock->win32_spinlock); + rwlock->read_counter--; + if (rwlock->read_counter == 0) + _pgm_rwlock_signal (rwlock); + LeaveCriticalSection (&rwlock->win32_spinlock); +} + +void +pgm_rwlock_writer_lock ( + pgm_rwlock_t* rwlock + ) +{ + pgm_assert (NULL != rwlock); + EnterCriticalSection (&rwlock->win32_spinlock); + rwlock->want_to_write++; + while (rwlock->have_writer || rwlock->read_counter) + pgm_cond_wait (&rwlock->write_cond, &rwlock->win32_spinlock); + rwlock->want_to_write--; + rwlock->have_writer = TRUE; + LeaveCriticalSection (&rwlock->win32_spinlock); +} + +bool +pgm_rwlock_writer_trylock ( + pgm_rwlock_t* rwlock + ) +{ + pgm_assert (NULL != rwlock); + bool status; + EnterCriticalSection (&rwlock->win32_spinlock); + if (!rwlock->have_writer && !rwlock->read_counter) { + rwlock->have_writer = TRUE; + status = TRUE; + } else + status = FALSE; + LeaveCriticalSection (&rwlock->win32_spinlock); + return status; +} + +void +pgm_rwlock_writer_unlock ( + pgm_rwlock_t* rwlock + ) +{ + pgm_assert (NULL != rwlock); + EnterCriticalSection (&rwlock->win32_spinlock); + rwlock->have_writer = FALSE; + _pgm_rwlock_signal (rwlock); + LeaveCriticalSection (&rwlock->win32_spinlock); +} +#endif /* !_WIN32 && !CONFIG_HAVE_WIN_SRW_LOCK */ + + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/thread.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/thread.c.c89.patch new file mode 100644 index 0000000..34acaaf --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/thread.c.c89.patch @@ -0,0 +1,137 @@ +--- thread.c 2010-05-21 11:35:21.000000000 +0800 ++++ thread.c89 2010-08-05 11:31:03.000000000 +0800 +@@ -46,7 +46,8 @@ + } while (0) + # define posix_check_cmd(cmd) posix_check_err ((cmd), #cmd) + #else +-# define win32_check_err(err, name) \ ++# ifdef __PRETTY_FUNCTION ++# define win32_check_err(err, name) \ + do { \ + const bool save_error = (err); \ + if (PGM_UNLIKELY(!save_error)) { \ +@@ -55,6 +56,17 @@ + pgm_wsastrerror (GetLastError ()), name); \ + } \ + } while (0) ++# else ++# define win32_check_err(err, name) \ ++ do { \ ++ const bool save_error = (err); \ ++ if (PGM_UNLIKELY(!save_error)) { \ ++ pgm_error ("file %s: line %d: error '%s' during '%s'", \ ++ __FILE__, __LINE__, \ ++ pgm_wsastrerror (GetLastError ()), name); \ ++ } \ ++ } while (0) ++# endif + # define win32_check_cmd(cmd) win32_check_err ((cmd), #cmd) + #endif /* !_WIN32 */ + +@@ -94,9 +106,11 @@ + #ifndef _WIN32 + posix_check_cmd (pthread_mutex_init (&mutex->pthread_mutex, NULL)); + #else ++ { + HANDLE handle; +- win32_check_cmd (handle = CreateMutex (NULL, FALSE, NULL)); ++ win32_check_cmd (NULL != (handle = CreateMutex (NULL, FALSE, NULL))); + mutex->win32_mutex = handle; ++ } + #endif /* !_WIN32 */ + } + +@@ -113,9 +127,11 @@ + posix_check_err (result, "pthread_mutex_trylock"); + return TRUE; + #else ++ { + DWORD result; + win32_check_cmd (WAIT_FAILED != (result = WaitForSingleObject (mutex->win32_mutex, 0))); + return WAIT_TIMEOUT != result; ++ } + #endif /* !_WIN32 */ + } + +@@ -227,8 +243,11 @@ + WakeAllConditionVariable (&cond->win32_cond); + #else + EnterCriticalSection (&cond->win32_spinlock); +- for (unsigned i = 0; i < cond->len; i++) ++ { ++ unsigned i; ++ for (i = 0; i < cond->len; i++) + SetEvent (cond->phandle[ i ]); ++ } + cond->len = 0; + LeaveCriticalSection (&cond->win32_spinlock); + #endif /* !_WIN32 */ +@@ -257,11 +276,12 @@ + # if defined(CONFIG_HAVE_WIN_COND) + SleepConditionVariableCS (&cond->win32_cond, spinlock, INFINITE); + # else ++ { + DWORD status; + HANDLE event = TlsGetValue (cond_event_tls); + + if (!event) { +- win32_check_cmd (event = CreateEvent (0, FALSE, FALSE, NULL)); ++ win32_check_cmd (NULL != (event = CreateEvent (0, FALSE, FALSE, NULL))); + TlsSetValue (cond_event_tls, event); + } + +@@ -280,7 +300,9 @@ + + if (WAIT_TIMEOUT == status) { + EnterCriticalSection (&cond->win32_spinlock); +- for (unsigned i = 0; i < cond->len; i++) { ++ { ++ unsigned i; ++ for (i = 0; i < cond->len; i++) { + if (cond->phandle[ i ] == event) { + if (i != cond->len - 1) + memmove (&cond->phandle[ i ], &cond->phandle[ i + 1 ], sizeof(HANDLE) * (cond->len - i - 1)); +@@ -288,9 +310,11 @@ + break; + } + } ++ } + win32_check_cmd (WAIT_FAILED != (status = WaitForSingleObject (event, 0))); + LeaveCriticalSection (&cond->win32_spinlock); + } ++ } + # endif /* !CONFIG_HAVE_WIN_COND */ + } + #endif /* !_WIN32 */ +@@ -384,6 +408,7 @@ + ) + { + pgm_assert (NULL != rwlock); ++ { + bool status; + EnterCriticalSection (&rwlock->win32_spinlock); + if (!rwlock->have_writer && !rwlock->want_to_write) { +@@ -393,6 +418,7 @@ + status = FALSE; + LeaveCriticalSection (&rwlock->win32_spinlock); + return status; ++ } + } + + void +@@ -429,6 +455,7 @@ + ) + { + pgm_assert (NULL != rwlock); ++ { + bool status; + EnterCriticalSection (&rwlock->win32_spinlock); + if (!rwlock->have_writer && !rwlock->read_counter) { +@@ -438,6 +465,7 @@ + status = FALSE; + LeaveCriticalSection (&rwlock->win32_spinlock); + return status; ++ } + } + + void diff --git a/3rdparty/openpgm-svn-r1135/pgm/time.c b/3rdparty/openpgm-svn-r1135/pgm/time.c new file mode 100644 index 0000000..f012b50 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/time.c @@ -0,0 +1,774 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * high resolution timers. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __STDC_FORMAT_MACROS +#ifdef _MSC_VER +# include +#else +# include +#endif +#include +#include +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include "windows.h" +#endif +#include +#include + +//#define TIME_DEBUG + + +/* globals */ + +pgm_time_update_func pgm_time_update_now PGM_GNUC_READ_MOSTLY; +pgm_time_since_epoch_func pgm_time_since_epoch PGM_GNUC_READ_MOSTLY; + + +/* locals */ + +#define msecs_to_secs(t) ( (t) / 1000 ) +#define usecs_to_secs(t) ( (t) / 1000000UL ) +#define nsecs_to_secs(t) ( (t) / 1000000000UL ) +#define secs_to_msecs(t) ( (pgm_time_t)(t) * 1000 ) +#define secs_to_usecs(t) ( (pgm_time_t)(t) * 1000000UL ) +#define secs_to_nsecs(t) ( (pgm_time_t)(t) * 1000000000UL ) +#define msecs_to_usecs(t) ( (pgm_time_t)(t) * 1000 ) +#define msecs_to_nsecs(t) ( (pgm_time_t)(t) * 1000000UL ) +#define usecs_to_msecs(t) ( (t) / 1000 ) +#define usecs_to_nsecs(t) ( (pgm_time_t)(t) * 1000 ) +#define nsecs_to_msecs(t) ( (t) / 1000000UL ) +#define nsecs_to_usecs(t) ( (t) / 1000 ) +#define fsecs_to_nsecs(t) ( (t) / 1000000UL ) +#define fsecs_to_usecs(t) ( (t) / 1000000000UL ) + +static volatile uint32_t time_ref_count = 0; +static pgm_time_t rel_offset PGM_GNUC_READ_MOSTLY = 0; + +static void pgm_time_conv (const pgm_time_t*const restrict, time_t*restrict); +static void pgm_time_conv_from_reset (const pgm_time_t*const restrict, time_t*restrict); + +#if defined(CONFIG_HAVE_CLOCK_GETTIME) +# include +static pgm_time_t pgm_clock_update (void); +#endif +#ifdef CONFIG_HAVE_FTIME +# include +# ifdef _WIN32 +# define ftime _ftime +# endif +static pgm_time_t pgm_ftime_update (void); +#endif +#ifdef CONFIG_HAVE_GETTIMEOFDAY +# include +static pgm_time_t pgm_gettimeofday_update (void); +#endif +#ifdef CONFIG_HAVE_HPET +# include +# include +# include +# include +# include +# define HPET_MMAP_SIZE 0x400 +# define HPET_GENERAL_CAPS_REGISTER 0x00 +# define HPET_COUNTER_CLK_PERIOD 0x004 +# define HPET_MAIN_COUNTER_REGISTER 0x0f0 +# define HPET_COUNT_SIZE_CAP (1 << 13) +/* HPET counter size maybe 64-bit or 32-bit */ +# if defined(__x86_64__) +typedef uint64_t hpet_counter_t; +# else +typedef uint32_t hpet_counter_t; +# endif +static int hpet_fd PGM_GNUC_READ_MOSTLY = -1; +static char* hpet_ptr PGM_GNUC_READ_MOSTLY; +static uint64_t hpet_offset = 0; +static uint64_t hpet_wrap PGM_GNUC_READ_MOSTLY; +static hpet_counter_t hpet_last = 0; + +# define HPET_NS_SCALE 22 +# define HPET_US_SCALE 34 +static uint_fast32_t hpet_ns_mul PGM_GNUC_READ_MOSTLY = 0; +static uint_fast32_t hpet_us_mul PGM_GNUC_READ_MOSTLY = 0; + +static inline +void +set_hpet_mul ( + const uint32_t hpet_period + ) +{ + hpet_ns_mul = fsecs_to_nsecs((uint64_t)hpet_period << HPET_NS_SCALE); + hpet_us_mul = fsecs_to_usecs((uint64_t)hpet_period << HPET_US_SCALE); +} + +static inline +uint64_t +hpet_to_ns ( + const uint64_t hpet + ) +{ + return (hpet * hpet_ns_mul) >> HPET_NS_SCALE; +} + +static inline +uint64_t +hpet_to_us ( + const uint64_t hpet + ) +{ + return (hpet * hpet_us_mul) >> HPET_US_SCALE; +} + +static bool pgm_hpet_init (pgm_error_t**); +static bool pgm_hpet_shutdown (void); +static pgm_time_t pgm_hpet_update (void); +#endif +#ifdef CONFIG_HAVE_RTC +# include +# include +# include +# include +# include +# include +static int rtc_fd PGM_GNUC_READ_MOSTLY = -1; +static int rtc_frequency PGM_GNUC_READ_MOSTLY = 8192; +static pgm_time_t rtc_count = 0; +static bool pgm_rtc_init (pgm_error_t**); +static bool pgm_rtc_shutdown (void); +static pgm_time_t pgm_rtc_update (void); +#endif +#ifdef CONFIG_HAVE_TSC +# include +# include +# define TSC_NS_SCALE 10 /* 2^10, carefully chosen */ +# define TSC_US_SCALE 20 +static uint_fast32_t tsc_mhz PGM_GNUC_READ_MOSTLY = 0; +static uint_fast32_t tsc_ns_mul PGM_GNUC_READ_MOSTLY = 0; +static uint_fast32_t tsc_us_mul PGM_GNUC_READ_MOSTLY = 0; + +static inline +void +set_tsc_mul ( + const unsigned khz + ) +{ + tsc_ns_mul = (1000000 << TSC_NS_SCALE) / khz; + tsc_us_mul = (1000 << TSC_US_SCALE) / khz; +} + +static inline +uint64_t +tsc_to_ns ( + const uint64_t tsc + ) +{ + return (tsc * tsc_ns_mul) >> TSC_NS_SCALE; +} + +static inline +uint64_t +ns_to_tsc ( + const uint64_t ns + ) +{ + return (ns << TSC_NS_SCALE) / tsc_ns_mul; +} + +static inline +uint64_t +tsc_to_us ( + const uint64_t tsc + ) +{ + return (tsc * tsc_us_mul) >> TSC_US_SCALE; +} + +static inline +uint64_t +us_to_tsc ( + const uint64_t us + ) +{ + return (us << TSC_US_SCALE) / tsc_us_mul; +} + +# ifndef _WIN32 +static bool pgm_tsc_init (pgm_error_t**); +# endif +static pgm_time_t pgm_tsc_update (void); +#endif + + +/* initialize time system. + * + * returns TRUE on success, returns FALSE on error such as being unable to open + * the RTC device, an unstable TSC, or system already initialized. + */ + +bool +pgm_time_init ( + pgm_error_t** error + ) +{ + if (pgm_atomic_exchange_and_add32 (&time_ref_count, 1) > 0) + return TRUE; + +/* current time */ + const char *cfg = getenv ("PGM_TIMER"); + if (cfg == NULL) { +#ifdef CONFIG_HAVE_TSC + cfg = "TSC"; +#else + cfg = "GTOD"; +#endif + } + + pgm_time_since_epoch = pgm_time_conv; + + switch (cfg[0]) { +#ifdef CONFIG_HAVE_FTIME + case 'F': + pgm_minor (_("Using ftime() timer.")); + pgm_time_update_now = pgm_ftime_update; + break; +#endif +#ifdef CONFIG_HAVE_CLOCK_GETTIME + case 'C': + pgm_minor (_("Using clock_gettime() timer.")); + pgm_time_update_now = pgm_clock_update; + break; +#endif +#ifdef CONFIG_HAVE_RTC + case 'R': + pgm_minor (_("Using /dev/rtc timer.")); + pgm_time_update_now = pgm_rtc_update; + pgm_time_since_epoch = pgm_time_conv_from_reset; + break; +#endif +#ifdef CONFIG_HAVE_TSC +# ifdef _WIN32 + default: +# endif + case 'T': + pgm_minor (_("Using TSC timer.")); + pgm_time_update_now = pgm_tsc_update; + pgm_time_since_epoch = pgm_time_conv_from_reset; + break; +#endif +#ifdef CONFIG_HAVE_HPET + case 'H': + pgm_minor (_("Using HPET timer.")); + pgm_time_update_now = pgm_hpet_update; + pgm_time_since_epoch = pgm_time_conv_from_reset; + break; +#endif + +#ifdef CONFIG_HAVE_GETTIMEOFDAY +# ifndef _WIN32 + default: +# endif + case 'G': + pgm_minor (_("Using gettimeofday() timer.")); + pgm_time_update_now = pgm_gettimeofday_update; + break; +#endif + } + +#ifdef CONFIG_HAVE_RTC + if (pgm_time_update_now == pgm_rtc_update) + { + pgm_error_t* sub_error = NULL; + if (!pgm_rtc_init (&sub_error)) { + pgm_propagate_error (error, sub_error); + goto err_cleanup; + } + } +#endif +#ifdef CONFIG_HAVE_TSC + if (pgm_time_update_now == pgm_tsc_update) + { +#ifdef CONFIG_HAVE_PROC +/* attempt to parse clock ticks from kernel + */ + FILE* fp = fopen ("/proc/cpuinfo", "r"); + char buffer[1024]; + if (fp) + { + while (!feof(fp) && fgets (buffer, sizeof(buffer), fp)) + { + if (strstr (buffer, "cpu MHz")) + { + const char *p = strchr (buffer, ':'); + if (p) tsc_mhz = atoi (p + 1); + break; + } + } + fclose (fp); + } +#elif defined(_WIN32) + uint64_t frequency; + if (QueryPerformanceFrequency ((LARGE_INTEGER*)&frequency)) + { + tsc_mhz = frequency / 1000; + } +#endif /* !_WIN32 */ + +/* e.g. export RDTSC_FREQUENCY=3200.000000 + * + * Value can be used to override kernel tick rate as well as internal calibration + */ + const char *env_mhz = getenv ("RDTSC_FREQUENCY"); + if (env_mhz) + tsc_mhz = atoi (env_mhz); + +#ifndef _WIN32 +/* calibrate */ + if (0 >= tsc_mhz) { + pgm_error_t* sub_error = NULL; + if (!pgm_tsc_init (&sub_error)) { + pgm_propagate_error (error, sub_error); + goto err_cleanup; + } + } +#endif + set_tsc_mul (tsc_mhz * 1000); + } +#endif /* CONFIG_HAVE_TSC */ + +#ifdef CONFIG_HAVE_HPET + if (pgm_time_update_now == pgm_hpet_update) + { + pgm_error_t* sub_error = NULL; + if (!pgm_hpet_init (&sub_error)) { + pgm_propagate_error (error, sub_error); + goto err_cleanup; + } + } +#endif + + pgm_time_update_now(); + +/* calculate relative time offset */ +#if defined(CONFIG_HAVE_RTC) || defined(CONFIG_HAVE_TSC) + if ( 0 +# ifdef CONFIG_HAVE_RTC + || pgm_time_update_now == pgm_rtc_update +# endif +# ifdef CONFIG_HAVE_TSC + || pgm_time_update_now == pgm_tsc_update +# endif + ) + { +# if defined( CONFIG_HAVE_GETTIMEOFDAY ) + rel_offset = pgm_gettimeofday_update() - pgm_time_update_now(); +# elif defined( CONFIG_HAVE_FTIME ) + rel_offset = pgm_ftime_update() - pgm_time_update_now(); +# else +# error "gettimeofday() or ftime() required to calculate counter offset" +# endif + } +#else + rel_offset = 0; +#endif + + return TRUE; + +err_cleanup: + pgm_atomic_dec32 (&time_ref_count); + return FALSE; +} + +/* returns TRUE if shutdown succeeded, returns FALSE on error. + */ + +bool +pgm_time_shutdown (void) +{ + pgm_return_val_if_fail (pgm_atomic_read32 (&time_ref_count) > 0, FALSE); + + if (pgm_atomic_exchange_and_add32 (&time_ref_count, (uint32_t)-1) != 1) + return TRUE; + + bool success = TRUE; +#ifdef CONFIG_HAVE_RTC + if (pgm_time_update_now == pgm_rtc_update) + success = pgm_rtc_shutdown (); +#endif +#ifdef CONFIG_HAVE_HPET + if (pgm_time_update_now == pgm_hpet_update) + success = pgm_hpet_shutdown (); +#endif + return success; +} + +#ifdef CONFIG_HAVE_GETTIMEOFDAY +static +pgm_time_t +pgm_gettimeofday_update (void) +{ + struct timeval gettimeofday_now; + static pgm_time_t last = 0; + gettimeofday (&gettimeofday_now, NULL); + const pgm_time_t now = secs_to_usecs (gettimeofday_now.tv_sec) + gettimeofday_now.tv_usec; + if (PGM_UNLIKELY(now < last)) + return last; + else + return last = now; +} +#endif /* CONFIG_HAVE_GETTIMEOFDAY */ + +#ifdef CONFIG_HAVE_CLOCK_GETTIME +static +pgm_time_t +pgm_clock_update (void) +{ + struct timespec clock_now; + static pgm_time_t last = 0; + clock_gettime (CLOCK_MONOTONIC, &clock_now); + const pgm_time_t now = secs_to_usecs (clock_now.tv_sec) + nsecs_to_usecs (clock_now.tv_nsec); + if (PGM_UNLIKELY(now < last)) + return last; + else + return last = now; +} +#endif /* CONFIG_HAVE_CLOCK_GETTIME */ + +#ifdef CONFIG_HAVE_FTIME +static +pgm_time_t +pgm_ftime_update (void) +{ + struct timeb ftime_now; + static pgm_time_t last = 0; + ftime (&ftime_now); + const pgm_time_t now = secs_to_usecs (ftime_now.time) + msecs_to_usecs (ftime_now.millitm); + if (PGM_UNLIKELY(now < last)) + return last; + else + return last = now; +} +#endif /* CONFIG_HAVE_FTIME */ + +#ifdef CONFIG_HAVE_RTC +/* Old PC/AT-Compatible driver: /dev/rtc + * + * Not so speedy 8192 Hz timer, thats 122us resolution. + * + * WARNING: time is relative to start of timer. + * WARNING: only one process is allowed to access the RTC. + */ + +static +bool +pgm_rtc_init ( + pgm_error_t** error + ) +{ + pgm_return_val_if_fail (rtc_fd == -1, FALSE); + + rtc_fd = open ("/dev/rtc", O_RDONLY); + if (-1 == rtc_fd) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_TIME, + PGM_ERROR_FAILED, + _("Cannot open /dev/rtc for reading: %s"), + strerror(errno)); + return FALSE; + } + if (-1 == ioctl (rtc_fd, RTC_IRQP_SET, rtc_frequency)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_TIME, + PGM_ERROR_FAILED, + _("Cannot set RTC frequency to %i Hz: %s"), + rtc_frequency, + strerror(errno)); + return FALSE; + } + if (-1 == ioctl (rtc_fd, RTC_PIE_ON, 0)) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_TIME, + PGM_ERROR_FAILED, + _("Cannot enable periodic interrupt (PIE) on RTC: %s"), + strerror(errno)); + return FALSE; + } + return TRUE; +} + +/* returns TRUE on success even if RTC device cannot be closed or had an IO error, + * returns FALSE if the RTC file descriptor is not set. + */ + +static +bool +pgm_rtc_shutdown (void) +{ + pgm_return_val_if_fail (rtc_fd, FALSE); + pgm_warn_if_fail (0 == close (rtc_fd)); + rtc_fd = -1; + return TRUE; +} + +/* RTC only indicates passed ticks therefore is by definition monotonic, we do not + * need to check the difference with respect to the last value. + */ + +static +pgm_time_t +pgm_rtc_update (void) +{ + uint32_t data; + +/* returned value contains interrupt type and count of interrupts since last read */ + pgm_warn_if_fail (sizeof(data) == read (rtc_fd, &data, sizeof(data))); + rtc_count += data >> 8; + return rtc_count * 1000000UL / rtc_frequency; +} +#endif /* CONFIG_HAVE_RTC */ + +#ifdef CONFIG_HAVE_TSC +/* read time stamp counter (TSC), count of ticks from processor reset. + * + * NB: On Windows this will usually be HPET or PIC timer interpolated with TSC. + */ + +static inline +pgm_time_t +rdtsc (void) +{ +# ifndef _WIN32 + uint32_t lo, hi; + +/* We cannot use "=A", since this would use %rax on x86_64 */ + asm volatile ("rdtsc" : "=a" (lo), "=d" (hi)); + + return (pgm_time_t)hi << 32 | lo; +# else + uint64_t counter; + QueryPerformanceCounter ((LARGE_INTEGER*)&counter); + return (pgm_time_t)counter; +# endif +} + +# ifndef _WIN32 +/* determine ratio of ticks to nano-seconds, use /dev/rtc for high accuracy + * millisecond timer and convert. + * + * WARNING: time is relative to start of timer. + */ + +static +bool +pgm_tsc_init ( + PGM_GNUC_UNUSED pgm_error_t** error + ) +{ +# ifdef CONFIG_HAVE_PROC +/* Test for constant TSC from kernel + */ + FILE* fp = fopen ("/proc/cpuinfo", "r"); + char buffer[1024], *flags = NULL; + if (fp) + { + while (!feof(fp) && fgets (buffer, sizeof(buffer), fp)) + { + if (strstr (buffer, "flags")) + { + flags = strchr (buffer, ':'); + break; + } + } + fclose (fp); + } + if (!flags || !strstr (flags, " tsc")) { + pgm_warn (_("Linux kernel reports no Time Stamp Counter (TSC).")); +/* force both to stable clocks even though one might be OK */ + pgm_time_update_now = pgm_gettimeofday_update; + return TRUE; + } + if (!strstr (flags, " constant_tsc")) { + pgm_warn (_("Linux kernel reports non-constant Time Stamp Counter (TSC).")); +/* force both to stable clocks even though one might be OK */ + pgm_time_update_now = pgm_gettimeofday_update; + return TRUE; + } +# endif /* CONFIG_HAVE_PROC */ + pgm_time_t start, stop; + const pgm_time_t calibration_usec = secs_to_usecs (4); + + pgm_info (_("Running a benchmark to measure system clock frequency...")); + + struct timespec req = { + .tv_sec = 4, + .tv_nsec = 0 + }; + start = rdtsc(); + while (-1 == nanosleep (&req, &req) && EINTR == errno); + stop = rdtsc(); + + if (stop < start) + { + pgm_warn (_("Finished RDTSC test. Unstable TSC detected. The benchmark resulted in a " + "non-monotonic time response rendering the TSC unsuitable for high resolution " + "timing. To prevent the start delay from this benchmark and use a stable clock " + "source set the environment variable PGM_TIMER to GTOD.")); +/* force both to stable clocks even though one might be OK */ + pgm_time_update_now = pgm_gettimeofday_update; + return TRUE; + } + +/* TODO: this math needs to be scaled to reduce rounding errors */ + const pgm_time_t tsc_diff = stop - start; + if (tsc_diff > calibration_usec) { +/* cpu > 1 Ghz */ + tsc_mhz = tsc_diff / calibration_usec; + } else { +/* cpu < 1 Ghz */ + tsc_mhz = -( calibration_usec / tsc_diff ); + } + + pgm_info (_("Finished RDTSC test. To prevent the startup delay from this benchmark, " + "set the environment variable RDTSC_FREQUENCY to %" PRIuFAST32 " on this " + "system. This value is dependent upon the CPU clock speed and " + "architecture and should be determined separately for each server."), + tsc_mhz); + return TRUE; +} +# endif + +/* TSC is monotonic on the same core but we do neither force the same core or save the count + * for each core as if the counter is unstable system wide another timing mechanism should be + * used, preferably HPET on x86/AMD64 or gettimeofday() on SPARC. + */ + +static +pgm_time_t +pgm_tsc_update (void) +{ + static pgm_time_t last = 0; + const pgm_time_t now = tsc_to_us (rdtsc()); + if (PGM_UNLIKELY(now < last)) + return last; + else + return last = now; +} +#endif + +#ifdef CONFIG_HAVE_HPET +/* High Precision Event Timer (HPET) created as a system wide stable high resolution timer + * to replace dependency on core specific counters (TSC). + * + * NB: Only available on x86/AMD64 hardware post 2007 + */ + +static +bool +pgm_hpet_init ( + pgm_error_t** error + ) +{ + pgm_return_val_if_fail (hpet_fd == -1, FALSE); + + hpet_fd = open("/dev/hpet", O_RDONLY); + if (hpet_fd < 0) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_TIME, + PGM_ERROR_FAILED, + _("Cannot open /dev/hpet for reading: %s"), + strerror(errno)); + return FALSE; + } + + hpet_ptr = mmap(NULL, HPET_MMAP_SIZE, PROT_READ, MAP_SHARED, hpet_fd, 0); + if (MAP_FAILED == hpet_ptr) { + pgm_set_error (error, + PGM_ERROR_DOMAIN_TIME, + PGM_ERROR_FAILED, + _("Error mapping HPET device: %s"), + strerror(errno)); + close (hpet_fd); + hpet_fd = -1; + return FALSE; + } + +/* HPET counter tick period is in femto-seconds, a value of 0 is not permitted, + * the value must be <= 0x05f5e100 or 100ns. + */ + const uint32_t hpet_period = *((uint32_t*)(hpet_ptr + HPET_COUNTER_CLK_PERIOD)); + set_hpet_mul (hpet_period); +#if defined( __x86_64__ ) || defined( __amd64 ) + const uint32_t hpet_caps = *((uint32_t*)(hpet_ptr + HPET_GENERAL_CAPS_REGISTER)); + hpet_wrap = hpet_caps & HPET_COUNT_SIZE_CAP ? 0 : (1ULL << 32); +#else + hpet_wrap = 1ULL << 32; +#endif + + return TRUE; +} + +static +bool +pgm_hpet_shutdown (void) +{ + pgm_return_val_if_fail (hpet_fd, FALSE); + pgm_warn_if_fail (0 == close (hpet_fd)); + hpet_fd = -1; + return TRUE; +} + +static +pgm_time_t +pgm_hpet_update (void) +{ + const hpet_counter_t hpet_count = *((hpet_counter_t*)(hpet_ptr + HPET_MAIN_COUNTER_REGISTER)); +/* 32-bit HPET counters wrap after ~4 minutes */ + if (PGM_UNLIKELY(hpet_count < hpet_last)) + hpet_offset += hpet_wrap; + hpet_last = hpet_count; + return hpet_to_us (hpet_offset + hpet_count); +} +#endif /* CONFIG_HAVE_HPET */ + +/* convert from pgm_time_t to time_t with pgm_time_t in microseconds since the epoch. + */ +static +void +pgm_time_conv ( + const pgm_time_t* const restrict pgm_time_t_time, + time_t* restrict time_t_time + ) +{ + *time_t_time = pgm_to_secs (*pgm_time_t_time); +} + +/* convert from pgm_time_t to time_t with pgm_time_t in microseconds since the core started. + */ +static +void +pgm_time_conv_from_reset ( + const pgm_time_t* const restrict pgm_time_t_time, + time_t* restrict time_t_time + ) +{ + *time_t_time = pgm_to_secs (*pgm_time_t_time + rel_offset); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/time.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/time.c.c89.patch new file mode 100644 index 0000000..be65fec --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/time.c.c89.patch @@ -0,0 +1,115 @@ +--- time.c 2010-08-04 18:15:50.000000000 +0800 ++++ time.c89 2010-08-05 12:22:53.000000000 +0800 +@@ -232,7 +232,15 @@ + return TRUE; + + /* current time */ ++#ifdef _MSC_VER ++ { ++ char* cfg = NULL; ++ size_t len; ++ errno_t err = _dupenv_s (&cfg, &len, "PGM_TIMER"); ++#else ++ { + const char *cfg = getenv ("PGM_TIMER"); ++#endif + if (cfg == NULL) { + #ifdef CONFIG_HAVE_TSC + cfg = "TSC"; +@@ -292,6 +300,13 @@ + #endif + } + ++#ifdef _MSC_VER ++/* cleanup after _dupenv_s() */ ++ if (!err && len > 0) { ++ free (cfg); ++ } ++#endif ++ + #ifdef CONFIG_HAVE_RTC + if (pgm_time_update_now == pgm_rtc_update) + { +@@ -324,10 +339,12 @@ + fclose (fp); + } + #elif defined(_WIN32) ++ { + uint64_t frequency; + if (QueryPerformanceFrequency ((LARGE_INTEGER*)&frequency)) + { +- tsc_mhz = frequency / 1000; ++ tsc_mhz = (uint_fast32_t)(frequency / 1000); ++ } + } + #endif /* !_WIN32 */ + +@@ -335,10 +352,20 @@ + * + * Value can be used to override kernel tick rate as well as internal calibration + */ ++ { ++#ifdef _MSC_VER ++ char* env_mhz = NULL; ++ size_t len; ++ errno_t err = _dupenv_s (&env_mhz, &len, "RDTSC_FREQUENCY"); ++#else + const char *env_mhz = getenv ("RDTSC_FREQUENCY"); ++#endif + if (env_mhz) + tsc_mhz = atoi (env_mhz); +- ++#ifdef _MSC_VER ++ free (env_mhz); ++#endif ++ } + #ifndef _WIN32 + /* calibrate */ + if (0 >= tsc_mhz) { +@@ -394,6 +421,7 @@ + err_cleanup: + pgm_atomic_dec32 (&time_ref_count); + return FALSE; ++ } + } + + /* returns TRUE if shutdown succeeded, returns FALSE on error. +@@ -407,6 +435,7 @@ + if (pgm_atomic_exchange_and_add32 (&time_ref_count, (uint32_t)-1) != 1) + return TRUE; + ++ { + bool success = TRUE; + #ifdef CONFIG_HAVE_RTC + if (pgm_time_update_now == pgm_rtc_update) +@@ -417,6 +446,7 @@ + success = pgm_hpet_shutdown (); + #endif + return success; ++ } + } + + #ifdef CONFIG_HAVE_GETTIMEOFDAY +@@ -456,14 +486,21 @@ + pgm_time_t + pgm_ftime_update (void) + { +- struct timeb ftime_now; + static pgm_time_t last = 0; ++#ifdef _MSC_VER ++ struct __timeb64 ftime_now; ++ _ftime64_s (&ftime_now); ++#else ++ struct timeb ftime_now; + ftime (&ftime_now); ++#endif ++ { + const pgm_time_t now = secs_to_usecs (ftime_now.time) + msecs_to_usecs (ftime_now.millitm); + if (PGM_UNLIKELY(now < last)) + return last; + else + return last = now; ++ } + } + #endif /* CONFIG_HAVE_FTIME */ + diff --git a/3rdparty/openpgm-svn-r1135/pgm/time_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/time_unittest.c new file mode 100644 index 0000000..fd28572 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/time_unittest.c @@ -0,0 +1,188 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for high resolution timers. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include + + +/* mock state */ + + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + + +#include "time.c" + + +/* target: + * boolean + * pgm_time_init (pgm_error_t** error) + */ + +/* time initialisation uses reference counting */ + +START_TEST (test_init_pass_001) +{ + fail_unless (TRUE == pgm_time_init (NULL), "init #1 failed"); + fail_unless (TRUE == pgm_time_init (NULL), "init #2 failed"); +} +END_TEST + +/* target: + * bool + * pgm_time_shutdown (void) + */ + +START_TEST (test_shutdown_pass_001) +{ + fail_unless (TRUE == pgm_time_init (NULL), "init failed"); + fail_unless (TRUE == pgm_time_shutdown (), "shutdown #1 failed"); + fail_unless (FALSE == pgm_time_shutdown (), "shutdown #2 failed"); +} +END_TEST + +START_TEST (test_shutdown_pass_002) +{ + fail_unless (TRUE == pgm_time_init (NULL), "init #1 failed"); + fail_unless (TRUE == pgm_time_init (NULL), "init #2 failed"); + fail_unless (TRUE == pgm_time_shutdown (), "shutdown #1 failed"); + fail_unless (TRUE == pgm_time_shutdown (), "shutdown #2 failed"); + fail_unless (FALSE == pgm_time_shutdown (), "shutdown #3 failed"); +} +END_TEST + +/* target: + * pgm_time_t + * pgm_time_update_now (void) + */ + +START_TEST (test_update_now_pass_001) +{ + pgm_time_t tstamps[11]; + fail_unless (TRUE == pgm_time_init (NULL), "init failed"); + const pgm_time_t start_time = pgm_time_update_now (); + for (unsigned i = 1; i <= 10; i++) + { + tstamps[i] = pgm_time_update_now(); + } + g_message ("start-time: %" PGM_TIME_FORMAT, start_time); + for (unsigned i = 1; i <= 10; i++) + { + const pgm_time_t check_time = tstamps[i]; + const gint64 elapsed_time = check_time - start_time; + +/* must be monotonic */ + fail_unless (G_LIKELY(check_time >= start_time), "non-monotonic"); + + g_message ("check-point-%2.2u: %" PGM_TIME_FORMAT " (%+" G_GINT64_FORMAT "us)", + i, check_time, pgm_to_usecs(elapsed_time)); + } + fail_unless (TRUE == pgm_time_shutdown (), "shutdown failed"); +} +END_TEST + +/* target: + * void + * pgm_time_since_epoch ( + * pgm_time_t* pgm_time, + * time_t* epoch_time + * ) + */ + +START_TEST (test_since_epoch_pass_001) +{ + char stime[1024]; + time_t t; + struct tm* tmp; + fail_unless (TRUE == pgm_time_init (NULL), "init failed"); + pgm_time_t pgm_now = pgm_time_update_now (); + pgm_time_since_epoch (&pgm_now, &t); + tmp = localtime (&t); + fail_unless (NULL != tmp, "localtime failed"); + fail_unless (0 != strftime (stime, sizeof(stime), "%X", tmp), "strftime failed"); + g_message ("pgm-time:%" PGM_TIME_FORMAT " = %s", + pgm_now, stime); + fail_unless (TRUE == pgm_time_shutdown (), "shutdown failed"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_init = tcase_create ("init"); + suite_add_tcase (s, tc_init); + tcase_add_test (tc_init, test_init_pass_001); + + TCase* tc_shutdown = tcase_create ("shutdown"); + suite_add_tcase (s, tc_shutdown); + tcase_add_test (tc_shutdown, test_shutdown_pass_001); + tcase_add_test (tc_shutdown, test_shutdown_pass_002); + + TCase* tc_update_now = tcase_create ("update-now"); + suite_add_tcase (s, tc_update_now); + tcase_add_test (tc_update_now, test_update_now_pass_001); + + TCase* tc_since_epoch = tcase_create ("since-epoch"); + suite_add_tcase (s, tc_since_epoch); + tcase_add_test (tc_since_epoch, test_since_epoch_pass_001); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/timer.c b/3rdparty/openpgm-svn-r1135/pgm/timer.c new file mode 100644 index 0000000..0df1f66 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/timer.c @@ -0,0 +1,227 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * PGM timer thread. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __STDC_FORMAT_MACROS +#ifdef _MSC_VER +# include +#else +# include +#endif +#include +#include +#include +#include +#include + + +//#define TIMER_DEBUG + + +/* determine which timer fires next: spm (ihb_tmr), nak_rb_ivl, nak_rpt_ivl, or nak_rdata_ivl + * and check whether its already due. + * + * called in sock creation so locks unrequired. + */ + +bool +pgm_timer_prepare ( + pgm_sock_t* const sock + ) +{ + int32_t msec; + +/* pre-conditions */ + pgm_assert (NULL != sock); + pgm_assert (sock->can_send_data || sock->can_recv_data); + + pgm_time_t now = pgm_time_update_now(); + pgm_time_t expiration; + + if (sock->can_send_data) + expiration = sock->next_ambient_spm; + else + expiration = now + sock->peer_expiry; + + sock->next_poll = expiration; + +/* advance time again to adjust for processing time out of the event loop, this + * could cause further timers to expire even before checking for new wire data. + */ + msec = pgm_to_msecs ((int64_t)expiration - (int64_t)now); + if (msec < 0) + msec = 0; + else + msec = MIN (INT32_MAX, msec); + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiration in %" PRIi32 "ms"), msec); + return (msec == 0); +} + +bool +pgm_timer_check ( + pgm_sock_t* const sock + ) +{ + const pgm_time_t now = pgm_time_update_now(); + bool expired; + +/* pre-conditions */ + pgm_assert (NULL != sock); + + pgm_timer_lock (sock); + expired = pgm_time_after_eq (now, sock->next_poll); + pgm_timer_unlock (sock); + return expired; +} + +/* return next timer expiration in microseconds (μs) + */ + +pgm_time_t +pgm_timer_expiration ( + pgm_sock_t* const sock + ) +{ + const pgm_time_t now = pgm_time_update_now(); + pgm_time_t expiration; + +/* pre-conditions */ + pgm_assert (NULL != sock); + + pgm_timer_lock (sock); + expiration = pgm_time_after (sock->next_poll, now) ? pgm_to_usecs (sock->next_poll - now) : 0; + pgm_timer_unlock (sock); + return expiration; +} + +/* call all timers, assume that time_now has been updated by either pgm_timer_prepare + * or pgm_timer_check and no other method calls here. + * + * returns TRUE on success, returns FALSE on blocked send-in-receive operation. + */ + +bool +pgm_timer_dispatch ( + pgm_sock_t* const sock + ) +{ + const pgm_time_t now = pgm_time_update_now(); + pgm_time_t next_expiration = 0; + +/* pre-conditions */ + pgm_assert (NULL != sock); + + pgm_debug ("pgm_timer_dispatch (sock:%p)", (const void*)sock); + +/* find which timers have expired and call each */ + if (sock->can_recv_data) + { + if (!pgm_check_peer_state (sock, now)) + return FALSE; + next_expiration = pgm_min_receiver_expiry (now + sock->peer_expiry, sock); + } + + if (sock->can_send_data) + { +/* reset congestion control on ACK timeout */ + if (sock->use_pgmcc && + sock->tokens < pgm_fp8 (1) && + 0 != sock->ack_expiry) + { + if (pgm_time_after_eq (now, sock->ack_expiry)) + { +#ifdef DEBUG_PGMCC +char nows[1024]; +time_t t = time (NULL); +struct tm* tmp = localtime (&t); +strftime (nows, sizeof(nows), "%Y-%m-%d %H:%M:%S", tmp); +printf ("ACK timeout, T:%u W:%u\n", pgm_fp8tou(sock->tokens), pgm_fp8tou(sock->cwnd_size)); +#endif + sock->tokens = sock->cwnd_size = pgm_fp8 (1); + sock->ack_bitmap = 0xffffffff; + sock->ack_expiry = 0; + +/* notify blocking tx thread that transmission time is now available */ + pgm_notify_send (&sock->ack_notify); + } + next_expiration = next_expiration > 0 ? MIN(next_expiration, sock->ack_expiry) : sock->ack_expiry; + } + +/* SPM broadcast */ + pgm_mutex_lock (&sock->timer_mutex); + const unsigned spm_heartbeat_state = sock->spm_heartbeat_state; + const pgm_time_t next_heartbeat_spm = sock->next_heartbeat_spm; + pgm_mutex_unlock (&sock->timer_mutex); + +/* no lock needed on ambient */ + const pgm_time_t next_ambient_spm = sock->next_ambient_spm; + pgm_time_t next_spm = spm_heartbeat_state ? MIN(next_heartbeat_spm, next_ambient_spm) : next_ambient_spm; + + if (pgm_time_after_eq (now, next_spm) && + !pgm_send_spm (sock, 0)) + return FALSE; + +/* ambient timing not so important so base next event off current time */ + if (pgm_time_after_eq (now, next_ambient_spm)) + { + sock->next_ambient_spm = now + sock->spm_ambient_interval; + next_spm = spm_heartbeat_state ? MIN(next_heartbeat_spm, sock->next_ambient_spm) : sock->next_ambient_spm; + } + +/* heartbeat timing is often high resolution so base times to last event */ + if (spm_heartbeat_state && pgm_time_after_eq (now, next_heartbeat_spm)) + { + unsigned new_heartbeat_state = spm_heartbeat_state; + pgm_time_t new_heartbeat_spm = next_heartbeat_spm; + do { + new_heartbeat_spm += sock->spm_heartbeat_interval[new_heartbeat_state++]; + if (new_heartbeat_state == sock->spm_heartbeat_len) { + new_heartbeat_state = 0; + new_heartbeat_spm = now + sock->spm_ambient_interval; + break; + } + } while (pgm_time_after_eq (now, new_heartbeat_spm)); +/* check for reset heartbeat */ + pgm_mutex_lock (&sock->timer_mutex); + if (next_heartbeat_spm == sock->next_heartbeat_spm) { + sock->spm_heartbeat_state = new_heartbeat_state; + sock->next_heartbeat_spm = new_heartbeat_spm; + next_spm = MIN(sock->next_ambient_spm, new_heartbeat_spm); + } else + next_spm = MIN(sock->next_ambient_spm, sock->next_heartbeat_spm); + sock->next_poll = next_expiration > 0 ? MIN(next_expiration, next_spm) : next_spm; + pgm_mutex_unlock (&sock->timer_mutex); + return TRUE; + } + + next_expiration = next_expiration > 0 ? MIN(next_expiration, next_spm) : next_spm; + +/* check for reset */ + pgm_mutex_lock (&sock->timer_mutex); + sock->next_poll = sock->next_poll > now ? MIN(sock->next_poll, next_expiration) : next_expiration; + pgm_mutex_unlock (&sock->timer_mutex); + } + else + sock->next_poll = next_expiration; + + return TRUE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/timer.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/timer.c.c89.patch new file mode 100644 index 0000000..890f131 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/timer.c.c89.patch @@ -0,0 +1,63 @@ +--- timer.c 2010-08-04 18:16:05.000000000 +0800 ++++ timer.c89 2010-08-05 11:34:01.000000000 +0800 +@@ -52,6 +52,7 @@ + pgm_assert (NULL != sock); + pgm_assert (sock->can_send_data || sock->can_recv_data); + ++ { + pgm_time_t now = pgm_time_update_now(); + pgm_time_t expiration; + +@@ -65,13 +66,14 @@ + /* advance time again to adjust for processing time out of the event loop, this + * could cause further timers to expire even before checking for new wire data. + */ +- msec = pgm_to_msecs ((int64_t)expiration - (int64_t)now); ++ msec = (int32_t)pgm_to_msecs ((int64_t)expiration - (int64_t)now); + if (msec < 0) + msec = 0; + else + msec = MIN (INT32_MAX, msec); + pgm_trace (PGM_LOG_ROLE_NETWORK,_("Next expiration in %" PRIi32 "ms"), msec); + return (msec == 0); ++ } + } + + bool +@@ -148,11 +150,13 @@ + if (pgm_time_after_eq (now, sock->ack_expiry)) + { + #ifdef DEBUG_PGMCC ++{ + char nows[1024]; + time_t t = time (NULL); + struct tm* tmp = localtime (&t); + strftime (nows, sizeof(nows), "%Y-%m-%d %H:%M:%S", tmp); + printf ("ACK timeout, T:%u W:%u\n", pgm_fp8tou(sock->tokens), pgm_fp8tou(sock->cwnd_size)); ++} + #endif + sock->tokens = sock->cwnd_size = pgm_fp8 (1); + sock->ack_bitmap = 0xffffffff; +@@ -166,11 +170,13 @@ + + /* SPM broadcast */ + pgm_mutex_lock (&sock->timer_mutex); ++ { + const unsigned spm_heartbeat_state = sock->spm_heartbeat_state; + const pgm_time_t next_heartbeat_spm = sock->next_heartbeat_spm; + pgm_mutex_unlock (&sock->timer_mutex); + + /* no lock needed on ambient */ ++ { + const pgm_time_t next_ambient_spm = sock->next_ambient_spm; + pgm_time_t next_spm = spm_heartbeat_state ? MIN(next_heartbeat_spm, next_ambient_spm) : next_ambient_spm; + +@@ -217,6 +223,8 @@ + pgm_mutex_lock (&sock->timer_mutex); + sock->next_poll = sock->next_poll > now ? MIN(sock->next_poll, next_expiration) : next_expiration; + pgm_mutex_unlock (&sock->timer_mutex); ++ } ++ } + } + else + sock->next_poll = next_expiration; diff --git a/3rdparty/openpgm-svn-r1135/pgm/timer_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/timer_unittest.c new file mode 100644 index 0000000..2e48802 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/timer_unittest.c @@ -0,0 +1,355 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for PGM timer thread. + * + * Copyright (c) 2009-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include + + +/* mock state */ + + +#define g_main_context_new mock_g_main_context_new +#define g_main_context_unref mock_g_main_context_unref +#define g_main_loop_new mock_g_main_loop_new +#define g_main_loop_run mock_g_main_loop_run +#define g_main_loop_unref mock_g_main_loop_unref +#define g_source_new mock_g_source_new +#define g_source_set_priority mock_g_source_set_priority +#define g_source_attach mock_g_source_attach +#define g_source_unref mock_g_source_unref +#define pgm_time_now mock_pgm_time_now +#define pgm_time_update_now mock_pgm_time_update_now +#define pgm_min_receiver_expiry mock_pgm_min_receiver_expiry +#define pgm_check_peer_state mock_pgm_check_peer_state +#define pgm_send_spm mock_pgm_send_spm + + +#define TIMER_DEBUG +#include "timer.c" + +static pgm_time_t _mock_pgm_time_update_now(void); +pgm_time_update_func mock_pgm_time_update_now = _mock_pgm_time_update_now; +static pgm_time_t mock_pgm_time_now = 0x1; + + +static +pgm_sock_t* +generate_sock (void) +{ + pgm_sock_t* sock = g_new0 (pgm_sock_t, 1); + return sock; +} + + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + +/** GLib */ +static +GMainContext* +mock_g_main_context_new (void) +{ + GMainContext* context = g_malloc0 (sizeof(gpointer)); + return context; +} + +static +GMainLoop* +mock_g_main_loop_new ( + GMainContext* context, + gboolean is_running + ) +{ + g_assert (NULL != context); + GMainLoop* loop = g_malloc0 (sizeof(gpointer)); + return loop; +} + +static +void +mock_g_main_loop_run ( + GMainLoop* loop + ) +{ + g_assert (NULL != loop); +} + +static +void +mock_g_main_loop_unref ( + GMainLoop* loop + ) +{ + g_assert (NULL != loop); + g_free (loop); +} + +static +void +mock_g_main_context_unref ( + GMainContext* context + ) +{ + g_assert (NULL != context); + g_free (context); +} + +static +GSource* +mock_g_source_new ( + GSourceFuncs* source_funcs, + guint struct_size + ) +{ + g_assert (struct_size > 0); + GSource* source = g_malloc0 (struct_size); + return source; +} + +static +void +mock_g_source_set_priority ( + GSource* source, + gint priority + ) +{ + g_assert (NULL != source); +} + +static +guint +mock_g_source_attach ( + GSource* source, + GMainContext* context + ) +{ + g_assert (NULL != source); + return 1; +} + +static +void +mock_g_source_unref ( + GSource* source + ) +{ + g_assert (NULL != source); + g_free (source); +} + +/** time module */ +static +pgm_time_t +_mock_pgm_time_update_now (void) +{ + return mock_pgm_time_now; +} + +/** receiver module */ +PGM_GNUC_INTERNAL +pgm_time_t +mock_pgm_min_receiver_expiry ( + pgm_time_t expiration, + pgm_sock_t* sock + ) +{ + g_assert (NULL != sock); + return 0x1; +} + +PGM_GNUC_INTERNAL +bool +mock_pgm_check_peer_state ( + pgm_sock_t* sock, + pgm_time_t now + ) +{ + g_assert (NULL != sock); + return TRUE; +} + +/** source module */ +PGM_GNUC_INTERNAL +bool +mock_pgm_send_spm ( + pgm_sock_t* sock, + int flags + ) +{ + g_assert (NULL != sock); + return TRUE; +} + + +/* target: + * bool + * pgm_timer_prepare ( + * pgm_sock_t* sock + * ) + */ + +START_TEST (test_prepare_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->can_send_data = TRUE; + sock->next_ambient_spm = mock_pgm_time_now + pgm_secs(10); + fail_unless (FALSE == pgm_timer_prepare (sock), "prepare failed"); +} +END_TEST + +START_TEST (test_prepare_fail_001) +{ + gboolean expired = pgm_timer_prepare (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_timer_check ( + * pgm_sock_t* sock + * ) + */ + +START_TEST (test_check_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + fail_unless (TRUE == pgm_timer_check (sock), "check failed"); +} +END_TEST + +START_TEST (test_check_fail_001) +{ + gboolean expired = pgm_timer_check (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * pgm_time_t + * pgm_timer_expiration ( + * pgm_sock_t* sock + * ) + */ + +START_TEST (test_expiration_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + sock->next_poll = mock_pgm_time_now + pgm_secs(300); + fail_unless (pgm_secs(300) == pgm_timer_expiration (sock), "expiration failed"); +} +END_TEST + +START_TEST (test_expiration_fail_001) +{ + long expiration = pgm_timer_expiration (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_timer_dispatch ( + * pgm_sock_t* sock + * ) + */ + +START_TEST (test_dispatch_pass_001) +{ + pgm_sock_t* sock = generate_sock (); + fail_if (NULL == sock, "generate_sock failed"); + pgm_timer_dispatch (sock); +} +END_TEST + +START_TEST (test_dispatch_fail_001) +{ + pgm_timer_dispatch (NULL); + fail ("reached"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_prepare = tcase_create ("prepare"); + suite_add_tcase (s, tc_prepare); + tcase_add_test (tc_prepare, test_prepare_pass_001); + tcase_add_test_raise_signal (tc_prepare, test_prepare_fail_001, SIGABRT); + + TCase* tc_check = tcase_create ("check"); + suite_add_tcase (s, tc_check); + tcase_add_test (tc_check, test_check_pass_001); + tcase_add_test_raise_signal (tc_check, test_check_fail_001, SIGABRT); + + TCase* tc_expiration = tcase_create ("expiration"); + suite_add_tcase (s, tc_expiration); + tcase_add_test (tc_expiration, test_expiration_pass_001); + tcase_add_test_raise_signal (tc_expiration, test_expiration_fail_001, SIGABRT); + + TCase* tc_dispatch = tcase_create ("dispatch"); + suite_add_tcase (s, tc_dispatch); + tcase_add_test (tc_dispatch, test_dispatch_pass_001); + tcase_add_test_raise_signal (tc_dispatch, test_dispatch_fail_001, SIGABRT); + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/token and leaky bucket.txt b/3rdparty/openpgm-svn-r1135/pgm/token and leaky bucket.txt new file mode 100644 index 0000000..3efb9c7 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/token and leaky bucket.txt @@ -0,0 +1,12 @@ +leaky bucket: + + if (BUCKET->rate_limit > BUCKET->rate_per_sec) + BUCKET->rate_limit = BUCKET->rate_per_sec; + + +token bucket: + + guint bucket_limit; + + if (BUCKET->rate_limit > BUCKET->bucket_limit) + BUCKET->rate_limit = BUCKET->bucket_limit; diff --git a/3rdparty/openpgm-svn-r1135/pgm/tsi.c b/3rdparty/openpgm-svn-r1135/pgm/tsi.c new file mode 100644 index 0000000..5f9ae85 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/tsi.c @@ -0,0 +1,119 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * transport session ID helper functions. + * + * Copyright (c) 2006-2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + + +//#define TSI_DEBUG + + +/* locals */ + + +/* re-entrant form of pgm_tsi_print() + * + * returns number of bytes written to buffer on success, returns -1 on + * invalid parameters. + */ + +int +pgm_tsi_print_r ( + const pgm_tsi_t* restrict tsi, + char* restrict buf, + size_t bufsize + ) +{ + pgm_return_val_if_fail (NULL != tsi, -1); + pgm_return_val_if_fail (NULL != buf, -1); + pgm_return_val_if_fail (bufsize > 0, -1); + + const uint8_t* gsi = (const uint8_t*)tsi; + const uint16_t source_port = tsi->sport; + + return snprintf (buf, bufsize, "%i.%i.%i.%i.%i.%i.%i", + gsi[0], gsi[1], gsi[2], gsi[3], gsi[4], gsi[5], ntohs (source_port)); +} + +/* transform TSI to ASCII string form. + * + * on success, returns pointer to ASCII string. on error, returns NULL. + */ + +char* +pgm_tsi_print ( + const pgm_tsi_t* tsi + ) +{ + pgm_return_val_if_fail (tsi != NULL, NULL); + + static char buf[PGM_TSISTRLEN]; + pgm_tsi_print_r (tsi, buf, sizeof(buf)); + return buf; +} + +/* create hash value of TSI for use with GLib hash tables. + * + * on success, returns a hash value corresponding to the TSI. on error, fails + * on assert. + */ + +pgm_hash_t +pgm_tsi_hash ( + const void* p + ) +{ + const union { + pgm_tsi_t tsi; + uint32_t l[2]; + } *u = p; + +/* pre-conditions */ + pgm_assert (NULL != p); + + return u->l[0] ^ u->l[1]; +} + +/* compare two transport session identifier TSI values. + * + * returns TRUE if they are equal, FALSE if they are not. + */ + +bool +pgm_tsi_equal ( + const void* restrict p1, + const void* restrict p2 + ) +{ + const union { + pgm_tsi_t tsi; + uint32_t l[2]; + uint64_t ll; + } *restrict u1 = p1, *restrict u2 = p2; + +/* pre-conditions */ + pgm_assert (NULL != p1); + pgm_assert (NULL != p2); + + return (u1->l[0] == u2->l[0] && u1->l[1] == u2->l[1]); +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/tsi.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/tsi.c.c89.patch new file mode 100644 index 0000000..ff95ba8 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/tsi.c.c89.patch @@ -0,0 +1,33 @@ +--- tsi.c 2010-05-21 11:32:16.000000000 +0800 ++++ tsi.c89 2010-08-05 11:01:48.000000000 +0800 +@@ -46,11 +46,18 @@ + pgm_return_val_if_fail (NULL != buf, -1); + pgm_return_val_if_fail (bufsize > 0, -1); + ++ { + const uint8_t* gsi = (const uint8_t*)tsi; + const uint16_t source_port = tsi->sport; + ++#ifdef _MSC_VER ++ return _snprintf_s (buf, bufsize, _TRUNCATE, "%i.%i.%i.%i.%i.%i.%i", ++ gsi[0], gsi[1], gsi[2], gsi[3], gsi[4], gsi[5], ntohs (source_port)); ++#else + return snprintf (buf, bufsize, "%i.%i.%i.%i.%i.%i.%i", + gsi[0], gsi[1], gsi[2], gsi[3], gsi[4], gsi[5], ntohs (source_port)); ++#endif ++ } + } + + /* transform TSI to ASCII string form. +@@ -65,9 +72,11 @@ + { + pgm_return_val_if_fail (tsi != NULL, NULL); + ++ { + static char buf[PGM_TSISTRLEN]; + pgm_tsi_print_r (tsi, buf, sizeof(buf)); + return buf; ++ } + } + + /* create hash value of TSI for use with GLib hash tables. diff --git a/3rdparty/openpgm-svn-r1135/pgm/tsi_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/tsi_unittest.c new file mode 100644 index 0000000..fddff25 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/tsi_unittest.c @@ -0,0 +1,185 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for transport session ID helper functions. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#include +#include + + +/* mock state */ + +/* mock functions for external references */ + +size_t +pgm_transport_pkt_offset2 ( + const bool can_fragment, + const bool use_pgmcc + ) +{ + return 0; +} + + +#define TSI_DEBUG +#include "tsi.c" + + +/* target: + * gchar* + * pgm_tsi_print ( + * const pgm_tsi_t* tsi + * ) + */ + +START_TEST (test_print_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + fail_if (NULL == pgm_tsi_print (&tsi), "print failed"); +} +END_TEST + +START_TEST (test_print_pass_002) +{ + fail_unless (NULL == pgm_tsi_print (NULL), "print failed"); +} +END_TEST + +/* target: + * int + * pgm_tsi_print_r ( + * const pgm_tsi_t* tsi, + * char* buf, + * gsize bufsize + * ) + */ + +START_TEST (test_print_r_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + char buf[PGM_TSISTRLEN]; + fail_unless (pgm_tsi_print_r (&tsi, buf, sizeof(buf)) > 0, "print_r failed"); +} +END_TEST + +START_TEST (test_print_r_pass_002) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + char buf[PGM_TSISTRLEN]; + fail_unless (pgm_tsi_print_r (NULL, buf, sizeof(buf)) == -1, "print_r failed"); + fail_unless (pgm_tsi_print_r (&tsi, NULL, sizeof(buf)) == -1, "print_r failed"); + fail_unless (pgm_tsi_print_r (&tsi, buf, 0) == -1, "print_r failed"); +} +END_TEST + +/* target: + * gboolean + * pgm_tsi_equal ( + * gconstpointer tsi1, + * gconstpointer tsi2 + * ) + */ + +START_TEST (test_equal_pass_001) +{ + const pgm_tsi_t tsi1 = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const pgm_tsi_t tsi2 = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + fail_unless (pgm_tsi_equal (&tsi1, &tsi2), "equal failed"); +} +END_TEST + +START_TEST (test_equal_pass_002) +{ + const pgm_tsi_t tsi1 = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const pgm_tsi_t tsi2 = { { 9, 8, 7, 6, 5, 4 }, 2000 }; + fail_if (pgm_tsi_equal (&tsi1, &tsi2), "equal failed"); +} +END_TEST + +START_TEST (test_equal_fail_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + gboolean retval = pgm_tsi_equal (NULL, &tsi); + fail ("reached"); +} +END_TEST + +START_TEST (test_equal_fail_002) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + gboolean retval = pgm_tsi_equal (&tsi, NULL); + fail ("reached"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_print = tcase_create ("print"); + suite_add_tcase (s, tc_print); + tcase_add_test (tc_print, test_print_pass_001); + tcase_add_test (tc_print, test_print_pass_002); + + TCase* tc_print_r = tcase_create ("print-r"); + suite_add_tcase (s, tc_print_r); + tcase_add_test (tc_print_r, test_print_r_pass_001); + tcase_add_test (tc_print_r, test_print_r_pass_002); + + TCase* tc_equal = tcase_create ("equal"); + suite_add_tcase (s, tc_equal); + tcase_add_test (tc_equal, test_equal_pass_001); + tcase_add_test (tc_equal, test_equal_pass_002); + tcase_add_test_raise_signal (tc_equal, test_equal_fail_001, SIGABRT); + tcase_add_test_raise_signal (tc_equal, test_equal_fail_002, SIGABRT); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/txw.c b/3rdparty/openpgm-svn-r1135/pgm/txw.c new file mode 100644 index 0000000..36f4c53 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/txw.c @@ -0,0 +1,767 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * A basic transmit window: pointer array implementation. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __STDC_FORMAT_MACROS +#ifdef _MSC_VER +# include +#else +# include +#endif +#include +#include +#include + + +//#define TXW_DEBUG + +#ifndef TXW_DEBUG +# define PGM_DISABLE_ASSERT +#endif + + +/* testing function: is TSI null + * + * returns TRUE if null, returns FALSE if not null. + */ + +static inline +bool +pgm_tsi_is_null ( + const void*const tsi + ) +{ + const union { + pgm_tsi_t tsi; + uint32_t l[2]; + } *u = tsi; + +/* pre-conditions */ + pgm_assert (NULL != tsi); + + return (0 == u->l[0] && 0 == u->l[1]); +} + +/* returns the pointer at the given index of the window. responsibility + * is with the caller to verify a single user ownership. + */ + +static inline +struct pgm_sk_buff_t* +_pgm_txw_peek ( + const pgm_txw_t*const window, + const uint32_t sequence + ) +{ + struct pgm_sk_buff_t* skb; + +/* pre-conditions */ + pgm_assert (NULL != window); + + if (pgm_txw_is_empty (window)) + return NULL; + + if (pgm_uint32_gte (sequence, window->trail) && pgm_uint32_lte (sequence, window->lead)) + { + const uint_fast32_t index_ = sequence % pgm_txw_max_length (window); + skb = window->pdata[index_]; + pgm_assert (NULL != skb); + pgm_assert (pgm_skb_is_valid (skb)); + pgm_assert (pgm_tsi_is_null (&skb->tsi)); + } + else + skb = NULL; + + return skb; +} + +/* testing function: can a request be peeked from the retransmit queue. + * + * returns TRUE if request is available, returns FALSE if not available. + */ + +static inline +bool +pgm_txw_retransmit_can_peek ( + pgm_txw_t*const window + ) +{ + pgm_return_val_if_fail (NULL != window, FALSE); + return (NULL != pgm_txw_retransmit_try_peek (window)); +} + +/* sequence state must be smaller than PGM skbuff control buffer */ +PGM_STATIC_ASSERT(sizeof(struct pgm_txw_state_t) <= sizeof(((struct pgm_sk_buff_t*)0)->cb)); + +uint32_t +pgm_txw_get_unfolded_checksum ( + const struct pgm_sk_buff_t*const skb + ) +{ + const pgm_txw_state_t*const state = (const pgm_txw_state_t*const)&skb->cb; + return state->unfolded_checksum; +} + +void +pgm_txw_set_unfolded_checksum ( + struct pgm_sk_buff_t*const skb, + const uint32_t csum + ) +{ + pgm_txw_state_t* state = (pgm_txw_state_t*)&skb->cb; + state->unfolded_checksum = csum; +} + +void +pgm_txw_inc_retransmit_count ( + struct pgm_sk_buff_t*const skb + ) +{ + pgm_txw_state_t*const state = (pgm_txw_state_t*const)&skb->cb; + state->retransmit_count++; +} + +bool +pgm_txw_retransmit_is_empty ( + const pgm_txw_t*const window + ) +{ + pgm_assert (NULL != window); + return pgm_queue_is_empty (&window->retransmit_queue); +} + + +/* globals */ + +static void pgm_txw_remove_tail (pgm_txw_t*const); +static bool pgm_txw_retransmit_push_parity (pgm_txw_t*const, const uint32_t, const uint8_t); +static bool pgm_txw_retransmit_push_selective (pgm_txw_t*const, const uint32_t); + + +/* constructor for transmit window. zero-length windows are not permitted. + * + * returns pointer to window. + */ + +pgm_txw_t* +pgm_txw_create ( + const pgm_tsi_t*const tsi, + const uint16_t tpdu_size, + const uint32_t sqns, /* transmit window size in sequence numbers */ + const unsigned secs, /* size in seconds */ + const ssize_t max_rte, /* max bandwidth */ + const bool use_fec, + const uint8_t rs_n, + const uint8_t rs_k + ) +{ + pgm_txw_t* window; + +/* pre-conditions */ + pgm_assert (NULL != tsi); + if (sqns) { + pgm_assert_cmpuint (tpdu_size, ==, 0); + pgm_assert_cmpuint (sqns, >, 0); + pgm_assert_cmpuint (sqns & PGM_UINT32_SIGN_BIT, ==, 0); + pgm_assert_cmpuint (secs, ==, 0); + pgm_assert_cmpuint (max_rte, ==, 0); + } else { + pgm_assert_cmpuint (tpdu_size, >, 0); + pgm_assert_cmpuint (secs, >, 0); + pgm_assert_cmpuint (max_rte, >, 0); + } + if (use_fec) { + pgm_assert_cmpuint (rs_n, >, 0); + pgm_assert_cmpuint (rs_k, >, 0); + } + + pgm_debug ("create (tsi:%s max-tpdu:%" PRIu16 " sqns:%" PRIu32 " secs %u max-rte %zd use-fec:%s rs(n):%u rs(k):%u)", + pgm_tsi_print (tsi), + tpdu_size, sqns, secs, max_rte, + use_fec ? "YES" : "NO", + rs_n, rs_k); + +/* calculate transmit window parameters */ + pgm_assert (sqns || (tpdu_size && secs && max_rte)); + const unsigned alloc_sqns = sqns ? sqns : ( (secs * max_rte) / tpdu_size ); + window = pgm_malloc0 (sizeof(pgm_txw_t) + ( alloc_sqns * sizeof(struct pgm_sk_buff_t*) )); + window->tsi = tsi; + +/* empty state for transmission group boundaries to align. + * + * trail = 0, lead = -1 + */ + window->lead = -1; + window->trail = window->lead + 1; + +/* reed-solomon forward error correction */ + if (use_fec) { + window->parity_buffer = pgm_alloc_skb (tpdu_size); + window->tg_sqn_shift = pgm_power2_log2 (rs_k); + pgm_rs_create (&window->rs, rs_n, rs_k); + window->is_fec_enabled = 1; + } + +/* pointer array */ + window->alloc = alloc_sqns; + +/* post-conditions */ + pgm_assert_cmpuint (pgm_txw_max_length (window), ==, alloc_sqns); + pgm_assert_cmpuint (pgm_txw_length (window), ==, 0); + pgm_assert_cmpuint (pgm_txw_size (window), ==, 0); + pgm_assert (pgm_txw_is_empty (window)); + pgm_assert (!pgm_txw_is_full (window)); + pgm_assert (!pgm_txw_retransmit_can_peek (window)); + + return window; +} + +/* destructor for transmit window. must not be called more than once for same window. + */ + +void +pgm_txw_shutdown ( + pgm_txw_t*const window + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert_cmpuint (window->alloc, >, 0); + + pgm_debug ("shutdown (window:%p)", (const void*)window); + +/* contents of window */ + while (!pgm_txw_is_empty (window)) { + pgm_txw_remove_tail (window); + } + +/* window must now be empty */ + pgm_assert_cmpuint (pgm_txw_length (window), ==, 0); + pgm_assert_cmpuint (pgm_txw_size (window), ==, 0); + pgm_assert (pgm_txw_is_empty (window)); + pgm_assert (!pgm_txw_is_full (window)); + +/* retransmit queue must be empty */ + pgm_assert (!pgm_txw_retransmit_can_peek (window)); + +/* free reed-solomon state */ + if (window->is_fec_enabled) { + pgm_free_skb (window->parity_buffer); + pgm_rs_destroy (&window->rs); + } + +/* window */ + pgm_free (window); +} + +/* add skb to transmit window, taking ownership. window does not grow. + * PGM skbuff data/tail pointers must point to the PGM payload, and hence skb->len + * is allowed to be zero. + * + * side effects: + * + * 1) sequence number is set in skb. + * 2) window is updated with new skb. + * + * no return value. fatal error raised on invalid parameters. if window is full then + * an entry is dropped to fulfil the request. + * + * it is an error to try to free the skb after adding to the window. + */ + +void +pgm_txw_add ( + pgm_txw_t* const restrict window, + struct pgm_sk_buff_t* const restrict skb /* cannot be NULL */ + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (NULL != skb); + pgm_assert_cmpuint (pgm_txw_max_length (window), >, 0); + pgm_assert (pgm_skb_is_valid (skb)); + pgm_assert (((const pgm_list_t*)skb)->next == NULL); + pgm_assert (((const pgm_list_t*)skb)->prev == NULL); + pgm_assert (pgm_tsi_is_null (&skb->tsi)); + pgm_assert ((char*)skb->data > (char*)skb->head); + pgm_assert ((sizeof(struct pgm_header) + sizeof(struct pgm_data)) <= (size_t)((char*)skb->data - (char*)skb->head)); + + pgm_debug ("add (window:%p skb:%p)", (const char*)window, (const char*)skb); + + if (pgm_txw_is_full (window)) + { +/* transmit window advancement scheme dependent action here */ + pgm_txw_remove_tail (window); + } + +/* generate new sequence number */ + pgm_atomic_inc32 (&window->lead); + skb->sequence = window->lead; + +/* add skb to window */ + const uint_fast32_t index_ = skb->sequence % pgm_txw_max_length (window); + window->pdata[index_] = skb; + +/* statistics */ + window->size += skb->len; + +/* post-conditions */ + pgm_assert_cmpuint (pgm_txw_length (window), >, 0); + pgm_assert_cmpuint (pgm_txw_length (window), <=, pgm_txw_max_length (window)); +} + +/* peek an entry from the window for retransmission. + * + * returns pointer to skbuff on success, returns NULL on invalid parameters. + */ + +struct pgm_sk_buff_t* +pgm_txw_peek ( + const pgm_txw_t*const window, + const uint32_t sequence + ) +{ + pgm_debug ("peek (window:%p sequence:%" PRIu32 ")", + (const void*)window, sequence); + return _pgm_txw_peek (window, sequence); +} + +/* remove an entry from the trailing edge of the transmit window. + */ + +static +void +pgm_txw_remove_tail ( + pgm_txw_t* const window + ) +{ + struct pgm_sk_buff_t* skb; + pgm_txw_state_t* state; + + pgm_debug ("pgm_txw_remove_tail (window:%p)", (const void*)window); + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert (!pgm_txw_is_empty (window)); + + skb = _pgm_txw_peek (window, pgm_txw_trail (window)); + pgm_assert (NULL != skb); + pgm_assert (pgm_skb_is_valid (skb)); + pgm_assert (pgm_tsi_is_null (&skb->tsi)); + + state = (pgm_txw_state_t*)&skb->cb; + if (state->waiting_retransmit) { + pgm_queue_unlink (&window->retransmit_queue, (pgm_list_t*)skb); + state->waiting_retransmit = 0; + } + +/* statistics */ + window->size -= skb->len; + if (state->retransmit_count > 0) { + PGM_HISTOGRAM_COUNTS("Tx.RetransmitCount", state->retransmit_count); + } + if (state->nak_elimination_count > 0) { + PGM_HISTOGRAM_COUNTS("Tx.NakEliminationCount", state->nak_elimination_count); + } + +/* remove reference to skb */ + if (PGM_UNLIKELY(pgm_mem_gc_friendly)) { + const uint_fast32_t index_ = skb->sequence % pgm_txw_max_length (window); + window->pdata[index_] = NULL; + } + pgm_free_skb (skb); + +/* advance trailing pointer */ + pgm_atomic_inc32 (&window->trail); + +/* post-conditions */ + pgm_assert (!pgm_txw_is_full (window)); +} + +/* Try to add a sequence number to the retransmit queue, ignore if + * already there or no longer in the transmit window. + * + * For parity NAKs, we deal on the transmission group sequence number + * rather than the packet sequence number. To simplify managment we + * use the leading window packet to store the details of the entire + * transmisison group. Parity NAKs are ignored if the packet count is + * less than or equal to the count already queued for retransmission. + * + * returns FALSE if request was eliminated, returns TRUE if request was + * added to queue. + */ + +bool +pgm_txw_retransmit_push ( + pgm_txw_t* const window, + const uint32_t sequence, + const bool is_parity, /* parity NAK ⇒ sequence_number = transmission group | packet count */ + const uint8_t tg_sqn_shift + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert_cmpuint (tg_sqn_shift, <, 8 * sizeof(uint32_t)); + + pgm_debug ("retransmit_push (window:%p sequence:%" PRIu32 " is_parity:%s tg_sqn_shift:%u)", + (const void*)window, sequence, is_parity ? "TRUE" : "FALSE", tg_sqn_shift); + +/* early elimination */ + if (pgm_txw_is_empty (window)) + return FALSE; + + if (is_parity) + { + return pgm_txw_retransmit_push_parity (window, sequence, tg_sqn_shift); + } + else + { + return pgm_txw_retransmit_push_selective (window, sequence); + } +} + +static +bool +pgm_txw_retransmit_push_parity ( + pgm_txw_t* const window, + const uint32_t sequence, + const uint8_t tg_sqn_shift + ) +{ + struct pgm_sk_buff_t* skb; + pgm_txw_state_t* state; + +/* pre-conditions */ + pgm_assert (NULL != window); + pgm_assert_cmpuint (tg_sqn_shift, <, 8 * sizeof(uint32_t)); + + const uint32_t tg_sqn_mask = 0xffffffff << tg_sqn_shift; + const uint32_t nak_tg_sqn = sequence & tg_sqn_mask; /* left unshifted */ + const uint32_t nak_pkt_cnt = sequence & ~tg_sqn_mask; + skb = _pgm_txw_peek (window, nak_tg_sqn); + + if (NULL == skb) { + pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Transmission group lead #%" PRIu32 " not in window."), nak_tg_sqn); + return FALSE; + } + + pgm_assert (pgm_skb_is_valid (skb)); + pgm_assert (pgm_tsi_is_null (&skb->tsi)); + state = (pgm_txw_state_t*)&skb->cb; + +/* check if request can be eliminated */ + if (state->waiting_retransmit) + { + pgm_assert (NULL != ((const pgm_list_t*)skb)->next); + pgm_assert (NULL != ((const pgm_list_t*)skb)->prev); + if (state->pkt_cnt_requested < nak_pkt_cnt) { +/* more parity packets requested than currently scheduled, simply bump up the count */ + state->pkt_cnt_requested = nak_pkt_cnt; + } + state->nak_elimination_count++; + return FALSE; + } + else + { + pgm_assert (((const pgm_list_t*)skb)->next == NULL); + pgm_assert (((const pgm_list_t*)skb)->prev == NULL); + } + +/* new request */ + state->pkt_cnt_requested++; + pgm_queue_push_head_link (&window->retransmit_queue, (pgm_list_t*)skb); + pgm_assert (!pgm_queue_is_empty (&window->retransmit_queue)); + state->waiting_retransmit = 1; + return TRUE; +} + +static +bool +pgm_txw_retransmit_push_selective ( + pgm_txw_t* const window, + const uint32_t sequence + ) +{ + struct pgm_sk_buff_t* skb; + pgm_txw_state_t* state; + +/* pre-conditions */ + pgm_assert (NULL != window); + + skb = _pgm_txw_peek (window, sequence); + if (NULL == skb) { + pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Requested packet #%" PRIu32 " not in window."), sequence); + return FALSE; + } + + pgm_assert (pgm_skb_is_valid (skb)); + pgm_assert (pgm_tsi_is_null (&skb->tsi)); + state = (pgm_txw_state_t*)&skb->cb; + +/* check if request can be eliminated */ + if (state->waiting_retransmit) { + pgm_assert (!pgm_queue_is_empty (&window->retransmit_queue)); + state->nak_elimination_count++; + return FALSE; + } + + pgm_assert (((const pgm_list_t*)skb)->next == NULL); + pgm_assert (((const pgm_list_t*)skb)->prev == NULL); + +/* new request */ + pgm_queue_push_head_link (&window->retransmit_queue, (pgm_list_t*)skb); + pgm_assert (!pgm_queue_is_empty (&window->retransmit_queue)); + state->waiting_retransmit = 1; + return TRUE; +} + +/* try to peek a request from the retransmit queue + * + * return pointer of first skb in queue, or return NULL if the queue is empty. + */ + +struct pgm_sk_buff_t* +pgm_txw_retransmit_try_peek ( + pgm_txw_t* const window + ) +{ +/* pre-conditions */ + pgm_assert (NULL != window); + + pgm_debug ("retransmit_try_peek (window:%p)", (const void*)window); + +/* no lock required to detect presence of a request */ + pgm_list_t* tail_link = pgm_queue_peek_tail_link (&window->retransmit_queue); + if (PGM_UNLIKELY(NULL == tail_link)) { + pgm_debug ("retransmit queue empty on peek."); + return NULL; + } + + struct pgm_sk_buff_t* skb = (struct pgm_sk_buff_t*)tail_link; + pgm_assert (pgm_skb_is_valid (skb)); + pgm_txw_state_t* state = (pgm_txw_state_t*)&skb->cb; + + if (!state->waiting_retransmit) { + pgm_assert (((const pgm_list_t*)skb)->next == NULL); + pgm_assert (((const pgm_list_t*)skb)->prev == NULL); + } +/* packet payload still in transit */ + if (PGM_UNLIKELY(1 != pgm_atomic_read32 (&skb->users))) { + pgm_trace (PGM_LOG_ROLE_TX_WINDOW,_("Retransmit sqn #%" PRIu32 " is still in transit in transmit thread."), skb->sequence); + return NULL; + } + if (!state->pkt_cnt_requested) { + return skb; + } + +/* generate parity packet to satisify request */ + const uint8_t rs_h = state->pkt_cnt_sent % (window->rs.n - window->rs.k); + const uint32_t tg_sqn_mask = 0xffffffff << window->tg_sqn_shift; + const uint32_t tg_sqn = skb->sequence & tg_sqn_mask; + bool is_var_pktlen = FALSE; + bool is_op_encoded = FALSE; + uint16_t parity_length = 0; + const pgm_gf8_t* src[ window->rs.k ]; + for (uint_fast8_t i = 0; i < window->rs.k; i++) + { + const struct pgm_sk_buff_t* odata_skb = pgm_txw_peek (window, tg_sqn + i); + const uint16_t odata_tsdu_length = ntohs (odata_skb->pgm_header->pgm_tsdu_length); + if (!parity_length) + { + parity_length = odata_tsdu_length; + } + else if (odata_tsdu_length != parity_length) + { + is_var_pktlen = TRUE; + if (odata_tsdu_length > parity_length) + parity_length = odata_tsdu_length; + } + + src[i] = odata_skb->data; + if (odata_skb->pgm_header->pgm_options & PGM_OPT_PRESENT) { + is_op_encoded = TRUE; + } + } + +/* construct basic PGM header to be completed by send_rdata() */ + skb = window->parity_buffer; + skb->data = skb->tail = skb->head = skb + 1; + +/* space for PGM header */ + pgm_skb_put (skb, sizeof(struct pgm_header)); + + skb->pgm_header = skb->data; + skb->pgm_data = (void*)( skb->pgm_header + 1 ); + memcpy (skb->pgm_header->pgm_gsi, &window->tsi->gsi, sizeof(pgm_gsi_t)); + skb->pgm_header->pgm_options = PGM_OPT_PARITY; + +/* append actual TSDU length if variable length packets, zero pad as necessary. + */ + if (is_var_pktlen) + { + skb->pgm_header->pgm_options |= PGM_OPT_VAR_PKTLEN; + + for (uint_fast8_t i = 0; i < window->rs.k; i++) + { + struct pgm_sk_buff_t* odata_skb = pgm_txw_peek (window, tg_sqn + i); + const uint16_t odata_tsdu_length = ntohs (odata_skb->pgm_header->pgm_tsdu_length); + + pgm_assert (odata_tsdu_length == odata_skb->len); + pgm_assert (parity_length >= odata_tsdu_length); + + if (!odata_skb->zero_padded) { + memset (odata_skb->tail, 0, parity_length - odata_tsdu_length); + *(uint16_t*)((char*)odata_skb->data + parity_length) = odata_tsdu_length; + odata_skb->zero_padded = 1; + } + } + parity_length += 2; + } + + skb->pgm_header->pgm_tsdu_length = htons (parity_length); + +/* space for DATA */ + pgm_skb_put (skb, sizeof(struct pgm_data) + parity_length); + + skb->pgm_data->data_sqn = htonl ( tg_sqn | rs_h ); + + void* data_bytes = skb->pgm_data + 1; + +/* encode every option separately, currently only one applies: opt_fragment + */ + if (is_op_encoded) + { + skb->pgm_header->pgm_options |= PGM_OPT_PRESENT; + + struct pgm_opt_fragment null_opt_fragment; + const pgm_gf8_t* opt_src[ window->rs.k ]; + memset (&null_opt_fragment, 0, sizeof(null_opt_fragment)); + *(uint8_t*)&null_opt_fragment |= PGM_OP_ENCODED_NULL; + for (uint_fast8_t i = 0; i < window->rs.k; i++) + { + const struct pgm_sk_buff_t* odata_skb = pgm_txw_peek (window, tg_sqn + i); + + if (odata_skb->pgm_opt_fragment) + { + pgm_assert (odata_skb->pgm_header->pgm_options & PGM_OPT_PRESENT); +/* skip three bytes of header */ + opt_src[i] = (pgm_gf8_t*)((char*)odata_skb->pgm_opt_fragment + sizeof (struct pgm_opt_header)); + } + else + { + opt_src[i] = (pgm_gf8_t*)&null_opt_fragment; + } + } + +/* add options to this rdata packet */ + const uint16_t opt_total_length = sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment); + +/* add space for PGM options */ + pgm_skb_put (skb, opt_total_length); + + struct pgm_opt_length* opt_len = data_bytes; + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( opt_total_length ); + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fragment); + opt_header->opt_reserved = PGM_OP_ENCODED; + struct pgm_opt_fragment* opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + +/* The cast below is the correct way to handle the problem. + * The (void *) cast is to avoid a GCC warning like: + * + * "warning: dereferencing type-punned pointer will break strict-aliasing rules" + */ + pgm_rs_encode (&window->rs, + opt_src, + window->rs.k + rs_h, + (pgm_gf8_t*)((char*)opt_fragment + sizeof(struct pgm_opt_header)), + sizeof(struct pgm_opt_fragment) - sizeof(struct pgm_opt_header)); + + data_bytes = opt_fragment + 1; + } + +/* encode payload */ + pgm_rs_encode (&window->rs, + src, + window->rs.k + rs_h, + data_bytes, + parity_length); + +/* calculate partial checksum */ + const uint16_t tsdu_length = ntohs (skb->pgm_header->pgm_tsdu_length); + state->unfolded_checksum = pgm_csum_partial ((char*)skb->tail - tsdu_length, tsdu_length, 0); + return skb; +} + +/* remove head entry from retransmit queue, will fail on assertion if queue is empty. + */ + +void +pgm_txw_retransmit_remove_head ( + pgm_txw_t* const window + ) +{ + struct pgm_sk_buff_t* skb; + pgm_txw_state_t* state; + +/* pre-conditions */ + pgm_assert (NULL != window); + + pgm_debug ("retransmit_remove_head (window:%p)", + (const void*)window); + +/* tail link is valid without lock */ + pgm_list_t* tail_link = pgm_queue_peek_tail_link (&window->retransmit_queue); + +/* link must be valid for pop */ + pgm_assert (NULL != tail_link); + + skb = (struct pgm_sk_buff_t*)tail_link; + pgm_assert (pgm_skb_is_valid (skb)); + pgm_assert (pgm_tsi_is_null (&skb->tsi)); + state = (pgm_txw_state_t*)&skb->cb; + if (!state->waiting_retransmit) + { + pgm_assert (((const pgm_list_t*)skb)->next == NULL); + pgm_assert (((const pgm_list_t*)skb)->prev == NULL); + } + if (state->pkt_cnt_requested) + { + state->pkt_cnt_sent++; + +/* remove if all requested parity packets have been sent */ + if (state->pkt_cnt_sent == state->pkt_cnt_requested) { + pgm_queue_pop_tail_link (&window->retransmit_queue); + state->waiting_retransmit = 0; + } + } + else /* selective request */ + { + pgm_queue_pop_tail_link (&window->retransmit_queue); + state->waiting_retransmit = 0; + } +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/txw.c.c89.patch b/3rdparty/openpgm-svn-r1135/pgm/txw.c.c89.patch new file mode 100644 index 0000000..033d337 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/txw.c.c89.patch @@ -0,0 +1,223 @@ +--- txw.c 2010-08-05 11:07:09.000000000 +0800 ++++ txw.c89 2010-08-05 11:11:36.000000000 +0800 +@@ -192,7 +192,7 @@ + pgm_assert_cmpuint (rs_k, >, 0); + } + +- pgm_debug ("create (tsi:%s max-tpdu:%" PRIu16 " sqns:%" PRIu32 " secs %u max-rte %zd use-fec:%s rs(n):%u rs(k):%u)", ++ pgm_debug ("create (tsi:%s max-tpdu:%" PRIu16 " sqns:%" PRIu32 " secs %u max-rte %ld use-fec:%s rs(n):%u rs(k):%u)", + pgm_tsi_print (tsi), + tpdu_size, sqns, secs, max_rte, + use_fec ? "YES" : "NO", +@@ -200,6 +200,7 @@ + + /* calculate transmit window parameters */ + pgm_assert (sqns || (tpdu_size && secs && max_rte)); ++ { + const unsigned alloc_sqns = sqns ? sqns : ( (secs * max_rte) / tpdu_size ); + window = pgm_malloc0 (sizeof(pgm_txw_t) + ( alloc_sqns * sizeof(struct pgm_sk_buff_t*) )); + window->tsi = tsi; +@@ -231,6 +232,7 @@ + pgm_assert (!pgm_txw_retransmit_can_peek (window)); + + return window; ++ } + } + + /* destructor for transmit window. must not be called more than once for same window. +@@ -316,6 +318,7 @@ + skb->sequence = window->lead; + + /* add skb to window */ ++ { + const uint_fast32_t index_ = skb->sequence % pgm_txw_max_length (window); + window->pdata[index_] = skb; + +@@ -325,6 +328,7 @@ + /* post-conditions */ + pgm_assert_cmpuint (pgm_txw_length (window), >, 0); + pgm_assert_cmpuint (pgm_txw_length (window), <=, pgm_txw_max_length (window)); ++ } + } + + /* peek an entry from the window for retransmission. +@@ -452,6 +456,7 @@ + pgm_assert (NULL != window); + pgm_assert_cmpuint (tg_sqn_shift, <, 8 * sizeof(uint32_t)); + ++ { + const uint32_t tg_sqn_mask = 0xffffffff << tg_sqn_shift; + const uint32_t nak_tg_sqn = sequence & tg_sqn_mask; /* left unshifted */ + const uint32_t nak_pkt_cnt = sequence & ~tg_sqn_mask; +@@ -490,6 +495,7 @@ + pgm_assert (!pgm_queue_is_empty (&window->retransmit_queue)); + state->waiting_retransmit = 1; + return TRUE; ++ } + } + + static +@@ -548,14 +554,17 @@ + pgm_debug ("retransmit_try_peek (window:%p)", (const void*)window); + + /* no lock required to detect presence of a request */ ++ { + pgm_list_t* tail_link = pgm_queue_peek_tail_link (&window->retransmit_queue); + if (PGM_UNLIKELY(NULL == tail_link)) { + pgm_debug ("retransmit queue empty on peek."); + return NULL; + } + ++ { + struct pgm_sk_buff_t* skb = (struct pgm_sk_buff_t*)tail_link; + pgm_assert (pgm_skb_is_valid (skb)); ++ { + pgm_txw_state_t* state = (pgm_txw_state_t*)&skb->cb; + + if (!state->waiting_retransmit) { +@@ -572,14 +581,17 @@ + } + + /* generate parity packet to satisify request */ ++ { + const uint8_t rs_h = state->pkt_cnt_sent % (window->rs.n - window->rs.k); + const uint32_t tg_sqn_mask = 0xffffffff << window->tg_sqn_shift; + const uint32_t tg_sqn = skb->sequence & tg_sqn_mask; + bool is_var_pktlen = FALSE; + bool is_op_encoded = FALSE; + uint16_t parity_length = 0; +- const pgm_gf8_t* src[ window->rs.k ]; +- for (uint_fast8_t i = 0; i < window->rs.k; i++) ++ const pgm_gf8_t** src = pgm_newa (pgm_gf8_t*, window->rs.k); ++ { ++ uint_fast8_t i; ++ for (i = 0; i < window->rs.k; i++) + { + const struct pgm_sk_buff_t* odata_skb = pgm_txw_peek (window, tg_sqn + i); + const uint16_t odata_tsdu_length = ntohs (odata_skb->pgm_header->pgm_tsdu_length); +@@ -599,6 +611,7 @@ + is_op_encoded = TRUE; + } + } ++ } + + /* construct basic PGM header to be completed by send_rdata() */ + skb = window->parity_buffer; +@@ -618,7 +631,9 @@ + { + skb->pgm_header->pgm_options |= PGM_OPT_VAR_PKTLEN; + +- for (uint_fast8_t i = 0; i < window->rs.k; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < window->rs.k; i++) + { + struct pgm_sk_buff_t* odata_skb = pgm_txw_peek (window, tg_sqn + i); + const uint16_t odata_tsdu_length = ntohs (odata_skb->pgm_header->pgm_tsdu_length); +@@ -632,6 +647,7 @@ + odata_skb->zero_padded = 1; + } + } ++ } + parity_length += 2; + } + +@@ -642,6 +658,7 @@ + + skb->pgm_data->data_sqn = htonl ( tg_sqn | rs_h ); + ++ { + void* data_bytes = skb->pgm_data + 1; + + /* encode every option separately, currently only one applies: opt_fragment +@@ -650,11 +667,14 @@ + { + skb->pgm_header->pgm_options |= PGM_OPT_PRESENT; + ++ { + struct pgm_opt_fragment null_opt_fragment; +- const pgm_gf8_t* opt_src[ window->rs.k ]; ++ const pgm_gf8_t** opt_src = pgm_newa (pgm_gf8_t*, window->rs.k); + memset (&null_opt_fragment, 0, sizeof(null_opt_fragment)); + *(uint8_t*)&null_opt_fragment |= PGM_OP_ENCODED_NULL; +- for (uint_fast8_t i = 0; i < window->rs.k; i++) ++ { ++ uint_fast8_t i; ++ for (i = 0; i < window->rs.k; i++) + { + const struct pgm_sk_buff_t* odata_skb = pgm_txw_peek (window, tg_sqn + i); + +@@ -669,8 +689,10 @@ + opt_src[i] = (pgm_gf8_t*)&null_opt_fragment; + } + } ++ } + + /* add options to this rdata packet */ ++ { + const uint16_t opt_total_length = sizeof(struct pgm_opt_length) + + sizeof(struct pgm_opt_header) + + sizeof(struct pgm_opt_fragment); +@@ -678,14 +700,17 @@ + /* add space for PGM options */ + pgm_skb_put (skb, opt_total_length); + ++ { + struct pgm_opt_length* opt_len = data_bytes; + opt_len->opt_type = PGM_OPT_LENGTH; + opt_len->opt_length = sizeof(struct pgm_opt_length); + opt_len->opt_total_length = htons ( opt_total_length ); ++ { + struct pgm_opt_header* opt_header = (struct pgm_opt_header*)(opt_len + 1); + opt_header->opt_type = PGM_OPT_FRAGMENT | PGM_OPT_END; + opt_header->opt_length = sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fragment); + opt_header->opt_reserved = PGM_OP_ENCODED; ++ { + struct pgm_opt_fragment* opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1); + + /* The cast below is the correct way to handle the problem. +@@ -700,6 +725,11 @@ + sizeof(struct pgm_opt_fragment) - sizeof(struct pgm_opt_header)); + + data_bytes = opt_fragment + 1; ++ } ++ } ++ } ++ } ++ } + } + + /* encode payload */ +@@ -710,9 +740,16 @@ + parity_length); + + /* calculate partial checksum */ ++ { + const uint16_t tsdu_length = ntohs (skb->pgm_header->pgm_tsdu_length); + state->unfolded_checksum = pgm_csum_partial ((char*)skb->tail - tsdu_length, tsdu_length, 0); + return skb; ++ } ++ } ++ } ++ } ++ } ++ } + } + + /* remove head entry from retransmit queue, will fail on assertion if queue is empty. +@@ -733,6 +770,7 @@ + (const void*)window); + + /* tail link is valid without lock */ ++ { + pgm_list_t* tail_link = pgm_queue_peek_tail_link (&window->retransmit_queue); + + /* link must be valid for pop */ +@@ -762,6 +800,7 @@ + pgm_queue_pop_tail_link (&window->retransmit_queue); + state->waiting_retransmit = 0; + } ++ } + } + + /* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/txw_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/txw_unittest.c new file mode 100644 index 0000000..bec079b --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/txw_unittest.c @@ -0,0 +1,743 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for transmit window. + * + * Copyright (c) 2009 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + + +/* mock global */ + +#define pgm_histogram_add mock_pgm_histogram_add +#define pgm_rs_create mock_pgm_rs_create +#define pgm_rs_destroy mock_pgm_rs_destroy +#define pgm_rs_encode mock_pgm_rs_encode +#define pgm_compat_csum_partial mock_pgm_compat_csum_partial +#define pgm_histogram_init mock_pgm_histogram_init + +#define TXW_DEBUG +#include "txw.c" + + +/** reed-solomon module */ +void +mock_pgm_rs_create ( + pgm_rs_t* rs, + uint8_t n, + uint8_t k + ) +{ +} + +void +mock_pgm_rs_destroy ( + pgm_rs_t* rs + ) +{ +} + +void +mock_pgm_rs_encode( + pgm_rs_t* rs, + const pgm_gf8_t** src, + const uint8_t offset, + pgm_gf8_t* dst, + const uint16_t len + ) +{ +} + +/** checksum module */ +uint32_t +mock_pgm_compat_csum_partial ( + const void* addr, + uint16_t len, + uint32_t csum + ) +{ + return 0x0; +} + +void +mock_pgm_histogram_init ( + pgm_histogram_t* histogram + ) +{ +} + +void +mock_pgm_histogram_add ( + pgm_histogram_t* histogram, + int value + ) +{ +} + + +/* mock functions for external references */ + +size_t +pgm_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + + +/* generate valid skb, data pointer pointing to PGM payload + */ +static +struct pgm_sk_buff_t* +generate_valid_skb (void) +{ + const guint16 tsdu_length = 1000; + const guint16 header_length = sizeof(struct pgm_header) + sizeof(struct pgm_data); + struct pgm_sk_buff_t* skb = pgm_alloc_skb (1500); +/* fake but valid transport and timestamp */ + skb->sock = (pgm_sock_t*)0x1; + skb->tstamp = 1; +/* header */ + pgm_skb_reserve (skb, header_length); + memset (skb->head, 0, header_length); + skb->pgm_header = (struct pgm_header*)skb->head; + skb->pgm_data = (struct pgm_data*)(skb->pgm_header + 1); + skb->pgm_header->pgm_type = PGM_ODATA; + skb->pgm_header->pgm_tsdu_length = g_htons (tsdu_length); +/* DATA */ + pgm_skb_put (skb, tsdu_length); + return skb; +} + +/* target: + * pgm_txw_t* + * pgm_txw_create ( + * const pgm_tsi_t* const tsi, + * const guint16 tpdu_size, + * const guint32 sqns, + * const guint secs, + * const guint max_rte, + * const gboolean use_fec, + * const guint rs_n, + * const guint rs_k + * ) + */ + +/* vanilla sequence count window */ +START_TEST (test_create_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + fail_if (NULL == pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0), "create failed"); +} +END_TEST + +/* vanilla time based window */ +START_TEST (test_create_pass_002) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + fail_if (NULL == pgm_txw_create (&tsi, 1500, 0, 60, 800000, FALSE, 0, 0), "create failed"); +} +END_TEST + +/* jumbo frame */ +START_TEST (test_create_pass_003) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + fail_if (NULL == pgm_txw_create (&tsi, 9000, 0, 60, 800000, FALSE, 0, 0), "create failed"); +} +END_TEST + +/* max frame */ +START_TEST (test_create_pass_004) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + fail_if (NULL == pgm_txw_create (&tsi, UINT16_MAX, 0, 60, 800000, FALSE, 0, 0), "create failed"); +} +END_TEST + +/* invalid tpdu size */ +START_TEST (test_create_fail_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const pgm_txw_t* window = pgm_txw_create (&tsi, 0, 0, 60, 800000, FALSE, 0, 0); + fail ("reached"); +} +END_TEST + +/* no specified sequence count or time value */ +START_TEST (test_create_fail_002) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const pgm_txw_t* window = pgm_txw_create (&tsi, 0, 0, 0, 800000, FALSE, 0, 0); + fail ("reached"); +} +END_TEST + +/* no specified rate */ +START_TEST (test_create_fail_003) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const pgm_txw_t* window = pgm_txw_create (&tsi, 0, 0, 60, 0, FALSE, 0, 0); + fail ("reached"); +} +END_TEST + +/* all invalid */ +START_TEST (test_create_fail_004) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + const pgm_txw_t* window = pgm_txw_create (NULL, 0, 0, 0, 0, FALSE, 0, 0); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_txw_shutdown ( + * pgm_txw_t* const window + * ) + */ + +START_TEST (test_shutdown_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + pgm_txw_shutdown (window); +} +END_TEST + +START_TEST (test_shutdown_fail_001) +{ + pgm_txw_shutdown (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_txw_add ( + * pgm_txw_t* const window, + * struct pgm_sk_buff_t* const skb + * ) + * failures raise assert errors and stop process execution. + */ + +START_TEST (test_add_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + pgm_txw_shutdown (window); +} +END_TEST + +/* null skb */ +START_TEST (test_add_fail_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + pgm_txw_add (window, NULL); + fail ("reached"); +} +END_TEST + +/* null window */ +START_TEST (test_add_fail_002) +{ + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (NULL, skb); + fail ("reached"); +} +END_TEST + +/* null skb content */ +START_TEST (test_add_fail_003) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + char buffer[1500]; + memset (buffer, 0, sizeof(buffer)); + pgm_txw_add (window, (struct pgm_sk_buff_t*)buffer); + fail ("reached"); +} +END_TEST + +/* target: + * struct pgm_sk_buff_t* + * pgm_txw_peek ( + * pgm_txw_t* const window, + * const guint32 sequence + * ) + */ + +START_TEST (test_peek_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + fail_unless (skb == pgm_txw_peek (window, window->trail), "peek failed"); + pgm_txw_shutdown (window); +} +END_TEST + +/* null window */ +START_TEST (test_peek_fail_001) +{ + const struct pgm_sk_buff_t* skb = pgm_txw_peek (NULL, 0); + fail ("reached"); +} +END_TEST + +/* empty window */ +START_TEST (test_peek_fail_002) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + fail_unless (NULL == pgm_txw_peek (window, window->trail), "peek failed"); + pgm_txw_shutdown (window); +} +END_TEST + +/** inline function tests **/ +/* pgm_txw_max_length () + */ +START_TEST (test_max_length_pass_001) +{ + const guint window_length = 100; + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, window_length, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + fail_unless (window_length == pgm_txw_max_length (window), "max_length failed"); + pgm_txw_shutdown (window); +} +END_TEST + +START_TEST (test_max_length_fail_001) +{ + const size_t answer = pgm_txw_max_length (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_txw_length () + */ +START_TEST (test_length_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + fail_unless (0 == pgm_txw_length (window), "length failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + fail_unless (1 == pgm_txw_length (window), "length failed"); + pgm_txw_shutdown (window); +} +END_TEST + +START_TEST (test_length_fail_001) +{ + const uint32_t answer = pgm_txw_length (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_txw_size () + */ +START_TEST (test_size_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + fail_unless (0 == pgm_txw_size (window), "size failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + fail_unless (1000 == pgm_txw_size (window), "size failed"); + pgm_txw_shutdown (window); +} +END_TEST + +START_TEST (test_size_fail_001) +{ + const size_t answer = pgm_txw_size (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_txw_is_empty + */ +START_TEST (test_is_empty_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + fail_unless (pgm_txw_is_empty (window), "is_empty failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + fail_if (pgm_txw_is_empty (window), "is_empty failed"); + pgm_txw_shutdown (window); +} +END_TEST + +START_TEST (test_is_empty_fail_001) +{ + const bool answer = pgm_txw_is_empty (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_txw_is_full + */ +START_TEST (test_is_full_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 1, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + fail_if (pgm_txw_is_full (window), "is_full failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + fail_unless (pgm_txw_is_full (window), "is_full failed"); + pgm_txw_shutdown (window); +} +END_TEST + +START_TEST (test_is_full_fail_001) +{ + const bool answer = pgm_txw_is_full (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_txw_lead + */ +START_TEST (test_lead_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + guint32 lead = pgm_txw_lead (window); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + fail_unless (lead + 1 == pgm_txw_lead (window), "lead failed"); + pgm_txw_shutdown (window); +} +END_TEST + +START_TEST (test_lead_fail_001) +{ + const uint32_t answer = pgm_txw_lead (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_txw_next_lead + */ +START_TEST (test_next_lead_pass_001) +{ + const guint window_length = 100; + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, window_length, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + guint32 next_lead = pgm_txw_next_lead (window); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + fail_unless (next_lead == pgm_txw_lead (window), "lead failed"); + pgm_txw_shutdown (window); +} +END_TEST + +START_TEST (test_next_lead_fail_001) +{ + const uint32_t answer = pgm_txw_next_lead (NULL); + fail ("reached"); +} +END_TEST + +/* pgm_txw_trail + */ +START_TEST (test_trail_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 1, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); +/* does not advance with adding skb */ + guint32 trail = pgm_txw_trail (window); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + fail_unless (trail == pgm_txw_trail (window), "trail failed"); +/* does advance when filling up window */ + skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + fail_if (trail == pgm_txw_trail (window), "trail failed"); + pgm_txw_shutdown (window); +} +END_TEST + +START_TEST (test_trail_fail_001) +{ + const uint32_t answer = pgm_txw_trail (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * bool + * pgm_txw_retransmit_push ( + * pgm_txw_t* const window, + * const uint32_t sequence, + * const bool is_parity, + * const uint8_t tg_sqn_shift + * ) + */ + +START_TEST (test_retransmit_push_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); +/* empty window invalidates all requests */ + fail_unless (FALSE == pgm_txw_retransmit_push (window, window->trail, FALSE, 0), "retransmit_push failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); +/* first request */ + fail_unless (TRUE == pgm_txw_retransmit_push (window, window->trail, FALSE, 0), "retransmit_push failed"); +/* second request eliminated */ + fail_unless (FALSE == pgm_txw_retransmit_push (window, window->trail, FALSE, 0), "retransmit_push failed"); + pgm_txw_shutdown (window); +} +END_TEST + +START_TEST (test_retransmit_push_fail_001) +{ + const bool answer = pgm_txw_retransmit_push (NULL, 0, FALSE, 0); + fail ("reached"); +} +END_TEST + +/* target: + * struct pgm_sk_buff_t* + * pgm_txw_retransmit_try_peek ( + * pgm_txw_t* const window + * ) + */ + +START_TEST (test_retransmit_try_peek_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + fail_unless (1 == pgm_txw_retransmit_push (window, window->trail, FALSE, 0), "retransmit_push failed"); + fail_unless (NULL != pgm_txw_retransmit_try_peek (window), "retransmit_try_peek failed"); + pgm_txw_shutdown (window); +} +END_TEST + +/* null window */ +START_TEST (test_retransmit_try_peek_fail_001) +{ + const struct pgm_sk_buff_t* skb = pgm_txw_retransmit_try_peek (NULL); + fail ("reached"); +} +END_TEST + +/* target: + * void + * pgm_txw_retransmit_remove_head ( + * pgm_txw_t* const window + * ) + */ + +START_TEST (test_retransmit_remove_head_pass_001) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + struct pgm_sk_buff_t* skb = generate_valid_skb (); + fail_if (NULL == skb, "generate_valid_skb failed"); + pgm_txw_add (window, skb); + fail_unless (1 == pgm_txw_retransmit_push (window, window->trail, FALSE, 0), "retransmit_push failed"); + fail_unless (NULL != pgm_txw_retransmit_try_peek (window), "retransmit_try_peek failed"); + pgm_txw_retransmit_remove_head (window); + pgm_txw_shutdown (window); +} +END_TEST + +/* null window */ +START_TEST (test_retransmit_remove_head_fail_001) +{ + pgm_txw_retransmit_remove_head (NULL); + fail ("reached"); +} +END_TEST + +/* empty retransmit queue */ +START_TEST (test_retransmit_remove_head_fail_002) +{ + const pgm_tsi_t tsi = { { 1, 2, 3, 4, 5, 6 }, 1000 }; + pgm_txw_t* window = pgm_txw_create (&tsi, 0, 100, 0, 0, FALSE, 0, 0); + fail_if (NULL == window, "create failed"); + pgm_txw_retransmit_remove_head (window); + fail ("reached"); +} +END_TEST + +static +Suite* +make_test_suite (void) +{ + Suite* s; + + s = suite_create (__FILE__); + + TCase* tc_create = tcase_create ("create"); + suite_add_tcase (s, tc_create); + tcase_add_test (tc_create, test_create_pass_001); + tcase_add_test (tc_create, test_create_pass_002); + tcase_add_test (tc_create, test_create_pass_003); + tcase_add_test (tc_create, test_create_pass_004); + tcase_add_test_raise_signal (tc_create, test_create_fail_001, SIGABRT); + tcase_add_test_raise_signal (tc_create, test_create_fail_002, SIGABRT); + tcase_add_test_raise_signal (tc_create, test_create_fail_003, SIGABRT); + tcase_add_test_raise_signal (tc_create, test_create_fail_004, SIGABRT); + + TCase* tc_shutdown = tcase_create ("shutdown"); + suite_add_tcase (s, tc_shutdown); + tcase_add_test (tc_shutdown, test_shutdown_pass_001); + tcase_add_test_raise_signal (tc_shutdown, test_shutdown_fail_001, SIGABRT); + + TCase* tc_add = tcase_create ("add"); + suite_add_tcase (s, tc_add); + tcase_add_test (tc_add, test_add_pass_001); + tcase_add_test_raise_signal (tc_add, test_add_fail_001, SIGABRT); + tcase_add_test_raise_signal (tc_add, test_add_fail_002, SIGABRT); + tcase_add_test_raise_signal (tc_add, test_add_fail_003, SIGABRT); + + TCase* tc_peek = tcase_create ("peek"); + suite_add_tcase (s, tc_peek); + tcase_add_test (tc_peek, test_peek_pass_001); + tcase_add_test_raise_signal (tc_peek, test_peek_fail_001, SIGABRT); +/* logical not fatal errors */ + tcase_add_test (tc_peek, test_peek_fail_002); + + TCase* tc_max_length = tcase_create ("max-length"); + suite_add_tcase (s, tc_max_length); + tcase_add_test (tc_max_length, test_max_length_pass_001); + tcase_add_test_raise_signal (tc_max_length, test_max_length_fail_001, SIGABRT); + + TCase* tc_length = tcase_create ("length"); + suite_add_tcase (s, tc_length); + tcase_add_test (tc_length, test_length_pass_001); + tcase_add_test_raise_signal (tc_length, test_length_fail_001, SIGABRT); + + TCase* tc_size = tcase_create ("size"); + suite_add_tcase (s, tc_size); + tcase_add_test (tc_size, test_size_pass_001); + tcase_add_test_raise_signal (tc_size, test_size_fail_001, SIGABRT); + + TCase* tc_is_empty = tcase_create ("is-empty"); + suite_add_tcase (s, tc_is_empty); + tcase_add_test (tc_is_empty, test_is_empty_pass_001); + tcase_add_test_raise_signal (tc_is_empty, test_is_empty_fail_001, SIGABRT); + TCase* tc_is_full = tcase_create ("is-full"); + suite_add_tcase (s, tc_is_full); + tcase_add_test (tc_is_full, test_is_full_pass_001); + tcase_add_test_raise_signal (tc_is_full, test_is_full_fail_001, SIGABRT); + + TCase* tc_lead = tcase_create ("lead"); + suite_add_tcase (s, tc_lead); + tcase_add_test (tc_lead, test_lead_pass_001); + tcase_add_test_raise_signal (tc_lead, test_lead_fail_001, SIGABRT); + + TCase* tc_next_lead = tcase_create ("next-lead"); + suite_add_tcase (s, tc_next_lead); + tcase_add_test (tc_next_lead, test_next_lead_pass_001); + tcase_add_test_raise_signal (tc_next_lead, test_next_lead_fail_001, SIGABRT); + + TCase* tc_trail = tcase_create ("trail"); + suite_add_tcase (s, tc_trail); + tcase_add_test (tc_trail, test_trail_pass_001); + tcase_add_test_raise_signal (tc_trail, test_trail_fail_001, SIGABRT); + + TCase* tc_retransmit_push = tcase_create ("retransmit-push"); + suite_add_tcase (s, tc_retransmit_push); + tcase_add_test (tc_retransmit_push, test_retransmit_push_pass_001); + tcase_add_test_raise_signal (tc_retransmit_push, test_retransmit_push_fail_001, SIGABRT); + + TCase* tc_retransmit_try_peek = tcase_create ("retransmit-try-peek"); + suite_add_tcase (s, tc_retransmit_try_peek); + tcase_add_test (tc_retransmit_try_peek, test_retransmit_try_peek_pass_001); + tcase_add_test_raise_signal (tc_retransmit_try_peek, test_retransmit_try_peek_fail_001, SIGABRT); + + TCase* tc_retransmit_remove_head = tcase_create ("retransmit-remove-head"); + suite_add_tcase (s, tc_retransmit_remove_head); + tcase_add_test (tc_retransmit_remove_head, test_retransmit_remove_head_pass_001); + tcase_add_test_raise_signal (tc_retransmit_remove_head, test_retransmit_remove_head_fail_001, SIGABRT); + tcase_add_test_raise_signal (tc_retransmit_remove_head, test_retransmit_remove_head_fail_002, SIGABRT); + + return s; +} + +static +Suite* +make_master_suite (void) +{ + Suite* s = suite_create ("Master"); + return s; +} + +int +main (void) +{ + SRunner* sr = srunner_create (make_master_suite ()); + srunner_add_suite (sr, make_test_suite ()); + srunner_run_all (sr, CK_ENV); + int number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +/* eof */ diff --git a/3rdparty/openpgm-svn-r1135/pgm/valgrind.supp b/3rdparty/openpgm-svn-r1135/pgm/valgrind.supp new file mode 100644 index 0000000..ea74d2d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/valgrind.supp @@ -0,0 +1,147 @@ +##----------------------------------------------------------------------## +## Suppressions to run OpenPGM + +{ + miru-glib-hack-1 + Memcheck:Leak + fun:memalign + fun:posix_memalign + obj:/usr/lib/libglib-2.0.so* + fun:g_slice_alloc +} + +{ + miru-glib-hack-2 + Memcheck:Leak + fun:calloc + fun:g_malloc0 + obj:/usr/lib/libglib-2.0.so* + fun:g_slice_alloc +} + +{ + miru-glib-hack-2b + Memcheck:Leak + fun:malloc + fun:g_malloc + obj:/usr/lib/libglib-2.0.so* + fun:g_slice_alloc +} + +{ + miru-glib-hack-3 + Memcheck:Leak + fun:malloc + fun:realloc + fun:g_realloc + obj:/usr/lib/libglib-2.0.so* + fun:g_ptr_array_add + fun:g_main_context_check + obj:/usr/lib/libglib-2.0.so* + fun:g_main_loop_run +} + +{ + miru-glib-hack-4 + Memcheck:Leak + fun:realloc + fun:g_realloc + obj:/usr/lib/libglib-2.0.so* + fun:g_array_set_size + fun:g_static_private_set + fun:g_get_language_names +} + +{ + miru-glib-hack-5 + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_slice_alloc + fun:g_array_sized_new + fun:g_static_private_set + fun:g_get_charset + fun:g_log_default_handler + fun:g_logv + fun:g_log +} + +{ + miru-glib-hack-6 + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_log_set_handler +} + +{ + miru-glib-hack-7 + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:g_thread_self + fun:g_thread_init_glib +} + + + +## Annoying libc errors + +{ + miru-libc-hack-1 + Memcheck:Addr8 + obj:/lib/ld-2.*.so + obj:/lib/ld-2.*.so + obj:/lib/libc-2.*.so + obj:/lib/ld-2.*.so + fun:__libc_dlopen_mode + fun:__nss_lookup_function + obj:/lib/libc-2.*.so + fun:getprotobyname_r +} + +{ + miru-libc-hack-1b + Memcheck:Addr8 + obj:/lib/ld-2.*.so + obj:/lib/ld-2.*.so + obj:/lib/ld-2.*.so + obj:/lib/ld-2.*.so + obj:/lib/ld-2.*.so + obj:/lib/ld-2.*.so + obj:/lib/ld-2.*.so + obj:/lib/libc-2.*.so + obj:/lib/ld-2.*.so + fun:__libc_dlopen_mode + fun:__nss_lookup_function + obj:/lib/libc-2.*.so + fun:getprotobyname_r +} + +{ + miru-libc-hack-2 + Memcheck:Cond + obj:/lib/ld-2.*.so + obj:/lib/ld-2.*.so + obj:/lib/libc-2.*.so + obj:/lib/ld-2.*.so + fun:__libc_dlsym + fun:__nss_lookup_function + obj:/lib/libc-2.*.so + fun:getaddrinfo +} + +{ + miru-libc-hack-3 + Memcheck:Addr8 + obj:/lib/ld-2.*.so + obj:/lib/ld-2.*.so + obj:/lib/ld-2.*.so + obj:/lib/ld-2.*.so + obj:/lib/libc-2.*.so + obj:/lib/ld-2.*.so + fun:__libc_dlsym + fun:__nss_lookup_function + obj:/lib/libc-2.*.so + fun:getaddrinfo +} diff --git a/3rdparty/openpgm-svn-r1135/pgm/version_generator.py b/3rdparty/openpgm-svn-r1135/pgm/version_generator.py new file mode 100755 index 0000000..9b48a3f --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/version_generator.py @@ -0,0 +1,52 @@ +#!/usr/bin/python + +import os +import platform +import time + +build_date = time.strftime ("%Y-%m-%d") +build_time = time.strftime ("%H:%M:%S") +build_rev = os.popen('svnversion -n .').read(); + +print """ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * OpenPGM version. + * + * Copyright (c) 2006-2010 Miru Limited. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + + +/* globals */ + +const unsigned pgm_major_version = 5; +const unsigned pgm_minor_version = 0; +const unsigned pgm_micro_version = 79; +const char* pgm_build_date = "%s"; +const char* pgm_build_time = "%s"; +const char* pgm_build_system = "%s"; +const char* pgm_build_machine = "%s"; +const char* pgm_build_revision = "%s"; + + +/* eof */ +"""%(build_date, build_time, platform.system(), platform.machine(), build_rev) + +# end of file diff --git a/3rdparty/openpgm-svn-r1135/pgm/win/mingw32-runtime_3.13-1openpgm3.diff b/3rdparty/openpgm-svn-r1135/pgm/win/mingw32-runtime_3.13-1openpgm3.diff new file mode 100644 index 0000000..189c32d --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/win/mingw32-runtime_3.13-1openpgm3.diff @@ -0,0 +1,136 @@ +diff -urN include-original/mswsock.h include/mswsock.h +--- include-original/mswsock.h 2009-08-21 22:41:22.000000000 +0800 ++++ include/mswsock.h 2010-01-21 17:31:14.662159471 +0800 +@@ -83,23 +83,19 @@ + } WSAMSG, *PWSAMSG, *LPWSAMSG; + + +-/* According to MSDN docs, the WSAMSG.Control buffer starts with a +- cmsghdr header of the following form. See also RFC 2292. */ +- +-typedef struct wsacmsghdr { +- UINT cmsg_len; +- INT cmsg_level; +- INT cmsg_type; +- /* followed by UCHAR cmsg_data[]; */ +-} WSACMSGHDR; +- +-/* TODO: Standard Posix.1g macros as per RFC 2292, with WSA_uglification. */ +-#if 0 +-#define WSA_CMSG_FIRSTHDR(mhdr) +-#define WSA_CMSG_NXTHDR(mhdr, cmsg) +-#define WSA_CMSG_SPACE(length) +-#define WSA_CMSG_LEN(length) +-#endif ++ typedef struct _WSACMSGHDR { ++ SIZE_T cmsg_len; ++ INT cmsg_level; ++ INT cmsg_type; ++ } WSACMSGHDR,*PWSACMSGHDR,*LPWSACMSGHDR; ++ ++#define WSA_CMSGHDR_ALIGN(length) (((length) + TYPE_ALIGNMENT(WSACMSGHDR)-1) & (~(TYPE_ALIGNMENT(WSACMSGHDR)-1))) ++#define WSA_CMSGDATA_ALIGN(length) (((length) + MAX_NATURAL_ALIGNMENT-1) & (~(MAX_NATURAL_ALIGNMENT-1))) ++#define WSA_CMSG_FIRSTHDR(msg) (((msg)->Control.len >= sizeof(WSACMSGHDR)) ? (LPWSACMSGHDR)(msg)->Control.buf : (LPWSACMSGHDR)NULL) ++#define WSA_CMSG_NXTHDR(msg,cmsg) ((!(cmsg)) ? WSA_CMSG_FIRSTHDR(msg) : ((((u_char *)(cmsg) + WSA_CMSGHDR_ALIGN((cmsg)->cmsg_len) + sizeof(WSACMSGHDR)) > (u_char *)((msg)->Control.buf) + (msg)->Control.len) ? (LPWSACMSGHDR)NULL : (LPWSACMSGHDR)((u_char *)(cmsg) + WSA_CMSGHDR_ALIGN((cmsg)->cmsg_len)))) ++#define WSA_CMSG_DATA(cmsg) ((u_char *)(cmsg) + WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR))) ++#define WSA_CMSG_SPACE(length) (WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR) + WSA_CMSGHDR_ALIGN(length))) ++#define WSA_CMSG_LEN(length) (WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR)) + length) ++ ++typedef INT (WINAPI * LPFN_WSARECVMSG)(SOCKET, LPWSAMSG, LPDWORD, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); ++ + BOOL PASCAL DisconnectEx(SOCKET,LPOVERLAPPED,DWORD,DWORD); + int PASCAL WSARecvMsg(SOCKET,LPWSAMSG,LPDWORD,LPWSAOVERLAPPED,LPWSAOVERLAPPED_COMPLETION_ROUTINE); + +diff -urN include-original/ws2tcpip.h include/ws2tcpip.h +--- include-original/ws2tcpip.h 2009-08-21 22:41:42.000000000 +0800 ++++ include/ws2tcpip.h 2009-08-21 22:42:15.000000000 +0800 +@@ -78,6 +78,18 @@ + + #define UDP_NOCHECKSUM 1 + ++/* RFC 3768 */ ++#define MCAST_JOIN_GROUP 41 ++#define MCAST_LEAVE_GROUP 42 ++#define MCAST_BLOCK_SOURCE 43 ++#define MCAST_UNBLOCK_SOURCE 44 ++#define MCAST_JOIN_SOURCE_GROUP 45 ++#define MCAST_LEAVE_SOURCE_GROUP 46 ++#define MCAST_MSFILTER 47 ++ ++#define MCAST_EXCLUDE 0 ++#define MCAST_INCLUDE 1 ++ + /* INTERFACE_INFO iiFlags */ + #define IFF_UP 1 + #define IFF_BROADCAST 2 +@@ -104,6 +116,7 @@ + #define AI_PASSIVE 1 + #define AI_CANONNAME 2 + #define AI_NUMERICHOST 4 ++#define AI_ADDRCONFIG 0x20 + + /* getaddrinfo error codes */ + #define EAI_AGAIN WSATRY_AGAIN +@@ -132,6 +145,25 @@ + struct in_addr imr_interface; + }; + ++struct group_req { ++ u_long gr_interface; ++ struct sockaddr_storage gr_group; ++}; ++ ++struct group_source_req { ++ u_long gsr_interface; ++ struct sockaddr_storage gsr_group; ++ struct sockaddr_storage gsr_source; ++}; ++ ++struct group_filter { ++ u_long gf_interface; ++ struct sockaddr_storage gf_group; ++ u_long gf_fmode; ++ u_long gf_numsrc; ++ struct sockaddr_storage gf_slist[1]; ++}; ++ + struct ip_msfilter { + struct in_addr imsf_multiaddr; + struct in_addr imsf_interface; +@@ -356,6 +388,13 @@ + sockaddr_gen iiNetmask; + } INTERFACE_INFO, *LPINTERFACE_INFO; + ++typedef struct _INTERFACE_INFO_EX { ++ u_long iiFlags; ++ SOCKET_ADDRESS iiAddress; ++ SOCKET_ADDRESS iiBroadcastAddress; ++ SOCKET_ADDRESS iiNetmask; ++} INTERFACE_INFO_EX, *_LPINTERFACE_INFO_EX; ++ + /* + The definition above can cause problems on NT4,prior to sp4. + To workaround, include the following struct and typedef and +--- include-original/winnt.h 2009-08-21 22:41:42.000000000 +0800 ++++ include/winnt.h 2010-01-21 17:33:56.366162880 +0800 +@@ -43,6 +43,20 @@ + #define UNALIGNED + #endif + ++#ifdef _WIN64 ++#define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG) ++#define MEMORY_ALLOCATION_ALIGNMENT 16 ++#else ++#define MAX_NATURAL_ALIGNMENT sizeof(DWORD) ++#define MEMORY_ALLOCATION_ALIGNMENT 8 ++#endif ++ ++#ifdef __cplusplus ++#define TYPE_ALIGNMENT(t) __alignof__ (t) ++#else ++#define TYPE_ALIGNMENT(t) FIELD_OFFSET(struct { char x; t test; },test) ++#endif ++ + #ifndef DECLSPEC_ALIGN + #ifdef __GNUC__ + #define DECLSPEC_ALIGN(x) __attribute__((aligned(x))) diff --git a/3rdparty/openpgm-svn-r1135/pgm/win/mingw32-runtime_3.15.2-0openpgm1.diff b/3rdparty/openpgm-svn-r1135/pgm/win/mingw32-runtime_3.15.2-0openpgm1.diff new file mode 100644 index 0000000..b9453eb --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/win/mingw32-runtime_3.15.2-0openpgm1.diff @@ -0,0 +1,135 @@ +diff -urN include-original/mswsock.h include/mswsock.h +--- include-original/mswsock.h 2009-06-30 16:32:31.000000000 +0800 ++++ include/mswsock.h 2010-03-23 20:34:12.000000000 +0800 +@@ -83,23 +83,20 @@ + } WSAMSG, *PWSAMSG, *LPWSAMSG; + + +-/* According to MSDN docs, the WSAMSG.Control buffer starts with a +- cmsghdr header of the following form. See also RFC 2292. */ +- +-typedef struct wsacmsghdr { +- UINT cmsg_len; +- INT cmsg_level; +- INT cmsg_type; +- /* followed by UCHAR cmsg_data[]; */ +-} WSACMSGHDR; +- +-/* TODO: Standard Posix.1g macros as per RFC 2292, with WSA_uglification. */ +-#if 0 +-#define WSA_CMSG_FIRSTHDR(mhdr) +-#define WSA_CMSG_NXTHDR(mhdr, cmsg) +-#define WSA_CMSG_SPACE(length) +-#define WSA_CMSG_LEN(length) +-#endif ++typedef struct _WSACMSGHDR { ++ SIZE_T cmsg_len; ++ INT cmsg_level; ++ INT cmsg_type; ++} WSACMSGHDR,*PWSACMSGHDR,*LPWSACMSGHDR; ++ ++#define WSA_CMSGHDR_ALIGN(length) (((length) + TYPE_ALIGNMENT(WSACMSGHDR)-1) & (~(TYPE_ALIGNMENT(WSACMSGHDR)-1))) ++#define WSA_CMSGDATA_ALIGN(length) (((length) + MAX_NATURAL_ALIGNMENT-1) & (~(MAX_NATURAL_ALIGNMENT-1))) ++#define WSA_CMSG_FIRSTHDR(msg) (((msg)->Control.len >= sizeof(WSACMSGHDR)) ? (LPWSACMSGHDR)(msg)->Control.buf : (LPWSACMSGHDR)NULL) ++#define WSA_CMSG_NXTHDR(msg,cmsg) ((!(cmsg)) ? WSA_CMSG_FIRSTHDR(msg) : ((((u_char *)(cmsg) + WSA_CMSGHDR_ALIGN((cmsg)->cmsg_len) + sizeof(WSACMSGHDR)) > (u_char *)((msg)->Control.buf) + (msg)->Control.len) ? (LPWSACMSGHDR)NULL : (LPWSACMSGHDR)((u_char *)(cmsg) + WSA_CMSGHDR_ALIGN((cmsg)->cmsg_len)))) ++#define WSA_CMSG_DATA(cmsg) ((u_char *)(cmsg) + WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR))) ++#define WSA_CMSG_SPACE(length) (WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR) + WSA_CMSGHDR_ALIGN(length))) ++#define WSA_CMSG_LEN(length) (WSA_CMSGDATA_ALIGN(sizeof(WSACMSGHDR)) + length) ++typedef INT (WINAPI * LPFN_WSARECVMSG)(SOCKET, LPWSAMSG, LPDWORD, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); + + BOOL PASCAL DisconnectEx(SOCKET,LPOVERLAPPED,DWORD,DWORD); + int PASCAL WSARecvMsg(SOCKET,LPWSAMSG,LPDWORD,LPWSAOVERLAPPED,LPWSAOVERLAPPED_COMPLETION_ROUTINE); +diff -urN include-original/winnt.h include/winnt.h +--- include-original/winnt.h 2009-06-30 16:32:32.000000000 +0800 ++++ include/winnt.h 2010-03-23 20:36:29.000000000 +0800 +@@ -43,6 +43,20 @@ + #define UNALIGNED + #endif + ++#ifdef _WIN64 ++#define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG) ++#define MEMORY_ALLOCATION_ALIGNMENT 16 ++#else ++#define MAX_NATURAL_ALIGNMENT sizeof(DWORD) ++#define MEMORY_ALLOCATION_ALIGNMENT 8 ++#endif ++ ++#ifdef __cplusplus ++#define TYPE_ALIGNMENT(t) __alignof__ (t) ++#else ++#define TYPE_ALIGNMENT(t) FIELD_OFFSET(struct { char x; t test; },test) ++#endif ++ + #ifndef DECLSPEC_ALIGN + #ifdef __GNUC__ + #define DECLSPEC_ALIGN(x) __attribute__((aligned(x))) +diff -urN include-original/ws2tcpip.h include/ws2tcpip.h +--- include-original/ws2tcpip.h 2009-06-30 16:32:32.000000000 +0800 ++++ include/ws2tcpip.h 2010-03-23 20:35:59.000000000 +0800 +@@ -78,6 +78,18 @@ + + #define UDP_NOCHECKSUM 1 + ++/* RFC 3768 */ ++#define MCAST_JOIN_GROUP 41 ++#define MCAST_LEAVE_GROUP 42 ++#define MCAST_BLOCK_SOURCE 43 ++#define MCAST_UNBLOCK_SOURCE 44 ++#define MCAST_JOIN_SOURCE_GROUP 45 ++#define MCAST_LEAVE_SOURCE_GROUP 46 ++#define MCAST_MSFILTER 47 ++ ++#define MCAST_EXCLUDE 0 ++#define MCAST_INCLUDE 1 ++ + /* INTERFACE_INFO iiFlags */ + #define IFF_UP 1 + #define IFF_BROADCAST 2 +@@ -104,6 +116,7 @@ + #define AI_PASSIVE 1 + #define AI_CANONNAME 2 + #define AI_NUMERICHOST 4 ++#define AI_ADDRCONFIG 0x20 + + /* getaddrinfo error codes */ + #define EAI_AGAIN WSATRY_AGAIN +@@ -132,6 +145,25 @@ + struct in_addr imr_interface; + }; + ++struct group_req { ++ u_long gr_interface; ++ struct sockaddr_storage gr_group; ++}; ++ ++struct group_source_req { ++ u_long gsr_interface; ++ struct sockaddr_storage gsr_group; ++ struct sockaddr_storage gsr_source; ++}; ++ ++struct group_filter { ++ u_long gf_interface; ++ struct sockaddr_storage gf_group; ++ u_long gf_fmode; ++ u_long gf_numsrc; ++ struct sockaddr_storage gf_slist[1]; ++}; ++ + struct ip_msfilter { + struct in_addr imsf_multiaddr; + struct in_addr imsf_interface; +@@ -356,6 +388,13 @@ + sockaddr_gen iiNetmask; + } INTERFACE_INFO, *LPINTERFACE_INFO; + ++typedef struct _INTERFACE_INFO_EX { ++ u_long iiFlags; ++ SOCKET_ADDRESS iiAddress; ++ SOCKET_ADDRESS iiBroadcastAddress; ++ SOCKET_ADDRESS iiNetmask; ++} INTERFACE_INFO_EX, *_LPINTERFACE_INFO_EX; ++ + /* + The definition above can cause problems on NT4,prior to sp4. + To workaround, include the following struct and typedef and diff --git a/3rdparty/openpgm-svn-r1135/pgm/win64/mingw-w64-bin_x86-64-linux_4.4.1-1openpgm1.diff b/3rdparty/openpgm-svn-r1135/pgm/win64/mingw-w64-bin_x86-64-linux_4.4.1-1openpgm1.diff new file mode 100644 index 0000000..d873544 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/win64/mingw-w64-bin_x86-64-linux_4.4.1-1openpgm1.diff @@ -0,0 +1,53 @@ +diff -urN include-original/./ws2tcpip.h x86_64-w64-mingw32/include/./ws2tcpip.h +--- include-original/./ws2tcpip.h 2009-09-10 13:36:49.000000000 +0800 ++++ x86_64-w64-mingw32/include/./ws2tcpip.h 2010-01-21 14:59:13.000000000 +0800 +@@ -12,6 +12,25 @@ + + #include + ++struct group_req { ++ u_long gr_interface; ++ struct sockaddr_storage gr_group; ++}; ++ ++struct group_source_req { ++ u_long gsr_interface; ++ struct sockaddr_storage gsr_group; ++ struct sockaddr_storage gsr_source; ++}; ++ ++struct group_filter { ++ u_long gf_interface; ++ struct sockaddr_storage gf_group; ++ u_long gf_fmode; ++ u_long gf_numsrc; ++ struct sockaddr_storage gf_slist[1]; ++}; ++ + struct ip_msfilter { + struct in_addr imsf_multiaddr; + struct in_addr imsf_interface; +@@ -22,6 +41,15 @@ + + #define IP_MSFILTER_SIZE(numsrc) (sizeof(struct ip_msfilter)-sizeof(struct in_addr) + (numsrc)*sizeof(struct in_addr)) + ++/* RFC 3768 */ ++#define MCAST_JOIN_GROUP 41 ++#define MCAST_LEAVE_GROUP 42 ++#define MCAST_BLOCK_SOURCE 43 ++#define MCAST_UNBLOCK_SOURCE 44 ++#define MCAST_JOIN_SOURCE_GROUP 45 ++#define MCAST_LEAVE_SOURCE_GROUP 46 ++#define MCAST_MSFILTER 47 ++ + #define MCAST_INCLUDE 0 + #define MCAST_EXCLUDE 1 + +@@ -277,6 +305,7 @@ + #define AI_PASSIVE 0x1 + #define AI_CANONNAME 0x2 + #define AI_NUMERICHOST 0x4 ++#define AI_ADDRCONFIG 0x20 + + #ifdef __cplusplus + extern "C" { diff --git a/3rdparty/openpgm-svn-r1135/pgm/wsastrerror.c b/3rdparty/openpgm-svn-r1135/pgm/wsastrerror.c new file mode 100644 index 0000000..2e21449 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/wsastrerror.c @@ -0,0 +1,372 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * Winsock Error strings. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#ifdef _WIN32 +# include + + +char* +pgm_wsastrerror ( + const int wsa_errno + ) +{ + switch (wsa_errno) { +#ifdef WSA_INVALID_HANDLE + case WSA_INVALID_HANDLE: return _("Specified event object handle is invalid."); +#endif +#ifdef WSA_NOT_ENOUGH_MEMORY + case WSA_NOT_ENOUGH_MEMORY: return _("Insufficient memory available."); +#endif +#ifdef WSA_INVALID_PARAMETER + case WSA_INVALID_PARAMETER: return _("One or more parameters are invalid."); +#endif +#ifdef WSA_OPERATION_ABORTED + case WSA_OPERATION_ABORTED: return _("Overlapped operation aborted."); +#endif +#ifdef WSA_IO_INCOMPLETE + case WSA_IO_INCOMPLETE: return _("Overlapped I/O event object not in signaled state."); +#endif +#ifdef WSA_IO_PENDING + case WSA_IO_PENDING: return _("Overlapped operations will complete later."); +#endif +#ifdef WSAEINTR + case WSAEINTR: return _("Interrupted function call."); +#endif +#ifdef WSAEBADF + case WSAEBADF: return _("File handle is not valid."); +#endif +#ifdef WSAEACCES + case WSAEACCES: return _("Permission denied."); +#endif +#ifdef WSAEFAULT + case WSAEFAULT: return _("Bad address."); +#endif +#ifdef WSAEINVAL + case WSAEINVAL: return _("Invalid argument."); +#endif +#ifdef WSAEMFILE + case WSAEMFILE: return _("Too many open files."); +#endif +#ifdef WSAEWOULDBLOCK + case WSAEWOULDBLOCK: return _("Resource temporarily unavailable."); +#endif +#ifdef WSAEINPROGRESS + case WSAEINPROGRESS: return _("Operation now in progress."); +#endif +#ifdef WSAEALREADY + case WSAEALREADY: return _("Operation already in progress."); +#endif +#ifdef WSAENOTSOCK + case WSAENOTSOCK: return _("Socket operation on nonsocket."); +#endif +#ifdef WSAEDESTADDRREQ + case WSAEDESTADDRREQ: return _("Destination address required."); +#endif +#ifdef WSAEMSGSIZE + case WSAEMSGSIZE: return _("Message too long."); +#endif +#ifdef WSAEPROTOTYPE + case WSAEPROTOTYPE: return _("Protocol wrong type for socket."); +#endif +#ifdef WSAENOPROTOOPT + case WSAENOPROTOOPT: return _("Bad protocol option."); +#endif +#ifdef WSAEPROTONOSUPPORT + case WSAEPROTONOSUPPORT: return _("Protocol not supported."); +#endif +#ifdef WSAESOCKTNOSUPPORT + case WSAESOCKTNOSUPPORT: return _("Socket type not supported."); +#endif +#ifdef WSAEOPNOTSUPP + case WSAEOPNOTSUPP: return _("Operation not supported."); +#endif +#ifdef WSAEPFNOSUPPORT + case WSAEPFNOSUPPORT: return _("Protocol family not supported."); +#endif +#ifdef WSAEAFNOSUPPORT + case WSAEAFNOSUPPORT: return _("Address family not supported by protocol family."); +#endif +#ifdef WSAEADDRINUSE + case WSAEADDRINUSE: return _("Address already in use."); +#endif +#ifdef WSAEADDRNOTAVAIL + case WSAEADDRNOTAVAIL: return _("Cannot assign requested address."); +#endif +#ifdef WSAENETDOWN + case WSAENETDOWN: return _("Network is down."); +#endif +#ifdef WSAENETUNREACH + case WSAENETUNREACH: return _("Network is unreachable."); +#endif +#ifdef WSAENETRESET + case WSAENETRESET: return _("Network dropped connection on reset."); +#endif +#ifdef WSAECONNABORTED + case WSAECONNABORTED: return _("Software caused connection abort."); +#endif +#ifdef WSAECONNRESET + case WSAECONNRESET: return _("Connection reset by peer."); +#endif +#ifdef WSAENOBUFS + case WSAENOBUFS: return _("No buffer space available."); +#endif +#ifdef WSAEISCONN + case WSAEISCONN: return _("Socket is already connected."); +#endif +#ifdef WSAENOTCONN + case WSAENOTCONN: return _("Socket is not connected."); +#endif +#ifdef WSAESHUTDOWN + case WSAESHUTDOWN: return _("Cannot send after socket shutdown."); +#endif +#ifdef WSAETOOMANYREFS + case WSAETOOMANYREFS: return _("Too many references."); +#endif +#ifdef WSAETIMEDOUT + case WSAETIMEDOUT: return _("Connection timed out."); +#endif +#ifdef WSAECONNREFUSED + case WSAECONNREFUSED: return _("Connection refused."); +#endif +#ifdef WSAELOOP + case WSAELOOP: return _("Cannot translate name."); +#endif +#ifdef WSAENAMETOOLONG + case WSAENAMETOOLONG: return _("Name too long."); +#endif +#ifdef WSAEHOSTDOWN + case WSAEHOSTDOWN: return _("Host is down."); +#endif +#ifdef WSAEHOSTUNREACH + case WSAEHOSTUNREACH: return _("No route to host."); +#endif +#ifdef WSAENOTEMPTY + case WSAENOTEMPTY: return _("Directory not empty."); +#endif +#ifdef WSAEPROCLIM + case WSAEPROCLIM: return _("Too many processes."); +#endif +#ifdef WSAEUSERS + case WSAEUSERS: return _("User quota exceeded."); +#endif +#ifdef WSAEDQUOT + case WSAEDQUOT: return _("Disk quota exceeded."); +#endif +#ifdef WSAESTALE + case WSAESTALE: return _("Stale file handle reference."); +#endif +#ifdef WSAEREMOTE + case WSAEREMOTE: return _("Item is remote."); +#endif +#ifdef WSASYSNOTREADY + case WSASYSNOTREADY: return _("Network subsystem is unavailable."); +#endif +#ifdef WSAVERNOTSUPPORTED + case WSAVERNOTSUPPORTED: return _("Winsock.dll version out of range."); +#endif +#ifdef WSANOTINITIALISED + case WSANOTINITIALISED: return _("Successful WSAStartup not yet performed."); +#endif +#ifdef WSAEDISCON + case WSAEDISCON: return _("Graceful shutdown in progress."); +#endif +#ifdef WSAENOMORE + case WSAENOMORE: return _("No more results."); +#endif +#ifdef WSAECANCELLED + case WSAECANCELLED: return _("Call has been canceled."); +#endif +#ifdef WSAEINVALIDPROCTABLE + case WSAEINVALIDPROCTABLE: return _("Procedure call table is invalid."); +#endif +#ifdef WSAEINVALIDPROVIDER + case WSAEINVALIDPROVIDER: return _("Service provider is invalid."); +#endif +#ifdef WSAEPROVIDERFAILEDINIT + case WSAEPROVIDERFAILEDINIT: return _("Service provider failed to initialize."); +#endif +#ifdef WSASYSCALLFAILURE + case WSASYSCALLFAILURE: return _("System call failure."); +#endif +#ifdef WSASERVICE_NOT_FOUND + case WSASERVICE_NOT_FOUND: return _("Service not found."); +#endif +#ifdef WSATYPE_NOT_FOUND + case WSATYPE_NOT_FOUND: return _("Class type not found."); +#endif +#ifdef WSA_E_NO_MORE + case WSA_E_NO_MORE: return _("No more results."); +#endif +#ifdef WSA_E_CANCELLED + case WSA_E_CANCELLED: return _("Call was canceled."); +#endif +#ifdef WSAEREFUSED + case WSAEREFUSED: return _("Database query was refused."); +#endif +#ifdef WSAHOST_NOT_FOUND + case WSAHOST_NOT_FOUND: return _("Host not found."); +#endif +#ifdef WSATRY_AGAIN + case WSATRY_AGAIN: return _("Nonauthoritative host not found."); +#endif +#ifdef WSANO_RECOVERY + case WSANO_RECOVERY: return _("This is a nonrecoverable error."); +#endif +#ifdef WSANO_DATA + case WSANO_DATA: return _("Valid name, no data record of requested type."); +#endif +#ifdef WSA_QOS_RECEIVERS + case WSA_QOS_RECEIVERS: return _("QOS receivers."); +#endif +#ifdef WSA_QOS_SENDERS + case WSA_QOS_SENDERS: return _("QOS senders."); +#endif +#ifdef WSA_QOS_NO_SENDERS + case WSA_QOS_NO_SENDERS: return _("No QOS senders."); +#endif +#ifdef WSA_QOS_NO_RECEIVERS + case WSA_QOS_NO_RECEIVERS: return _("QOS no receivers."); +#endif +#ifdef WSA_QOS_REQUEST_CONFIRMED + case WSA_QOS_REQUEST_CONFIRMED: return _("QOS request confirmed."); +#endif +#ifdef WSA_QOS_ADMISSION_FAILURE + case WSA_QOS_ADMISSION_FAILURE: return _("QOS admission error."); +#endif +#ifdef WSA_QOS_POLICY_FAILURE + case WSA_QOS_POLICY_FAILURE: return _("QOS policy failure."); +#endif +#ifdef WSA_QOS_BAD_STYLE + case WSA_QOS_BAD_STYLE: return _("QOS bad style."); +#endif +#ifdef WSA_QOS_BAD_OBJECT + case WSA_QOS_BAD_OBJECT: return _("QOS bad object."); +#endif +#ifdef WSA_QOS_TRAFFIC_CTRL_ERROR + case WSA_QOS_TRAFFIC_CTRL_ERROR: return _("QOS traffic control error."); +#endif +#ifdef WSA_QOS_GENERIC_ERROR + case WSA_QOS_GENERIC_ERROR: return _("QOS generic error."); +#endif +#ifdef WSA_QOS_ESERVICETYPE + case WSA_QOS_ESERVICETYPE: return _("QOS service type error."); +#endif +#ifdef WSA_QOS_EFLOWSPEC + case WSA_QOS_EFLOWSPEC: return _("QOS flowspec error."); +#endif +#ifdef WSA_QOS_EPROVSPECBUF + case WSA_QOS_EPROVSPECBUF: return _("Invalid QOS provider buffer."); +#endif +#ifdef WSA_QOS_EFILTERSTYLE + case WSA_QOS_EFILTERSTYLE: return _("Invalid QOS filter style."); +#endif +#ifdef WSA_QOS_EFILTERTYPE + case WSA_QOS_EFILTERTYPE: return _("Invalid QOS filter type."); +#endif +#ifdef WSA_QOS_EFILTERCOUNT + case WSA_QOS_EFILTERCOUNT: return _("Incorrect QOS filter count."); +#endif +#ifdef WSA_QOS_EOBJLENGTH + case WSA_QOS_EOBJLENGTH: return _("Invalid QOS object length."); +#endif +#ifdef WSA_QOS_EFLOWCOUNT + case WSA_QOS_EFLOWCOUNT: return _("Incorrect QOS flow count."); +#endif +#ifdef WSA_QOS_EUNKOWNPSOBJ + case WSA_QOS_EUNKOWNPSOBJ: return _("Unrecognized QOS object."); +#endif +#ifdef WSA_QOS_EPOLICYOBJ + case WSA_QOS_EPOLICYOBJ: return _("Invalid QOS policy object."); +#endif +#ifdef WSA_QOS_EFLOWDESC + case WSA_QOS_EFLOWDESC: return _("Invalid QOS flow descriptor."); +#endif +#ifdef WSA_QOS_EPSFLOWSPEC + case WSA_QOS_EPSFLOWSPEC: return _("Invalid QOS provider-specific flowspec."); +#endif +#ifdef WSA_QOS_EPSFILTERSPEC + case WSA_QOS_EPSFILTERSPEC: return _("Invalid QOS provider-specific filterspec."); +#endif +#ifdef WSA_QOS_ESDMODEOBJ + case WSA_QOS_ESDMODEOBJ: return _("Invalid QOS shape discard mode object."); +#endif +#ifdef WSA_QOS_ESHAPERATEOBJ + case WSA_QOS_ESHAPERATEOBJ: return _("Invalid QOS shaping rate object."); +#endif +#ifdef WSA_QOS_RESERVED_PETYPE + case WSA_QOS_RESERVED_PETYPE: return _("Reserved policy QOS element type."); +#endif + default: return _("Unknown."); + } +} + +char* +pgm_adapter_strerror ( + const int adapter_errno + ) +{ + switch (adapter_errno) { +#ifdef ERROR_ADDRESS_NOT_ASSOCIATED + case ERROR_ADDRESS_NOT_ASSOCIATED: return _("DHCP lease information was available."); +#endif +#ifdef ERROR_BUFFER_OVERFLOW + case ERROR_BUFFER_OVERFLOW: return _("The buffer to receive the adapter information is too small."); +#endif +#ifdef ERROR_INVALID_DATA + case ERROR_INVALID_DATA: return _("Invalid adapter information was retrieved."); +#endif +#ifdef ERROR_INVALID_PARAMETER + case ERROR_INVALID_PARAMETER: return _("One of the parameters is invalid."); +#endif +#ifdef ERROR_NOT_ENOUGH_MEMORY + case ERROR_NOT_ENOUGH_MEMORY: return _("Insufficient memory resources are available to complete the operation."); +#endif +#ifdef ERROR_NO_DATA + case ERROR_NO_DATA: return _("No adapter information exists for the local computer."); +#endif +#ifdef ERROR_NOT_SUPPORTED + case ERROR_NOT_SUPPORTED: return _("The GetAdaptersInfo function is not supported by the operating system running on the local computer.."); +#endif + default: return _("Other."); + } +} + +char* +pgm_win_strerror ( + char* buf, + size_t buflen, + const int win_errno + ) +{ + const DWORD nSize = buflen; + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, + NULL, /* source */ + win_errno, /* message id */ + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* language id */ + (LPTSTR)buf, + buflen, + NULL); /* arguments */ + return buf; +} +#endif /* _WIN32 */ + +/* eof */ -- cgit v1.2.3-55-g7522